CLAUDE.md · git:20260716.1d599e1 · 2026-07-16 · sha256 16212c1749e6005d

CLAUDE.md git:20260716.1d599e1A

Immutable. This exact content is served forever at /api/v1/blob/16212c1749e6005d.

# 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
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
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
meaning. Never lead with internal ids.