AGENTS.md

  1<!--
  2SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  3
  4SPDX-License-Identifier: CC0-1.0
  5-->
  6
  7# AGENTS.md
  8
  9This file provides guidance to AI coding agents when working with code in this repository.
 10
 11## Development Commands
 12
 13- **Default workflow**: `task` (runs fmt, lint, staticcheck, test, vuln, reuse)
 14- **Build**: `task build` (outputs binary as `formatted-commit`)
 15- **Run during development**: `task run -- [flags]`
 16- **Format code**: `task fmt` (uses gofumpt)
 17- **Lint**: `task lint` (uses golangci-lint)
 18- **Static analysis**: `task staticcheck`
 19- **Vulnerability check**: `task vuln` (uses govulncheck)
 20- **License compliance**: `task reuse` (REUSE specification)
 21- **Test**: `task test` or `go test ./...`
 22- **Single test**: `go test -v -run TestName ./...` (no tests exist yet)
 23- **Update dependencies**: `go mod tidy`
 24
 25Example usage:
 26
 27```bash
 28task run -- -t feat -m "add validation" -T "Assisted-by: GLM 4.6 via Crush"
 29```
 30
 31## Project Purpose
 32
 33This is a CLI tool that formats git commit messages according to Conventional Commits specification and pipes them directly to `git commit -F -`. It enforces:
 34
 351. Subject length: max 50 characters in format `type(scope): message`
 362. Body wrapping: strictly 72 columns with hanging indents for bullets/numbered lists
 373. Trailer validation: follows git's trailer specification
 38
 39## Architecture
 40
 41Multi-file CLI application split by concern:
 42
 43- **main.go**: Cobra CLI setup, flag definitions, subject validation, orchestration, git command execution
 44- **trailers.go**: Trailer validation and block building following git's RFC 822 folding specification
 45- **wrapBody.go**: Custom word-wrapping with hanging indent support
 46
 47Dependencies:
 48
 49- **cobra**: CLI framework for flags and commands
 50- **fang**: Charmbracelet's execution wrapper (version handling, etc.)
 51- **Custom word wrapping**: Pure-Go implementation for 72-column wrapping with hanging indents
 52
 53## Critical Implementation Details
 54
 55### Subject Validation (50 char limit)
 56
 57The subject is constructed as `type(scope): message` or `type: message` (when scope is empty). Breaking changes add a `!` after the type/scope like `type(scope)!: message`.
 58
 59When validation fails, clearly mark where the subject exceeds 50 characters in error output.
 60
 61### Body Formatting
 62
 63The body (`-b` flag) processing pipeline:
 64
 651. **Line-by-line processing**: Each line is processed based on its type:
 66   - **Bullets** (`- ` or `* `): Wrapped with 2-space hanging indent for continuation lines
 67   - **Numbered lists** (`^\d+\.\s`): Wrapped with hanging indent matching the marker length (e.g., `1. `, `10. `)
 68   - **Plain text**: Standard word-wrap at 72 columns
 69   - **Blank lines**: Preserved as-is
 702. **Word wrapping algorithm**: Greedy wrapping splits on word boundaries, never mid-word
 713. **Hanging indent logic**: For bullets/numbered lists, first line gets the marker, continuation lines get spaces equal to marker width
 724. **Spacing**: Body separated from subject by one blank line, from trailers by one blank line
 73
 74Example wrapped bullet:
 75
 76```
 77- This is a long bullet point that exceeds 72 characters and will
 78  be wrapped with proper hanging indent alignment on continuation
 79  lines.
 80```
 81
 82### Trailer Formatting (Critical)
 83
 84Trailers follow git's specification precisely:
 85
 86- Format: `Key: value` (newline-delimited pairs)
 87- No whitespace before or inside the key
 88- Any number of spaces/tabs allowed between key and separator `:`
 89- Values can be multiline with continuation lines starting with whitespace (RFC 822 folding)
 90- The trailer group must be:
 91  - At the end of input, OR
 92  - The last non-whitespace lines before a line starting with `---`
 93  - Preceded by one or more empty/whitespace-only lines
 94
 95Example valid trailer:
 96
 97```
 98Assisted-by: This is a very long value, with spaces and
 99  newlines in it.
100```
101
102### Flag Nuance
103
104- `-t` / `--type`: Commit type (required) - e.g., `feat`, `fix`, `refactor`
105- `-m` / `--message`: Commit message (required) - the description after the colon
106- `-s` / `--scope`: Commit scope (optional) - goes in parentheses after type
107- `-B` / `--breaking`: Boolean flag for breaking changes (adds `!` to subject)
108- `-b` / `--body`: String flag for commit body text (can use heredoc for multiline)
109- `-T` / `--trailer`: Repeatable flag accepting full trailer strings in `Key: value` format (not separate key/value args)
110- `-a` / `--add`: Boolean flag to stage all modified files before committing (optional)
111- `--amend`: Boolean flag to amend the previous commit instead of creating a new one (optional)
112
113Trailer format detail: Each `-T` flag takes a complete trailer string like `-T "Assisted-by: GLM 4.6 via Crush"`, NOT separate key and value arguments.
114
115### Final Output
116
117The formatted commit message must be piped to `git commit -F -` to read from stdin. When the `--amend` flag is used, it pipes to `git commit --amend -F -` instead.