# Contributing ## Commit messages We follow the [Go commit message convention][go] (the same style [Tailscale][ts] uses). The subject line is: ``` pkg/path: short summary in the imperative mood ``` - **Prefix**: the package or path affected, from the repo root. Use a real Go package (`appview/pages`, `knot2/xrpc`) or the actual top-level path — e.g. `.tangled/workflows:`, **not** `workflows:`. If several packages are touched, either abbreviate to top-level names (`api,lexicons:`) or group subpackages with braces (`appview/{config,state}:`). Do **not** use Conventional Commit types (`feat:`, `fix:`, `chore:`); name the package instead. - **Summary**: a lowercase, imperative-mood verb phrase — "add", not "added" / "adds" / "adding". No trailing period. Keep it under ~76 characters. - Leave a blank line between the summary and the body. - Use the body to explain *what* changed and *why*, wrapped at ~76 columns. ### Examples ``` ogre: pluralize metrics # good knot2/xrpc: forward X-Forwarded-For headers # good api,lexicons: add lexicons for private xrpc # good appview/{config,state}: gate xrpc router # good fix: pluralize metrics in ogre # bad — Conventional Commit prefix workflows/rust: run checks and tests # bad — no top-level `workflows/`; use `.tangled/workflows` bobbin extra certs # bad — no package prefix web: Added reactions # bad — capitalized, past tense ``` Reference: . ## Enforcement Commit messages are linted by [`.tangled/hooks/commit-msg-lint.sh`](.tangled/hooks/commit-msg-lint.sh), which runs both in CI and, optionally, as a local git hook. ### CI The [`commit-lint`](.tangled/workflows/commit-lint.yml) workflow runs on every push and pull request to `master`. On a pull request it lints every commit between the target branch and the PR head; on a push it lints the pushed commit. ### Local git hook Install the repo's git hooks once, so bad messages are caught before you commit: ```sh ./.tangled/hooks/install.sh ``` This points `core.hooksPath` at `.tangled/hooks`. Bypass the check for a single commit with `git commit --no-verify`. To undo: `git config --unset core.hooksPath`. ### jj (jujutsu) `jj` does not run git hooks, so `jj` users rely on the CI check. You can lint a change locally at any time: ```sh .tangled/hooks/commit-msg-lint.sh --rev @ # lint the current change .tangled/hooks/commit-msg-lint.sh --range main @ # lint a range ``` [go]: https://go.dev/wiki/CommitMessage [ts]: https://github.com/tailscale/tailscale/blob/main/docs/commit-messages.md