CLAUDE.md · diff

git:20260716.1d599e1 to git:20260721.4ddf94c

4 added, 4 removed. Audit A to A.

# Maintainer guide for AI-assisted work on cladding
This file is read by Claude Code (and any other AI assistant with project-instructions support) when working **inside** the cladding repo. It captures invariants that aren't visible from a clean `git clone` — i.e. things a human-or-AI maintainer must respect that aren't enforced by tests or detectors alone.
External cladding users (people running cladding on *their own* project) read `README.md` + `docs/spec-ids-multi-dev.md` instead.
## Spec authoring — always hash, never F-NNN
When adding a new spec entry to `spec/features/` or `spec/scenarios/`:
- **DO NOT** create `spec/features/F-NNN.yaml` (the legacy sequential format) by hand.
- **DO** use the hash-based model:
- Filename: `<slug>-<hash>.yaml` (e.g. `auth-bypass-c4d108e9.yaml`)
- Inside the yaml: `id: F-<hash>` plus `slug: <slug>`
- The hash is an 8-character hex string since 0.6.0 (legacy 6-char ids stay valid). Generate with:
```bash
node -e "console.log('F-' + require('node:crypto').randomBytes(4).toString('hex'))"
```
This rule exists because v0.3.9 introduced the multi-developer-safe hash model and external users get hash-based IDs whenever they invoke `clad_create_feature` via their host AI. Cladding's own spec must dogfood the same model — otherwise the reference implementation drifts from what the standard recommends.
Legacy `F-001` ~ `F-083` files (authored before v0.3.9) stay sequential — they're stable identifiers in audit logs and historical references. Do not migrate them.
Files `F-082` ~ `F-090` were the *drift period* (authored after v0.3.9 but bypassing the hash model). v0.3.16 migrated them via `scripts/migrate-dogfood-v0.3.16.mjs`.
## Version bumps — use the script
Don't hand-edit version strings. There are eleven sites (incl. `.claude-plugin/marketplace.json`, the marketplace *catalog* the Claude Code host reads to detect "update available"); missing one breaks `HARNESS_INTEGRITY` (which now also guards the marketplace catalog version). Run:
```bash
npm run version-bump -- 0.3.X
```
## Detector additions — count is auto-recomputed
When you add a drift detector under `src/stages/detectors/`:
- Register it in `src/stages/detectors/index.ts` `allDetectors` array.
- Run `npm run build:plugin` (or `npm run build`, which calls it). Phase D of `scripts/build-plugin.mjs` (v0.3.17) recounts files and rewrites both `ironclad.current.detectors` and `ironclad.target.detectors` in `.claude-plugin/plugin.json`. No manual `N/N` edit needed — the filesystem is source-of-truth.
## Plugin manifest mirrors — built, not hand-authored
`agents/`, `plugins/codex/skills/`, `plugins/gemini-cli/commands/` are regenerated by `scripts/build-plugin.mjs`. Don't hand-edit those — edit the canonical sources (`src/agents/*.md` for persona prompts, `skills/<verb>/SKILL.md` for verb skills) and run `npm run build:plugin`.
## Release flow
A user-explicit instruction ("release vX.Y.Z") triggers the ritual:
1. `npm run version-bump -- X.Y.Z` (all eleven sites) + `npm install` (refresh the committed `package-lock.json` to the new version — CI's `npm ci` fails on a stale lock) + `npm run build` + GREEN `npm test` / `clad check --strict`
2. open a **PR `develop → main`** and merge it with the GitHub **"Create a merge commit"** button — NEVER squash, NEVER rebase (see the squash-ban below)
3. `git tag vX.Y.Z` on main's merge commit
4. push main + tag, then **back-merge `main → develop`** (`git checkout develop && git merge origin/main && git push`) so develop keeps the release commit in its ancestry — skip this and the next release PR phantom-conflicts
5. **`npm publish`** — existing users install the engine via the global npm `clad`, so a tag + `gh release` alone does NOT reach them; the registry must carry the new version or they stay frozen on the old one. (`prepublishOnly` rebuilds dist + mirrors first, so the tarball is never stale.)
6. `gh release create vX.Y.Z --notes-file <CHANGELOG section>`
The marketplace plugin (Claude Code / Codex / Gemini) ships only the prompts + the `mcpServers` wiring and delegates the engine to the global `clad` — so **both channels must be released in lockstep**: `npm publish` for the engine, the bumped `marketplace.json` catalog (step 1) for the plugin's "update available" signal.
Never auto-tag, auto-publish, or auto-release. Patch-first cadence — minor bumps (0.4.0 etc.) need explicit user confirmation.
**All merges go through a PR — git-flow, always.** `feature/* → develop` and `develop → main` both land via PR; no direct pushes that bypass review. For `develop → main`, **always use a merge commit — NEVER squash, NEVER rebase.** A squash puts the release commit outside develop's ancestry, so the *next* release PR reports every file touched since as conflicting (the v0.5.2 squash via PR #180 made PR #181 show 31 phantom conflicts; #183's squash left develop unreconciled until a manual `merge origin/main` reconciliation on 2026-06-25). GitHub has no per-branch merge-method lock, so this is a hand-enforced convention: deliberately pick "Create a merge commit" on every `develop → main` PR, then back-merge `main → develop` (step 4) to keep develop a clean superset. Squashing `feature/* → develop` PRs is fine — only the `develop → main` direction causes the divergence.
## Derived-file merge conflicts — never hand-resolve
`spec/attestation.yaml` and `spec/index.yaml` are harness-written. On a merge or rebase conflict in either, never hand-edit the hashes — both sides are stale against the merged tree, and only a GREEN `clad check --tier=pre-push --strict` gate computes the truth. Follow the canonical ritual in `docs/spec-ids-multi-dev.md` under **"Merging: derived files heal, never hand-resolve"** — do not duplicate the steps here.
## AI behavior guidance from `spec.yaml.project.ai_hints`
When operating inside a cladding-managed project (cladding itself included), grep `spec.yaml::project.ai_hints` at session start. It is the SSoT for AI behavior policy:
- **`preferred_persona`** — which persona prompt to default to (`planner`, `developer`, `reviewer`, `observability`, `orchestrator`)
- **`token_budget_per_session`** — soft cap on session size
- **`test_framework`, `primary_branch`** — operational defaults (e.g. `vitest`, `develop`)
- **`forbidden_patterns`** — identifier substrings you must NOT introduce (detector `AI_HINTS_FORBIDDEN_PATTERN` #27 enforces; `clad check --strict` will block)
- **`preferred_patterns`** — domain `{when, prefer, over?}` triples to follow when writing code (advisory only; no detector, but reviewers + AI agents check)
Together with `docs/conventions.md` (style observed from code) and `docs/project-context.md` (why this project exists), `ai_hints` answers **"how should I work in this project?"**. The three documents form the AI-readable policy stack:
| Tier | File | Source | Refresh by |
|---|---|---|---|
| B | `spec.yaml::project.ai_hints` | LLM via `clad init --intent` OR user-authored | manual edit; `clad sync` validates |
| B | `docs/project-context.md` | LLM via onboarding OR user-authored | `clad init`, `clad clarify` |
| C | `docs/conventions.md` | derived from code | `clad init --scan` |
When `ai_hints` conflicts with `CLAUDE.md` for cladding-self specifically, **`ai_hints` wins** (it's the project-scoped SSoT; CLAUDE.md is the meta-instruction layer).
## Reference
- External-user guide: `docs/spec-ids-multi-dev.md`
- Detector catalog: `src/stages/detectors/README.md`
- Architecture invariant: `spec/architecture.yaml` (consumed by `ARCHITECTURE_FROM_SPEC` since v0.3.13)
- AI behavior SSoT: `spec.yaml::project.ai_hints` (since v0.3.56–58, F-5b9f9f + F-00eb1a + F-32b1e0)
## cladding
**Spec is SSoT** — `spec.yaml` is authoritative; code must satisfy its
`features[]` and `acceptance_criteria`. Run `clad check --strict` before commit.
**Persona separation** — planner writes spec, reviewer audits, developer
implements; whoever authors a unit must not sign off on it (anti-self-cert).
**Feature cycle — one at a time** — One feature end-to-end before the next:
- author its shard (`acceptance_criteria` + `modules`) → implement → author tests
+ author its spec entry (`acceptance_criteria` + `modules`) → implement → author tests
in a separate context → `clad done <featureId>` (sets `status: done` only when
- `clad check --tier=pre-push --strict` is GREEN). Never author shards ahead of
+ `clad check --tier=pre-push --strict` is GREEN). Never author spec entries ahead of
their code, or hand-write `status: done`. See `docs/feature-cycle.md`.
**Hash-based IDs** — Never hand-author `F-NNN` filenames; use the `clad` CLI
(or `/cladding:init`). Model in `docs/spec-ids-multi-dev.md`.
**Drift detectors** — `clad check --strict` runs them all; don't suppress
findings — fix them or update spec.
**Speak the user's language** — when reporting to the user, translate
- cladding terms into plain words in the user's own language (a shard = a spec
- entry) — including cladding's own gate and hook messages: relay them by
+ cladding terms into plain words in the user's own language — including
+ cladding's own gate and hook messages: relay them by
meaning. Never lead with internal ids.