This document is the authoritative record of the development process and
conventions for the pm CLI. Agents and people follow the same rules.
mainis the primary branch and is protected: never push to it directly. Enforcement is twofold — a GitHub branch-protection rule on the remote and a localpre-pushhook in.githooks/(enable withgit config core.hooksPath .githooks).- Do all work on a feature branch, named
type/short-slugwheretypematches the commit type below — for examplefeat/yaml-parser,fix/emit-idempotence,chore/ci. - Land each feature by opening a pull request and using squash merge, so
every feature becomes exactly one Conventional Commit on
mainand history stays linear and readable. - Pull requests open as draft and are merged only on explicit maintainer authorization.
- Use Conventional Commits.
- Scope is the package name, e.g.
feat(parse): reject merge keys,fix(emit): stabilize blank line between tasks,test(discover): nested ignore. - Allowed types:
feat,fix,docs,test,refactor,chore,ci,build. Use!(or aBREAKING CHANGE:footer) for breaking changes. - Keep commit messages plain. Do not add
Co-Authored-Bytrailers or any other AI-attribution footers.
Every pull request must be green before merge. make check runs the same gate
locally that CI runs:
- Formatting —
gofmtclean (andgoimportswhen available). - Vet —
go vet ./.... - Lint —
golangci-lint run(config in.golangci.yml). - Tests —
go test -race ./.... - Build —
go build ./....
Other standing rules:
- Keep
go mod tidyclean and commitgo.sum. No vendoring. - The
godirective and toolchain are pinned ingo.mod(Go 1.26). - Document exported identifiers with Go doc comments.
- Table-driven tests live beside the code they cover; a new package ships with its tests in the same pull request.
- Golden fixtures under
testdata/verify canonical formatting and its idempotence (emit twice, compare bytes). - Mutation tests operate on copies in a temporary discovery root. Live knowledge base task files may be used as read-only inputs for parse, validate, and discovery acceptance only — never mutated by tests.
- Lifecycle dates come from an injectable clock; tests never depend on the machine date.
.github/workflows/ci.yml runs the formatting check, go vet,
golangci-lint, go test -race, and go build on every pull request and on
pushes to main. Because the workflow file is executable automation, changes to
it go through the pull-request lane like any other code.
The package layout and the ordered task breakdown (T1–T13) are described in
implementation-plan.md. The normative format and CLI
specifications are frozen in docs/spec/; treat them as the
contract, and amend them only deliberately, in the same change as the code.