Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .claude/rules/go.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ paths:
double-click launch from Explorer. New CLI subcommands call
`wincon.AttachParent()` at the top.
- Commits: lowercase, terse, scope-prefixed ("v2 motion: …"); one concern per
commit; protocol and implementation never change in the same commit.
commit; protocol and implementation never change in the same commit. Naming +
hygiene (no plan labels, no attribution trailers): `docs/agent/naming.md`.
42 changes: 42 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,48 @@ jobs:
bash <(curl -sSf https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
./actionlint -color

# docs/agent/naming.md: names describe the change, never the plan that produced
# it, and commit messages carry no assistant attribution. PR-only because the
# checked surfaces (head branch, title, commit range) only exist on PRs.
naming:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
fetch-depth: 0
# head_ref and the PR title are attacker-controlled on fork PRs — they enter
# the script through env, never through template interpolation (zizmor).
- name: no plan jargon or attribution trailers
env:
HEAD_REF: ${{ github.head_ref }}
PR_TITLE: ${{ github.event.pull_request.title }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
jargon='\b(phase|pillar|sprint|milestone|week)[ _-]?[0-9ivx]+\b|\bbatch[ _-][a-d0-9]\b'
trailers='^(co-authored-by:.*claude|claude-session:)'
fail=0
if printf '%s\n%s\n' "$HEAD_REF" "$PR_TITLE" | grep -qiE "$jargon"; then
echo "::error::branch name or PR title carries plan jargon - name the change, not the plan (docs/agent/naming.md)"
fail=1
fi
if git log --format='%B' "$BASE_SHA..HEAD" | grep -qiE "$jargon"; then
echo "::error::a commit message in this PR carries plan jargon - name the change, not the plan (docs/agent/naming.md)"
git log --format='%h %s' "$BASE_SHA..HEAD" | grep -iE "$jargon" || true
fail=1
fi
if git log --format='%B' "$BASE_SHA..HEAD" | grep -qiE "$trailers"; then
echo "::error::assistant attribution trailer in a commit message - no Claude-Session/Co-Authored-By: Claude (docs/agent/naming.md)"
fail=1
fi
if git diff --name-only "$BASE_SHA...HEAD" | grep -iE '(phase|pillar|sprint|milestone|week|batch)[_-]?([0-9ivx]+|[a-d])([._-]|$)'; then
echo "::error::a changed file path carries plan jargon - name the file for its topic (docs/agent/naming.md)"
fail=1
fi
exit "$fail"

build-windows:
needs: frontend
runs-on: windows-latest
Expand Down
11 changes: 10 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ polish. Protect what works; be honest about what doesn't exist yet (Reality chec
triggers** — `docs/agent/reasoning.md`. Read it before chasing any bug.
- **Known UX debt** — `docs/agent/polish-backlog.md`; pull from it before inventing
new polish work.
- **Naming & git hygiene** (branches, PRs, commits, spec files) —
`docs/agent/naming.md`; CI's naming job is the gate.
- **Full command list + devmock UI state matrix** — `docs/agent/commands.md`.
- **Design charter** — `frontend/DESIGN.md`; read it before any UI work.

Expand Down Expand Up @@ -216,13 +218,20 @@ Nothing enforces this; it is judgment, and ignoring it has already cost a sessio
and check with `git merge-base --is-ancestor` rather than assuming one exists.
- **Label knowingly-incomplete work `wip:` and say what is missing.** An unlabelled
stub reads as a finished decision to the next session.
- **Name branches, PRs, and commits for the change, never the plan that produced
them** — plan labels ("phase 9", "pillar 8") mean nothing outside their session.
Rules + examples: `docs/agent/naming.md`; CI's naming job is the gate.
- **No attribution in commits.** DO NOT append Claude session URLs; DO NOT include
`Co-Authored-By: Claude` trailers. The message says what changed and why, nothing
else (same gate; `.claude/settings.json` sets attribution empty at the source).

## Enforcement — what is a gate, not advice

Blocks a merge → CI. `.github/workflows/ci.yml`: gofmt, vet, `go test -short` (unit +
e2e + goleak + doccheck), `-race` (CI is the **only** place it runs — it needs cgo),
the burst floor (own job, best-of-3 — never lower the floor to go green),
`golangci-lint` (`.golangci.yml`), a TODO/FIXME ban, `actionlint`, and a
`golangci-lint` (`.golangci.yml`), a TODO/FIXME ban, `actionlint`, the naming gate
(plan jargon + attribution trailers anywhere in a PR — `docs/agent/naming.md`), and a
stale-`frontend/wailsjs` check. `.github/workflows/security.yml`: CodeQL, govulncheck,
gitleaks, dependency-review, npm audit (gosec/zizmor/Scorecard are advisory → Security
tab). `.github/workflows/fuzz.yml` fuzzes the parsers nightly;
Expand Down
55 changes: 55 additions & 0 deletions docs/agent/naming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Naming & git hygiene — name the change, never the plan

Plans are session-scoped; names are permanent. A branch, PR, commit, or spec file
named after a plan's internal structure ("phase 9", "pillar 8", "batch A") means
nothing the moment that session ends. Cleaning them out of this repo on 2026-07-17
cost a 56-commit history rewrite, two branch renames, and edits to three merged
PRs — names that describe **what the change is** never need that.

Enforced by the `naming` job in `.github/workflows/ci.yml`: every PR's head branch
name, title, commit messages, and changed file paths are rejected if they carry
plan jargon or attribution trailers.

## The durability test

*Would this name make sense to someone who never saw the plan that produced it?*
If decoding a name requires the plan document, the name is wrong.

## Rules

- **Branches** are `type/feature-slug` — `feat/`, `fix/`, `security/`, `docs/`,
`ci/`, `deps/`. The slug names the capability or fix (`feat/agent-management-gui`,
`security/agent-identity-hardening`), never a plan label, counter, or date.
- **PR titles** read like a commit subject: what the change is. **PR bodies**
describe what changed and how it was verified — plan narrative stays in the plan.
Cross-reference other work by PR number (#13) or branch name, never by plan label.
- **Commit messages, body included.** "Lands in Phase 3" rots the moment the plan
dies; point at the artifact instead ("lands with the multi-agent GUI"). Avoid bare
commit SHAs in messages and PR bodies where a PR number or filename works — SHAs
don't survive history rewrites.
- **Spec files** under docs/superpowers/specs/ are named
YYYY-MM-DD-topic-design.md — the topic, not the plan's name for the work.
- **No attribution trailers.** No Claude session URLs, no Co-Authored-By: Claude.
A commit message carries what changed and why — nothing else.
`.claude/settings.json` sets attribution empty at the source; the CI gate
catches strays.
- **Merge commits take the PR title** — a repo setting (merge_commit_title:
PR_TITLE), so never hand-write "Merge pull request #N from …" subjects. Head
branches auto-delete on merge; don't recreate long-lived ones.

## Banned in names and messages (the CI regex, case-insensitive)

phase/pillar/sprint/milestone/week followed by a number, "batch" followed by a
letter or number, `Claude-Session:` and `Co-Authored-By: …Claude…` trailer lines.

## Before → after (from the 2026-07-17 cleanup)

```
feat/identity-phase9-finalize → feat/identity-enrollment-finalize
feat/pillar8-agent-mgmt → feat/agent-management-gui
identity phase 9: … finalize + docs → identity: enrollment, pairing, and revocation — finalize + docs
docs: Pillar 8 … Batch A design spec → docs: agent-management GUI surfacing design spec
"until Phase 3's Status.Agents" → "until the multi-agent GUI's Status.Agents lands"
2026-07-16-pillar8-agent-management-gui-design.md
→ 2026-07-16-agent-management-gui-surfacing-design.md
```