Every commit subject must match:
<type>[optional scope][optional !]: <description>
| Type | Use for |
|---|---|
feat |
New user-facing capability |
fix |
Bug fix |
docs |
Documentation only |
style |
Formatting / whitespace (no logic change) |
refactor |
Internal change that is not a fix or feat |
perf |
Performance improvement |
test |
Adding or fixing tests |
build |
Build system / deps (Cargo, Nix, tooling) |
ci |
CI configuration / workflows |
chore |
Maintenance that does not fit above |
revert |
Reverts a previous commit |
Rules:
- Subject ≤ 72 characters; prefer ≤ 50.
- Imperative mood:
add,fix,remove— notAdded/Fixes. - No trailing period on the subject.
- Blank line between subject and body when a body is present.
- Body explains why, not a restatement of the diff.
Good:
feat(cli): support --template for truss new
Default remains "default"; registry entries override embedded packs.
Bad:
truss: implement core new/sync/check
Added template rendering.
feat: wip
Never put any of the following in commits, PR titles, PR bodies, changelogs, or work-logs:
Generated with [Devin]/ Claude / Cursor / Copilot / Codex / …Co-Authored-By:trailers for agent or bot accountsAssisted-by:/Generated-by:AI footers- Robot emoji attribution lines
- Agent emails (
agent@devin,noreply@anthropic.com,<ai-bot>, …)
Authorship is the human Git author (user.name / user.email). Hooks enforce this
locally; CI enforces it on PRs.
Title — same Conventional Commits shape as a commit subject, ≤ 72 chars.
Body — use .github/PULL_REQUEST_TEMPLATE.md. Required:
- Summary — 1–3 concrete bullets of what changed and why.
- Type — checkbox.
- Test plan — commands actually run (or “N/A” with reason).
- Notes — risks, follow-ups, screenshots only when useful.
Rejects (CI / review):
- Titles like
Update,Fixes,WIP,stuff,misc,changes - Bodies that are only “Generated with …”, empty template sections, or lorem
- AI watermark sections
Hooks live in .githooks/ (tracked). Activate once per clone:
just setup-hooks
# equivalent: git config core.hooksPath .githooks| Hook | Role |
|---|---|
pre-commit |
gitleaks + ripsecrets on staged files; block secret filenames |
prepare-commit-msg |
Soft-strips known AI trailers before the editor |
commit-msg |
Hard-fails on AI attribution, non-conventional subjects, placeholder slop |
pre-push |
Scans commits being pushed for AI trailers, agent authors, non-conventional subjects |
Bypass (emergency only): git commit --no-verify / git push --no-verify.
Never commit:
.env/.env.*, PEM / OpenSSH private keys,credentials.json- Cloud / AI API keys (
sk-…,sk-ant-…,ghp_…,AKIA…, …) - Personal data (emails/phones in fixtures must be clearly fake)
- Private store dumps or customer indexes
Local
just secrets # gitleaks detect + ripsecrets
gitleaks protect --staged --config .gitleaks.toml
ripsecrets --strict-ignore $(git diff --cached --name-only --diff-filter=ACM)CI (.github/workflows/secrets-scan.yml)
gitleakson PR ranges and full history onmain/ weekly scheduletrufflehog --only-verifiedon the treecargo audit --deny warnings
Config: .gitleaks.toml, .trufflehog-exclude.
If a real secret is committed: rotate first, then rewrite history if needed.
Root AGENTS.md, CLAUDE.md, and tool dirs (.claude/, .cursor/, .devin/, …)
are gitignored. Keep personal agent loaders local. Product conventions for
humans and reviewers live in this file and README.md.
Scaffold templates may still embed AGENTS.md / CLAUDE.md inside template
trees (e.g. crates/truss-cli/templates/default/) — those are product output,
not repo agent config.
just setup-hooks # once
just secrets
just validate # fmt + check + clippy + test