From 0739619a0108fe3a8fec1b9c7f0545634908e08a Mon Sep 17 00:00:00 2001 From: Ivan Hilkov Date: Tue, 14 Jul 2026 09:20:29 +0300 Subject: [PATCH 1/6] #2 feat(2-git-memory): extend commit convention with git memory body and decision trailers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The write side of the git memory: commit bodies carry the Decision Shadow so a future agent recovers the why from git log alone. The vocabulary is fixed at four decision trailers; the body is required by content, not by commit type, so mechanical commits stay one-liners. The old blanket trailer ban narrows to identity trailers only. Rejected: nine-trailer Lore Protocol vocabulary — self-assessment keys degrade into ritual noise Related: #2 Related: .yoke/adr/0012-commit-messages-as-git-memory.md --- skills/gca/reference/commit-convention.md | 72 ++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/skills/gca/reference/commit-convention.md b/skills/gca/reference/commit-convention.md index e3cfa88..638bc9e 100644 --- a/skills/gca/reference/commit-convention.md +++ b/skills/gca/reference/commit-convention.md @@ -1,6 +1,9 @@ # Commit Convention -Commit format for yoke skills and standalone invocations. +Commit format for yoke skills and standalone invocations. This is the write +side of the **git memory** (ADR-0012): commit messages carry the project's +decision history, written for coding agents as the primary readers. The read +side — how to recover that history — lives in `history-reading.md`. --- @@ -11,7 +14,7 @@ Plugin-wide contract for when the agent may run git and how commits are shaped. - **Authorization.** A skill invocation (`/do`, `/merge`, `/gca`, `/gp`, `/pr`) authorizes the git operations that skill performs — commit, push, PR — with no mid-run "commit?" questions. - **Initiative.** Outside skill runs the agent never commits or pushes on its own initiative — only on an explicit user command. - **Language.** Commit messages default to English; a project may override via `.yoke/flow.md` or its `CLAUDE.md`. -- **Trailers.** Never add trailer lines (`Co-Authored-By`, `Signed-off-by`, etc.). +- **Trailers.** Never add identity trailers (`Co-Authored-By`, `Signed-off-by`, and the like). Decision trailers from the Body section are different — they carry memory, use them. - **Identity.** Never fabricate committer identity (no `git -c user.email=...`); when identity is missing, ask the user. --- @@ -44,6 +47,69 @@ R2-220 fix(R2-220-fix-doubled-stats): restrict analytics --- +## Body — the git memory + +The subject says what; the body says **why**. The body is the Decision +Shadow — the context that lived in the author's head when the code was +written and dies with the session unless it lands here. A future agent +recovers it with `git log -- ` (see `history-reading.md`). + +### When a body is required + +By content, not by type. Write a body when the commit carries a decision — a +chosen approach, a rejected alternative, a non-obvious constraint. The test: +**will a reader six months out wonder "why"?** Mechanical commits (dependency +bumps, formatting, generated files) stay one-liners. + +### Shape + +1. **Prose** — one or two short paragraphs of reasoning: why this approach, + what constraint drove it, what almost worked. Plain sentences, no headings, + no diff narration. +2. **Decision trailers** — after the prose, from the fixed vocabulary: + +| Trailer | Carries | +| ------------- | --------------------------------------------------------------- | +| `Constraint:` | An active rule the code must keep respecting | +| `Rejected:` | An approach considered or tried and dismissed — with the reason | +| `Directive:` | A warning to whoever touches this code next | +| `Related:` | A pointer: ticket, commit hash, or `.yoke/` artifact path | + +Every trailer is optional — write one only when there is real content; repeat +a key for multiple entries. Only these four keys: a fixed vocabulary is what +keeps the history greppable (`git log --grep="^Rejected:"`). + +### Example + +``` +#86 feat(86-black-jack-page): add SSE endpoint + +Polling was dropped: the kiosk network kills idle HTTP/1.1 +connections after 30s, SSE with retry survives it. Score state +lives server-side because the client is untrusted. + +Rejected: WebSocket — no proxy support on kiosks +Constraint: client is untrusted, never move score calc there +Related: #84 +``` + +### Body anti-patterns + +``` +# WRONG — diff narration, not a decision: +Added handleRetry() that retries the request and updated the tests. + +# WRONG — ritual trailers with no content: +Constraint: none +Confidence: high # not in the vocabulary; self-assessment is noise + +# RIGHT — the decision and its reason: +Retry lives in the client because the gateway strips Retry-After; +see the rejected server-side attempt in a1b2c3d. +``` + +--- + ## Ticket ID Priority cascade: @@ -158,6 +224,8 @@ Commits for yoke flow artifacts (format `TICKET docs(SLUG): description`): - One commit — one logical change. - Ticket ID first in the message (if present). +- A commit that carries a decision gets a prose body and, when there is + content, decision trailers — see "Body — the git memory". - Avoid `wip`, `temp`, `misc`. - Staging/exclusion policy lives in `staging-strategy.md`: gca excludes only untracked secrets, keys, and >1MB binaries, and always commits tracked files, git-crypt included. Never exclude a file by authorship. - Git initiative, message language, trailers, and committer identity follow "Git initiative and defaults". From 770ea40bfd4daee1679585636b019c6c3e2459d9 Mon Sep 17 00:00:00 2001 From: Ivan Hilkov Date: Tue, 14 Jul 2026 09:20:57 +0300 Subject: [PATCH 2/6] #2 feat(2-git-memory): add history reading guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The read side of the git memory: which git command answers which question, and how to act on Constraint/Directive/Rejected findings. Lives next to commit-convention.md because both sides of the memory share one owner, mirroring the issues/github-issues.md precedent. Directive: git log --trailer= does not exist — the real filters are --grep with a line-anchored key and the %(trailers:key=...) format Related: #2 --- skills/gca/reference/history-reading.md | 72 +++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 skills/gca/reference/history-reading.md diff --git a/skills/gca/reference/history-reading.md b/skills/gca/reference/history-reading.md new file mode 100644 index 0000000..56836c4 --- /dev/null +++ b/skills/gca/reference/history-reading.md @@ -0,0 +1,72 @@ +# History Reading + +The read side of the **git memory** (ADR-0012): how to recover the decision +history that `commit-convention.md` writes into commit messages. Run this +before touching or judging code — the history of a file carries constraints, +rejected approaches, and warnings that never made it into the code itself. + +--- + +## Before modifying a file + +```bash +git log -n 20 --format="%h %s" -- # quick pass over the intents +git log -n 5 -- # full messages: bodies + trailers +``` + +Act on what comes back: + +- `Constraint:` — an active rule. Respect it; when the plan conflicts with + it, surface the conflict instead of silently overriding. +- `Directive:` — a warning from a previous author. Heed it. +- `Rejected:` — a dead end already explored. Do not re-propose it without + new evidence; when you do, cite what changed. +- Prose bodies — the why behind the current shape. Read them before + concluding the code is wrong or accidental. + +## Before proposing an approach + +Check whether it was already tried and dismissed: + +```bash +git log --grep="^Rejected:" --format="%h %s%n%b" -- +``` + +`--grep` is line-oriented: `^Rejected:` anchors to a trailer line. Drop the +`-- ` to search the whole history. + +## Understanding one line + +```bash +git blame -L , # who last shaped these lines +git show # the full message — body and trailers +``` + +`git blame` gives the hash; `git show` gives the memory. Two steps from a +puzzling line to the decision behind it. + +## Searching wider + +```bash +git log --grep="" # search all messages +git log --follow -- # history across renames +``` + +## Trailer-aware output + +```bash +git log --format="%h %s%n%(trailers:key=Constraint,key=Directive,valueonly=false)" -- +``` + +`%(trailers:key=...)` prints only the named trailers — useful for harvesting +every active `Constraint:` over a directory in one pass. + +--- + +## Depth + +Ten subjects and the last five full messages per touched file is the default; +dig deeper (`--follow`, `--grep` over all history) only when a body references +older context or the file is central to the change. Older projects have +pre-memory history — a one-line commit with no body is normal there and +carries no signal beyond its subject. From 2ef07b2b4c42b5480161147af046bd3982c2edc5 Mon Sep 17 00:00:00 2001 From: Ivan Hilkov Date: Tue, 14 Jul 2026 09:21:49 +0300 Subject: [PATCH 3/6] #2 feat(2-git-memory): add git memory read step to all code skills Every skill that touches or judges code now reads the affected files' commit history before working, so constraints and rejected approaches recorded in the memory actually steer new work. Executors (do, draft) gate modification on it; review must cite the commit a finding argues with; the exploration skills (grill, grill-docs, prd, issues) treat history findings as interview and artifact material. Related: #2 --- skills/do/SKILL.md | 6 ++++++ skills/draft/SKILL.md | 4 ++++ skills/grill-docs/SKILL.md | 2 ++ skills/grill/SKILL.md | 1 + skills/issues/SKILL.md | 2 +- skills/prd/SKILL.md | 2 +- skills/review/SKILL.md | 1 + 7 files changed, 16 insertions(+), 2 deletions(-) diff --git a/skills/do/SKILL.md b/skills/do/SKILL.md index f5f2f85..4125730 100644 --- a/skills/do/SKILL.md +++ b/skills/do/SKILL.md @@ -91,6 +91,12 @@ These hold for every mode run: - **Commits by convention.** Format, ticket ID, and git initiative — from `${CLAUDE_PLUGIN_ROOT}/skills/gca/reference/commit-convention.md` (see its "Git initiative and defaults"). Do not ask "commit?" mid-run. +- **Read the git memory first.** Before modifying a file, read its recent + commit history per + `${CLAUDE_PLUGIN_ROOT}/skills/gca/reference/history-reading.md`. A + `Constraint:` or `Directive:` that conflicts with the plan is surfaced, + not silently overridden; a `Rejected:` approach is not re-proposed + without new evidence. - **Review after each task.** Spec compliance → code quality. Mandatory. - **Context isolation.** A sub-agent receives only its own task text, not the whole plan. diff --git a/skills/draft/SKILL.md b/skills/draft/SKILL.md index 2566dd9..5d64a3c 100644 --- a/skills/draft/SKILL.md +++ b/skills/draft/SKILL.md @@ -65,6 +65,10 @@ These hold for every run: `.yoke/ai//`. - **Commits by convention** per `${CLAUDE_PLUGIN_ROOT}/skills/gca/reference/commit-convention.md`. +- **Read the git memory first** per + `${CLAUDE_PLUGIN_ROOT}/skills/gca/reference/history-reading.md` — a Marker + must not re-propose what a `Rejected:` trailer already dismissed, and + Markup respects active `Constraint:` entries. - Language: match the ticket/input language, or follow the project-level definition in CLAUDE.md / AGENTS.md. diff --git a/skills/grill-docs/SKILL.md b/skills/grill-docs/SKILL.md index 250dcb2..553a16f 100644 --- a/skills/grill-docs/SKILL.md +++ b/skills/grill-docs/SKILL.md @@ -29,6 +29,8 @@ If a question can be answered by exploring the codebase, explore the codebase in ## Domain awareness +During codebase exploration, also read the git memory: the affected files' commit history per `${CLAUDE_PLUGIN_ROOT}/skills/gca/reference/history-reading.md` — a past `Rejected:` or `Constraint:` trailer is grill material, cite it when challenging the plan. + During codebase exploration, also look for existing documentation: ### File structure diff --git a/skills/grill/SKILL.md b/skills/grill/SKILL.md index 2bcca0c..4272670 100644 --- a/skills/grill/SKILL.md +++ b/skills/grill/SKILL.md @@ -48,5 +48,6 @@ Stop when a full pass down the tree surfaces no new open decisions, or when the - Always include the recommended answer, listed first. - Resolve dependencies in order — don't jump branches. - Prefer exploring the codebase over asking when the codebase holds the answer. +- Exploring the codebase includes its git memory: read the affected files' commit history per `${CLAUDE_PLUGIN_ROOT}/skills/gca/reference/history-reading.md` — a past `Rejected:` or `Constraint:` trailer is grill material, cite it when challenging the plan. - For deeper grilling that also captures terminology and decisions into `.yoke/context.md` and ADRs, use `/yoke:grill-docs`. - Language: match the user's language, or follow the project-level definition in CLAUDE.md / AGENTS.md. diff --git a/skills/issues/SKILL.md b/skills/issues/SKILL.md index e86fedf..d82e833 100644 --- a/skills/issues/SKILL.md +++ b/skills/issues/SKILL.md @@ -20,7 +20,7 @@ Work from whatever is already in the conversation context. If the user passes an ### 2. Explore the codebase (skip if already explored this session) -If the codebase has not been explored this session, explore it now to understand its current state. Follow the domain-doc consumer rules in `${CLAUDE_PLUGIN_ROOT}/skills/grill-docs/reference/domain-docs.md`: read `.yoke/context.md` and relevant `.yoke/adr/`, give issue titles and descriptions the glossary's vocabulary, and flag any ADR a slice contradicts. +If the codebase has not been explored this session, explore it now to understand its current state. Follow the domain-doc consumer rules in `${CLAUDE_PLUGIN_ROOT}/skills/grill-docs/reference/domain-docs.md`: read `.yoke/context.md` and relevant `.yoke/adr/`, give issue titles and descriptions the glossary's vocabulary, and flag any ADR a slice contradicts. Also read the git memory of the areas the slices touch per `${CLAUDE_PLUGIN_ROOT}/skills/gca/reference/history-reading.md` — a slice that re-proposes a `Rejected:` approach or crosses a `Constraint:` must say so. ### 3. Draft vertical slices diff --git a/skills/prd/SKILL.md b/skills/prd/SKILL.md index a378abf..b6dbfec 100644 --- a/skills/prd/SKILL.md +++ b/skills/prd/SKILL.md @@ -14,7 +14,7 @@ Turn the current conversation and codebase understanding into a PRD. Do NOT inte ## Process -1. **Explore the repo** to understand the codebase, if not already done. Follow the domain-doc consumer rules in `${CLAUDE_PLUGIN_ROOT}/skills/grill-docs/reference/domain-docs.md`: read `.yoke/context.md` and the relevant `.yoke/adr/`, use the glossary's vocabulary throughout the PRD, and flag any ADR the PRD contradicts. +1. **Explore the repo** to understand the codebase, if not already done. Follow the domain-doc consumer rules in `${CLAUDE_PLUGIN_ROOT}/skills/grill-docs/reference/domain-docs.md`: read `.yoke/context.md` and the relevant `.yoke/adr/`, use the glossary's vocabulary throughout the PRD, and flag any ADR the PRD contradicts. Also read the git memory of the modules the PRD touches per `${CLAUDE_PLUGIN_ROOT}/skills/gca/reference/history-reading.md` — active `Constraint:` entries and past `Rejected:` approaches belong in Implementation Decisions. 2. **Sketch the major modules** to build or modify. Look for deep modules to extract that can be tested in isolation. A deep module encapsulates substantial functionality behind a simple, testable interface that rarely changes. Decide the module breakdown and which modules are test-worthy yourself, and record both in the PRD's Implementation Decisions and Testing Decisions sections — do not stop to interview the user. diff --git a/skills/review/SKILL.md b/skills/review/SKILL.md index ec3c665..eaabf3f 100644 --- a/skills/review/SKILL.md +++ b/skills/review/SKILL.md @@ -34,4 +34,5 @@ The full pipeline — scope resolution, the code-reviewer dispatch, finding clas - **Report location.** Write the report to `.yoke/ai//-review.md`. - **Every fork is one question.** For any decision — fix scope, next action — ask a single AskUserQuestion with the recommended option listed first. - **Delegate the work.** File edits, bash, and analysis go to sub-agents; each receives only its own data. +- **Read the git memory.** Pull decision context from the affected files' commit history per `${CLAUDE_PLUGIN_ROOT}/skills/gca/reference/history-reading.md` — a finding that contradicts a `Constraint:` or re-proposes a `Rejected:` approach must cite the commit it argues with. - Language: match the ticket/input language, or follow the project-level definition in CLAUDE.md / AGENTS.md. From c045055ac6d4ce0792bb83fe51a9b65f67ba232b Mon Sep 17 00:00:00 2001 From: Ivan Hilkov Date: Tue, 14 Jul 2026 09:23:21 +0300 Subject: [PATCH 4/6] #2 feat(2-git-memory): scaffold git memory section and commit-msg hook in bootstrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Distribution of the git memory to target projects rides the two things bootstrap already generates: a mandatory CLAUDE.md section (always-on for any agent, with or without yoke skills) and a commit-msg hook. The hook checks shape and presence only — a hook cannot judge whether a commit carries a decision, so a bodyless feat/fix/refactor warns instead of blocking. Rejected: a separate .claude/rules/ file per the original issue #2 plan — one more artifact where an existing CLAUDE.md section suffices Related: #2 --- .../bootstrap/agents/claude-md-generator.md | 31 ++++++++++++- .../bootstrap/reference/bootstrap-pipeline.md | 9 ++++ skills/bootstrap/reference/hooks-patterns.md | 43 +++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/skills/bootstrap/agents/claude-md-generator.md b/skills/bootstrap/agents/claude-md-generator.md index f96ac27..d5ed952 100644 --- a/skills/bootstrap/agents/claude-md-generator.md +++ b/skills/bootstrap/agents/claude-md-generator.md @@ -56,7 +56,7 @@ You are the CLAUDE.md generator: create or extend the project's file. - Non-obvious decisions and gotchas (extract from DOC_CONTENT — workarounds, limitations; from `DOMAIN_FINDINGS.CODE_WORKAROUNDS` — code-level workarounds) - Workflows and processes (extract from DOC_CONTENT — CI/CD, deploy, release flow) 4. If DOMAIN_FINDINGS and DOC_CONTENT overlap, prefer DOC_CONTENT (don't duplicate). -5. Add an "Artifact root (`.yoke/`)" section (see below for required content). +5. Add the "Artifact root (`.yoke/`)" and "Git memory (commit convention)" sections (see below for required content). 6. Write CLAUDE.md to the project root ### 4. Enrich mode (CLAUDE_MD_EXISTS = true) @@ -69,6 +69,7 @@ You are the CLAUDE.md generator: create or extend the project's file. - Non-obvious — are gotchas/workarounds captured? - Conventions — are project-specific conventions described? - Artifact root — is the `.yoke/` layout documented? (add if absent) + - Git memory — is the commit convention documented? (add if absent) 3. For each missing section — add it via Edit, using DOC_CONTENT as the source: - Project description — from README.md and other documentation files - Non-obvious decisions and gotchas — from CONTRIBUTING.md, docs/ @@ -104,6 +105,32 @@ Yoke stores all AI-generated artifacts under `.yoke/` at the project root: If the section already exists with equivalent content, do not duplicate it. +## Git memory (commit convention) section — required content + +Every generated or enriched CLAUDE.md must also contain this section (place it +next to the Artifact root section). When the project already documents a +commit format, merge — keep the project's ticket/type specifics and add the +memory rules; do not leave two competing commit sections. + +```markdown +## Git memory (commit convention) + +Commit messages are this project's long-term decision memory, written for +coding agents as much as for people. + +- Subject: `TICKET type(SLUG): description` — ticket first when one exists. +- A commit that carries a decision (chosen approach, rejected alternative, + non-obvious constraint) gets a prose body explaining **why**, then optional + decision trailers: `Constraint:`, `Rejected:`, `Directive:`, `Related:`. + Mechanical commits stay one-liners. +- Never add identity trailers (`Co-Authored-By`, `Signed-off-by`). +- Before modifying a file, read its memory: `git log -n 5 -- `. + Respect `Constraint:`, heed `Directive:`, do not re-propose `Rejected:` + approaches without new evidence. +- A `commit-msg` hook validates the subject shape and warns when a + feat/fix/refactor commit lacks a body. +``` + ## Rules - Preserve user content — sections added manually stay on update @@ -114,7 +141,7 @@ If the section already exists with equivalent content, do not duplicate it. - On create, use Write - Don't verify commands — the verifier does that - Reach Grade A against quality-criteria (90+ points) -- The "Artifact root (`.yoke/`)" section is mandatory in every output (create and enrich) +- The "Artifact root (`.yoke/`)" and "Git memory (commit convention)" sections are mandatory in every output (create and enrich) ## Response format diff --git a/skills/bootstrap/reference/bootstrap-pipeline.md b/skills/bootstrap/reference/bootstrap-pipeline.md index d9e265f..2f9fcd9 100644 --- a/skills/bootstrap/reference/bootstrap-pipeline.md +++ b/skills/bootstrap/reference/bootstrap-pipeline.md @@ -248,6 +248,12 @@ Dispatch 3 agents **in parallel** via the Agent tool: Result → RECOMMENDATIONS (list of automation recommendations). +4. **Git memory hook** (orchestrator, no agent) — after the agents return, + scaffold the `commit-msg` hook per `reference/hooks-patterns.md` § Git + memory commit-msg hook: into `.husky/commit-msg` when the project uses + husky, else `.git/hooks/commit-msg` (`chmod +x`). A `commit-msg` hook + already exists → do not touch it; record the fact in VERIFY_NOTES. + Wait for all 3. Mark in TodoWrite: `[x] Generate`. Transition → Phase 4. --- @@ -406,6 +412,9 @@ git add CLAUDE.md .yoke/ git commit -m "chore: bootstrap yoke flow context and .yoke/ scaffold" ``` +When Phase 3 wrote `.husky/commit-msg`, stage it too — `.git/hooks/` stays +local by nature and is never staged. + **Local-only** — `.yoke/` is gitignored; commit only the repo-level artifacts. `.yoke/flow.md` and `.yoke/yoke-context.md` stay on disk, untracked: diff --git a/skills/bootstrap/reference/hooks-patterns.md b/skills/bootstrap/reference/hooks-patterns.md index b1266fa..f11fa9c 100644 --- a/skills/bootstrap/reference/hooks-patterns.md +++ b/skills/bootstrap/reference/hooks-patterns.md @@ -101,6 +101,49 @@ Claude Code supports hooks via `hooks.json` in a plugin or `settings.json` local } ``` +## Git memory commit-msg hook + +Enforces the commit convention from the "Git memory" section bootstrap adds to +CLAUDE.md: a malformed subject **blocks** the commit; a feat/fix/refactor +commit without a body gets a **warning** on stderr — an agent sees it and +amends, a human may ignore it. The hook never judges content, only shape and +presence. + +Location: `.husky/commit-msg` when the project uses husky (tracked, reaches +the whole team), otherwise `.git/hooks/commit-msg` with `chmod +x` (local +only — note that in the summary). Never overwrite an existing `commit-msg` +hook — leave it and report instead. + +```sh +#!/usr/bin/env sh +msg_file="$1" +subject=$(head -n 1 "$msg_file") + +case "$subject" in + Merge\ * | Revert\ * | fixup!* | squash!*) exit 0 ;; +esac + +if ! printf '%s' "$subject" | grep -qE '^(([A-Z]+-[0-9]+|#[0-9]+) )?(feat|fix|refactor|docs|test|chore|style|perf)(\([^)]+\))?: .+'; then + echo "commit-msg: bad subject '$subject'" >&2 + echo "commit-msg: expected 'TICKET type(SLUG): description' — see the Git memory section in CLAUDE.md" >&2 + exit 1 +fi + +type=$(printf '%s' "$subject" | sed -E 's/^(([A-Z]+-[0-9]+|#[0-9]+) )?([a-z]+).*/\3/') +case "$type" in + feat | fix | refactor) + if ! sed -n '2,$p' "$msg_file" | grep -v '^#' | grep -q '[^[:space:]]'; then + echo "commit-msg: warning — $type commit without a body; if it carries a decision, amend with the why (Git memory, CLAUDE.md)" >&2 + fi + ;; +esac + +exit 0 +``` + +No extra CLAUDE.md note is needed — the Git memory section already mentions +the hook. + ## Git hooks by stack ### Node.js — Prettier + ESLint From 68519b05bf040a45afb2990f214ddecdd9a37e02 Mon Sep 17 00:00:00 2001 From: Ivan Hilkov Date: Tue, 14 Jul 2026 09:25:13 +0300 Subject: [PATCH 5/6] #2 fix(2-git-memory): accept digits in ticket project codes The hook's ticket pattern [A-Z]+-[0-9]+ rejected R2-50-style ids where the project code itself contains a digit; real YouTrack projects use them. Caught by running the hook against the convention's own examples. Constraint: hook regex must accept every ticket form the commit-convention Ticket ID tables list Related: #2 --- skills/bootstrap/reference/hooks-patterns.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skills/bootstrap/reference/hooks-patterns.md b/skills/bootstrap/reference/hooks-patterns.md index f11fa9c..a2e416d 100644 --- a/skills/bootstrap/reference/hooks-patterns.md +++ b/skills/bootstrap/reference/hooks-patterns.md @@ -123,13 +123,13 @@ case "$subject" in Merge\ * | Revert\ * | fixup!* | squash!*) exit 0 ;; esac -if ! printf '%s' "$subject" | grep -qE '^(([A-Z]+-[0-9]+|#[0-9]+) )?(feat|fix|refactor|docs|test|chore|style|perf)(\([^)]+\))?: .+'; then +if ! printf '%s' "$subject" | grep -qE '^(([A-Z][A-Z0-9]*-[0-9]+|#[0-9]+) )?(feat|fix|refactor|docs|test|chore|style|perf)(\([^)]+\))?: .+'; then echo "commit-msg: bad subject '$subject'" >&2 echo "commit-msg: expected 'TICKET type(SLUG): description' — see the Git memory section in CLAUDE.md" >&2 exit 1 fi -type=$(printf '%s' "$subject" | sed -E 's/^(([A-Z]+-[0-9]+|#[0-9]+) )?([a-z]+).*/\3/') +type=$(printf '%s' "$subject" | sed -E 's/^(([A-Z][A-Z0-9]*-[0-9]+|#[0-9]+) )?([a-z]+).*/\3/') case "$type" in feat | fix | refactor) if ! sed -n '2,$p' "$msg_file" | grep -v '^#' | grep -q '[^[:space:]]'; then From 9d37dda1c265f843ba9125d6e7e806ab2f18c579 Mon Sep 17 00:00:00 2001 From: Ivan Hilkov Date: Tue, 14 Jul 2026 09:25:33 +0300 Subject: [PATCH 6/6] #2 chore(2-git-memory): adopt the git memory convention in the yoke repo Dogfooding: the repo that ships the convention runs the hook itself, so the read side gets real history to work against. The hook is tracked in .husky/ and activates for everyone via the existing husky prepare script; commits in this very branch already follow the format. Related: #2 --- .husky/commit-msg | 24 ++++++++++++++++++++++++ CLAUDE.md | 1 + 2 files changed, 25 insertions(+) create mode 100755 .husky/commit-msg diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..cbffb85 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,24 @@ +#!/usr/bin/env sh +msg_file="$1" +subject=$(head -n 1 "$msg_file") + +case "$subject" in + Merge\ * | Revert\ * | fixup!* | squash!*) exit 0 ;; +esac + +if ! printf '%s' "$subject" | grep -qE '^(([A-Z][A-Z0-9]*-[0-9]+|#[0-9]+) )?(feat|fix|refactor|docs|test|chore|style|perf)(\([^)]+\))?: .+'; then + echo "commit-msg: bad subject '$subject'" >&2 + echo "commit-msg: expected 'TICKET type(SLUG): description' — see the Git memory section in CLAUDE.md" >&2 + exit 1 +fi + +type=$(printf '%s' "$subject" | sed -E 's/^(([A-Z][A-Z0-9]*-[0-9]+|#[0-9]+) )?([a-z]+).*/\3/') +case "$type" in + feat | fix | refactor) + if ! sed -n '2,$p' "$msg_file" | grep -v '^#' | grep -q '[^[:space:]]'; then + echo "commit-msg: warning — $type commit without a body; if it carries a decision, amend with the why (Git memory, CLAUDE.md)" >&2 + fi + ;; +esac + +exit 0 diff --git a/CLAUDE.md b/CLAUDE.md index d53f985..dc4cf81 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -48,6 +48,7 @@ claude --plugin-dir . ## Conventions - **Content language**: English by default. Skills adapt to the ticket/input language, or follow the project-level definition in CLAUDE.md / AGENTS.md. +- **Commits**: `TICKET type(SLUG): description`; a commit that carries a decision gets a prose body plus decision trailers (`Constraint:`, `Rejected:`, `Directive:`, `Related:`) — the git memory, see `skills/gca/reference/commit-convention.md`. Before modifying a file, read its history per `skills/gca/reference/history-reading.md`. Subject shape is enforced by `.husky/commit-msg`. - **Files and directories**: kebab-case - **Versioning**: semver in `plugin.json` (source of truth for the version) - **marketplace.json**: required top-level fields — `name`, `owner` (object with `name`), `plugins[]`