`DCO Check` is a required status check on this repo and the top failing
check on open contributor PRs, but nothing documented it and nothing
surfaced it locally — a missing `Signed-off-by` trailer only showed up
as a red check after the PR was already open.
## `lefthook.yml`
New `commit-msg` hook that appends the `Signed-off-by` trailer:
```yaml
commit-msg:
commands:
signoff:
run: 'git interpret-trailers --if-exists doNothing --trailer "Signed-off-by: $(git var GIT_COMMITTER_IDENT | sed ''s/ [0-9]* [+-][0-9]*$//'')" --in-place {1}'
```
`GIT_COMMITTER_IDENT` is the identity that performed the commit, which
is what a DCO sign-off certifies and what native `git commit -s` uses.
Committing someone else's work with `--author` or `git commit -C`
therefore signs off as you, not as the original author.
`--if-exists doNothing` makes it idempotent: `git commit -s` still
yields exactly one trailer, and an existing sign-off from a different
signer is preserved rather than supplemented. An empty commit message
still aborts — the hook does not turn one into a commit body containing
only a trailer.
Git runs `commit-msg` for `git commit` and `git merge` only. Other flows
bypass it and need their own sign-off flag — `git rebase --signoff`,
`git cherry-pick -s`. Note `-s` is `--strategy` on `git rebase`, so only
the long flag works there. The header comment and both docs state the
scope rather than promising blanket coverage. Installed by `just hooks`;
`commit-msg` carries no `glob` because it rewrites the message, not
files.
## `CONTRIBUTING.md`
`Before You Open a PR` gains a paragraph on sign-off: commit with `git
commit -s`, what the trailer certifies, that the required `DCO Check`
blocks merge without it, `git rebase --signoff main` to repair
already-pushed commits, and what the hook does and does not cover.
`CI Gate` gains one sentence pointing at `just fix-all` for
formatting-only failures.
## `AGENTS.md`
`Quality Gates` gains the same requirement framed for agents, including
the sequencer caveat and the reminder to include `-s` in
programmatically built commit commands.
## Related issue
none found
---------
Signed-off-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
## Summary
- Activate lefthook pre-commit and pre-push hooks that have existed in `lefthook.yml` since the initial desktop app but were never wired up.
- Add `just hooks` recipe: sets `core.hooksPath = .hooks` and runs `lefthook install --force` to generate hook scripts.
- Wire hook installation into `scripts/dev-setup.sh` so hooks activate automatically on `just setup`.
- Enable `parallel: true` for pre-commit hooks (pre-push already had it) — all 5 format/lint checks run simultaneously.
- Add `just mobile-fmt` recipe (`dart format .`) and `just fmt-all` recipe (Rust root + Tauri Rust + Dart) as one-shot formatters.
- `.hooks/` is gitignored since lefthook generates machine-specific scripts.
- Update `AGENTS.md`: document pre-commit/pre-push hooks in Quality Gates, add `just fmt-all` and `just hooks` usage, upgrade worktree fmt gotcha from CI note to commit blocker, add `just mobile-fmt` to mobile commands; also backfill CLI-first updates (`SPROUT_AUTH_TAG`, complete exit codes, `--format compact` flag position, two new gotchas).
All hook commands delegate to `just` recipes as the single source of truth.