/git-conventions
Use when committing, squashing, merging, rebasing, or preparing changes for a pull request
Claude Code
$ npx -y skills add metraton/gaia --skill git-conventions --agent claude-code
Codex
$ npx skills add metraton/gaia --skill git-conventions -a codex -y
Cursor
$ npx skills add metraton/gaia --skill git-conventions -a cursor -y
Gemini CLI
$ npx skills add metraton/gaia --skill git-conventions -a gemini-cli -y
GitHub Copilot
$ npx skills add metraton/gaia --skill git-conventions -a github-copilot -y
OpenCode
$ npx skills add metraton/gaia --skill git-conventions -a opencode -y
Windsurf
$ npx skills add metraton/gaia --skill git-conventions -a windsurf -y
SKILL.md
git-conventions.SKILL.mdname: git-conventions
description: Use when committing, squashing, merging, rebasing, or preparing changes for a pull request
Git Conventions
Commit Format
| Element | Rule | |---------|------| | Format | `type(scope): short description` | | Types | feat, fix, refactor, docs, test, chore, ci, perf, style, build | | Scope | Optional, reflects module/area changed | | Subject | Max 72 chars, lowercase start, imperative mood, no period, no emoji | | Body | Optional, blank line after subject, 72 char line wrap | | Footers | `BREAKING CHANGE:`, `Refs:`, `Closes:`, `Fixes:`, `Implements:`, `See:` |
Commit messages, PR titles and branch names follow the language rule of `code-standards` Rule 10.
Examples
feat(helmrelease): add Phase 3.3 services
fix(pg-non-prod): correct API key environment variable mappings
refactor: simplify context provider logic
chore(deps): update terraform to v1.6.0
Multi-Line Body (No Heredoc, No Temp File)
Repeat `-m` once per paragraph -- `git -C /abs commit -m "type: subject" -m "First paragraph." -m "Second paragraph."` -- no heredoc, no temp file. For exact wraps, use `git commit -m "$(cat <<'EOF' ... EOF)"` instead (the bare-`cat` heredoc receiver `security-tiers` names). Never attach a bare, unquoted heredoc directly to git (`git commit -F - <<EOF ... EOF`) -- measured, the classifier misreads a prose line as a command and blocks with a spurious T3 (`Verb: 'rm' (MUTATIVE)` on text that only *mentions* `rm -rf`).
Git Path Flags
Target the repo with `git -C /absolute/path <verb>` -- this is the canonical form in a subagent. The T3 consent gate parses `-C` as a flag and classifies the command identically to the bare verb (`git -C /repo push origin main` is T3 `push`, same as `git push origin main`); there is NO bypass of Gaia's gate. The full discipline -- why one byte-identical form prevents the approval loop, and why a separate `cd` call cannot work (the cwd resets between Bash calls) -- lives in `command-execution` ("Before the call" rule 2 and "After the call"); follow it there.
Two narrow caveats:
- Prefer `-C /abs` (short flag) or `--git-dir=/abs` (equals form); both are
cleanly absorbed. Avoid the SPACE-separated `--git-dir /abs` / `--work-tree /abs` forms -- the path leaks into the first non-flag token and shifts the subcommand the local-safe guard reads (a mutative verb like `push` is still caught by the fallback scanner, but commit-message-leak protection is lost).
- The historical warning that a leading path flag "bypasses all rules silently"
described Claude Code's NATIVE settings.json prefix matching (`Bash(git commit:*)`), which Gaia used in 3.2.1 but no longer ships -- enforcement is now the PreToolUse hook, which is `-C`-robust. If a user adds their own `Bash(git ...:*)` allow rules, a leading path flag can still shift that prefix, but that affects only their auto-allow convenience, never Gaia's consent gate.
Push Defaults
Push to the feature branch. Only push directly to `main` when explicitly instructed or when the work is already on main. Force-push (`--force`) requires explicit user instruction.
Which of these ask for a signature (`security-tiers` owns the rule; the shapes are the entries of `verb_lexicon.py::EFFECT_OVER_VERB_EXCEPTIONS`):
- **Free:** `commit`, `add` and the other local subcommands;
`git -C /abs push [-u|--set-upstream] <remote> <branch>` when the branch is named, is not main, master or the remote's HEAD branch, and the repository's push configuration sends it to itself, with nothing before `git` (`mutative_verbs.py::_git_push_targets_feature_branch`).
- **Free in any repository:** a local `merge` whose flags are all in
`mutative_verbs.py::_GIT_LOCAL_MERGE_FLAGS` (`--no-ff`, `--ff-only`, `--squash`, ...), plus `-m <msg>`, with literal ref operands, and a bare `merge --abort|--continue|--quit` (`mutative_verbs.py::_git_merge_is_local`); opening a change request (`pr create`, any forge binary, any `--repo`; `forge_shapes.py::change_request_action`) and editing one on this checkout's origin without a retarget, ready, draft or status flag; `git fetch`, `pull --ff-only` and `switch`/`checkout <branch>` by elimination.
- **T3:** bare `git push`, a push to the default branch or `HEAD`, any push
with another flag (`--force`, `--force-with-lease`, `--delete`, `--mirror`, `--all`, `--tags`), a `+`/`:` refspec or a `src:dst` onto another branch (a force push signs as `sign.destroys`, never refused); `pr merge`; a change-request edit with `--base` (`_CHANGE_REQUEST_EDIT_FLAGS`) or on another origin (`mutative_verbs.py::_change_request_elsewhere`); a merge with a strategy option (`-s`, `-X`) or a computed operand; a `rebase` outside the unpushed, managed-worktree shape (`mutative_verbs.py::_git_rebase_rewrites_only_unpushed`); `reset --hard`.
Do not request the free forms in advance: run them, and request only what is still T3.
Hook Enforcement
The `commit_validator.py` hook validates against standards inlined as module-level constants in that file (`TYPE_ALLOWED`, `SUBJECT_MAX_LENGTH`, `SUBJECT_RULES`, `BODY_MAX_LINE_LENGTH`) -- it covers the conventional-commits format, subject, and body rules. Forbidden-footer detection lives separately in `bash_validator` (hardcoded there). Format violations block the commit. Body line length triggers warnings only.
Pull Request Body
The PR title reuses the commit subject's `type(scope): outcome` rule above. The body is a document a reviewer reads without having been there, so it is written with `technical-writing` (door: PR body), which owns its sections and the rule that no task id, plan label, approval, signature or tier appears in it. `commit_validator.py` validates only the commit message format; nothing parses or gates the body.
Read more
name: git-conventions description: Use when committing, squashing, merging, rebasing, or preparing changes for a pull request
Git Conventions
Commit Format
| Element | Rule | |---------|------| | Format | `type(scope): short description` | | Types | feat, fix, refactor, docs, test, chore, ci, perf, style, build | | Scope | Optional, reflects module/area changed | | Subject | Max 72 chars, lowercase start, imperative mood, no period, no emoji | | Body | Optional, blank line after subject, 72 char line wrap | | Footers | `BREAKING CHANGE:`, `Refs:`, `Closes:`, `Fixes:`, `Implements:`, `See:` |
Commit messages, PR titles and branch names follow the language rule of `code-standards` Rule 10.
Examples
feat(helmrelease): add Phase 3.3 services fix(pg-non-prod): correct API key environment variable mappings refactor: simplify context provider logic chore(deps): update terraform to v1.6.0
Multi-Line Body (No Heredoc, No Temp File)
Repeat `-m` once per paragraph -- `git -C /abs commit -m "type: subject" -m "First paragraph." -m "Second paragraph."` -- no heredoc, no temp file. For exact wraps, use `git commit -m "$(cat <<'EOF' ... EOF)"` instead (the bare-`cat` heredoc receiver `security-tiers` names). Never attach a bare, unquoted heredoc directly to git (`git commit -F - <<EOF ... EOF`) -- measured, the classifier misreads a prose line as a command and blocks with a spurious T3 (`Verb: 'rm' (MUTATIVE)` on text that only *mentions* `rm -rf`).
Git Path Flags
Target the repo with `git -C /absolute/path <verb>` -- this is the canonical form in a subagent. The T3 consent gate parses `-C` as a flag and classifies the command identically to the bare verb (`git -C /repo push origin main` is T3 `push`, same as `git push origin main`); there is NO bypass of Gaia's gate. The full discipline -- why one byte-identical form prevents the approval loop, and why a separate `cd` call cannot work (the cwd resets between Bash calls) -- lives in `command-execution` ("Before the call" rule 2 and "After the call"); follow it there.
Two narrow caveats:
- Prefer `-C /abs` (short flag) or `--git-dir=/abs` (equals form); both are
cleanly absorbed. Avoid the SPACE-separated `--git-dir /abs` / `--work-tree /abs` forms -- the path leaks into the first non-flag token and shifts the subcommand the local-safe guard reads (a mutative verb like `push` is still caught by the fallback scanner, but commit-message-leak protection is lost).
- The historical warning that a leading path flag "bypasses all rules silently"
described Claude Code's NATIVE settings.json prefix matching (`Bash(git commit:*)`), which Gaia used in 3.2.1 but no longer ships -- enforcement is now the PreToolUse hook, which is `-C`-robust. If a user adds their own `Bash(git ...:*)` allow rules, a leading path flag can still shift that prefix, but that affects only their auto-allow convenience, never Gaia's consent gate.
Push Defaults
Push to the feature branch. Only push directly to `main` when explicitly instructed or when the work is already on main. Force-push (`--force`) requires explicit user instruction.
Which of these ask for a signature (`security-tiers` owns the rule; the shapes are the entries of `verb_lexicon.py::EFFECT_OVER_VERB_EXCEPTIONS`):
- **Free:** `commit`, `add` and the other local subcommands;
`git -C /abs push [-u|--set-upstream] <remote> <branch>` when the branch is named, is not main, master or the remote's HEAD branch, and the repository's push configuration sends it to itself, with nothing before `git` (`mutative_verbs.py::_git_push_targets_feature_branch`).
- **Free in any repository:** a local `merge` whose flags are all in
`mutative_verbs.py::_GIT_LOCAL_MERGE_FLAGS` (`--no-ff`, `--ff-only`, `--squash`, ...), plus `-m <msg>`, with literal ref operands, and a bare `merge --abort|--continue|--quit` (`mutative_verbs.py::_git_merge_is_local`); opening a change request (`pr create`, any forge binary, any `--repo`; `forge_shapes.py::change_request_action`) and editing one on this checkout's origin without a retarget, ready, draft or status flag; `git fetch`, `pull --ff-only` and `switch`/`checkout <branch>` by elimination.
- **T3:** bare `git push`, a push to the default branch or `HEAD`, any push
with another flag (`--force`, `--force-with-lease`, `--delete`, `--mirror`, `--all`, `--tags`), a `+`/`:` refspec or a `src:dst` onto another branch (a force push signs as `sign.destroys`, never refused); `pr merge`; a change-request edit with `--base` (`_CHANGE_REQUEST_EDIT_FLAGS`) or on another origin (`mutative_verbs.py::_change_request_elsewhere`); a merge with a strategy option (`-s`, `-X`) or a computed operand; a `rebase` outside the unpushed, managed-worktree shape (`mutative_verbs.py::_git_rebase_rewrites_only_unpushed`); `reset --hard`.
Do not request the free forms in advance: run them, and request only what is still T3.
Hook Enforcement
The `commit_validator.py` hook validates against standards inlined as module-level constants in that file (`TYPE_ALLOWED`, `SUBJECT_MAX_LENGTH`, `SUBJECT_RULES`, `BODY_MAX_LINE_LENGTH`) -- it covers the conventional-commits format, subject, and body rules. Forbidden-footer detection lives separately in `bash_validator` (hardcoded there). Format violations block the commit. Body line length triggers warnings only.
Pull Request Body
The PR title reuses the commit subject's `type(scope): outcome` rule above. The body is a document a reviewer reads without having been there, so it is written with `technical-writing` (door: PR body), which owns its sections and the rule that no task id, plan label, approval, signature or tier appears in it. `commit_validator.py` validates only the commit message format; nothing parses or gates the body.
Generative AI Interface for Agents. Specialist agents for Claude Code and OpenCode, with a memory that outlives the session and a consent gate on everything that changes state.
Other skills on gaia.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about git-conventions.
- Which coding agents can use git-conventions?
- git-conventions installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

