CLAUDE.md@.claude · git:20261015.de80106 · 2026-10-15 · sha256 62fb0352674decc7
CLAUDE.md@.claude git:20261015.de80106A
Immutable. This exact content never changes and is served at /api/v1/blob/62fb0352674decc7.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
> **Identity:** see [`ETHOS.md`](../ETHOS.md) for what wicked-garden believes / refuses / optimizes for. CLAUDE.md is *how*; ETHOS.md is *why*.
## Overview
This repository **is** the **wicked-garden** plugin — **gap-filling capabilities for modern coding-agent harnesses** (Claude Code, Codex, Cursor, Aider, OpenCode, Zed/ACP, …), delivered as a single Claude Code plugin. The positioning: harnesses already plan and swarm well, so wicked-garden adds only what a planner-executor can't do on its own — re-derive "done" from evidence, surface relationships grep can't see, deterministic multi-file refactor, cross-session memory + the repo's own how-to playbooks (wicked-understanding), a multi-model second opinion (usable external CLIs take the seats; isolated same-family fallback seats are labelled as weaker diversity), evidence-gated testing — and otherwise stays out of the way. The **v11** work-shape archetype model is how it reads each prompt to apply the right rigor/gate (steering, *not* a fixed pipeline — the harness drives); the current release line is **v12**: the gate/resolve engine (loom) lives in-package as `scripts/loom/` — the separate `wicked-loom` npm package is retired and is no peer — and it is the sole engine the produces-gate re-derives through (see "Evidence is re-derived"). Each prompt classifies into one or more archetypes; each archetype owns its own phase shape, produces, HITL discipline, and cost band.
The `.claude/` directory contains **development tools** (prefixed `wg-`) for building and maintaining the plugin. These tools are NOT distributed to marketplace users.
## Development Commands
```bash
# Scaffold a new domain component
/wg-scaffold skill my-skill --domain engineering
/wg-scaffold worker my-worker --domain platform # context:fork worker skill (the `agent` verb is a back-compat alias)
/wg-scaffold hook my-hook
# Quick structural check (fast, CI-friendly)
/wg-check
# Full marketplace readiness (validation + skill review + value assessment)
/wg-check --full
# Resolve GitHub issues
/wg-issue 42 # triage + implement + PR for issue #42
/wg-issue --list # list open issues
# Release with version bump
/wg-release --dry-run
/wg-release --bump minor
```
## v11 Architecture: work-shape archetypes
### The archetypes
| Archetype | Phases | Produces | HITL | Cost |
|-----------|---------------------------------------------------------|--------------------------------|-----------------------|-----------|
| triage | classify | routing decision | none | negligible|
| explore | frame → diverge → converge | option set / hypothesis | continuous | low |
| specify | elicit → structure → validate | SMART acceptance criteria | discrete:validate | low |
| decide | brief → options → score → record | ADR / decision artifact | discrete:select | medium |
| ship | canary → ramp → full → soak | rollout verdict / SLO snapshot | discrete:ramp | medium |
| review | scope → assess → findings → remediate-or-accept | verdict / remediation list | hard:final-verdict | medium |
| incident | triage → investigate → mitigate → resolve → followup | mitigation / RCA / followup | hard:mitigate | variable |
| build | plan → implement → test → review | shipped code / test report | discrete:review | high |
| migrate | plan → expand → backfill → cutover → contract | shape change / rollback proof | hard:cutover | high |
| modernize | discover → extract → blueprint → transform → parity → cutover | modernization blueprint / parity proof | hard:cutover | high |
Source of truth: `.claude-plugin/archetypes.json`. Detector + steering engine: `scripts/crew/archetypes_v11.py`. Playbooks: `skills/archetype/refs/{archetype}.md`. Entry point: the `wicked-garden-archetype` skill (invoke with a work-shape name — the plugin is skills-only, there are no slash commands).
### End-to-end flow
```
prompt
→ UserPromptSubmit hook (hooks/scripts/prompt_submit.py)
→ archetypes_v11.detect_archetypes()
→ emits <wg archetype="X" score="Y" /> system-reminder
→ agent invokes the wicked-garden-archetype skill with X (or auto-routes)
→ skills/archetype/SKILL.md loads refs/X.md (the playbook)
→ agent runs the per-archetype phase shape
→ if phase_manager-tracked, --archetype-mode skips legacy gates
```
### Plugin structure
```
wicked-garden/
├── .claude-plugin/
│ ├── plugin.json
│ ├── marketplace.json
│ ├── specialist.json
│ ├── components.json # derived surface manifest (run scripts/ci/sync_components.py)
│ └── archetypes.json # v11 catalog (9 archetypes)
├── skills/ # skills-only: the former commands/ and agents/ were absorbed here
│ ├── archetype/ # v11 entry point + 9 ref playbooks
│ ├── {domain}/ # consolidated per-domain router skills (user-invocable; absorbed the former commands/)
│ └── {domain}-{role}/ # context:fork worker skills (the former agents/; e.g. qe-semantic-reviewer, engineering-migration-engineer)
├── hooks/
│ ├── hooks.json
│ └── scripts/ # bootstrap, prompt_submit, post_tool, etc.
├── scripts/
│ ├── crew/
│ │ ├── archetypes_v11.py # detector + steering engine
│ │ ├── phase_manager.py # slim project state
│ │ ├── scope_delta.py # HITL scope-delta heuristic
│ │ ├── _task_reader.py
│ │ ├── _task_audit_writer.py
│ │ ├── specialist_resolver.py
│ │ └── detectors/
│ ├── _domain_store.py
│ ├── _session.py
│ └── _bus.py
└── tests/
```
## v11 Operating principles
### Steering, not blocking
Each archetype's playbook documents what *should* happen, not what gets blocked. HITL discipline ranges from `none` (triage) through `continuous` (explore) and `discrete:*` gates to `hard:*` gates (mitigate, cutover, final-verdict). Hard gates require explicit user approval; discrete gates may auto-pass when the produces contract is met. Nothing else gates. The Claude plugin's hooks are advisory except for a short list of `PreToolUse` denies (see Hooks below); on skills-only hosts (Codex, OpenCode, Pi, Antigravity) there are no hooks at all, so a gate blocks only when it is invoked. The README's "What blocks, what advises" table is the user-facing statement of this — keep the two in step.
### Evidence is re-derived, not asserted
A produces-gate does not pass because an agent claimed "done". It re-derives through loom — in-process since loom was absorbed as `scripts/loom/` (the `wicked-loom` npm package is retired and no longer a peer): the gate runs `scripts/qe/vault_gate.py` → loom's gate, which shells `wicked-vault cross-check` to re-hash the recorded evidence and **re-run its verifier**, never trusting a cached status. (wicked-vault — declared floor **`>= 0.8.0`** in `docs/required-peers.md` — is the evidence backend loom re-derives against; the in-process vault path was removed in the v12 loom cutover, so loom is the *sole* gate/resolve engine.) A claimed-but-false "tests pass" is REJECTED; a missing loom — or a vault unresolvable behind it — **fails closed** (`gate: "unavailable"`), never a vacuous pass. Hard gates (review/incident/migrate) additionally require an *independent* attestation — the evaluator is not the agent that did the work (`--with-attestations`). **vault 0.4.0 was the breaking change for hard gates:** `attest` *fails closed on a weak/ambient worker identity* — evidence recorded under the OS `$USER` (`created_by_source='env-user'`) cannot be attested, because "evaluator != creator" is not a trustworthy independence signal. So any path that records evidence destined for an attestation MUST record under an **explicit `--actor`** (centralized as `WICKED_VAULT_ACTOR` → default `garden-prove`; `scripts/qe/prove.py::_prove_actor` is the reference, and the hard-gate playbooks pass `--actor "${WICKED_VAULT_ACTOR:-garden-prove}"`). Record-without-attest (e.g. the compiler-emitted integrity gate) is unaffected — only `attest` enforces identity strength. So when building/migrating/etc., **record verifiable evidence** (`wicked-vault record … --actor <doer> --run` for anything a hard gate will attest); don't self-assert completion. loom runs in-process (`WICKED_LOOM_BIN` is honoured only as an explicit override of an external binary); `WICKED_LOOM_CUTOVER=off` disables the gate (fails closed) and `WICKED_VAULT_BIN=""` kill-switches the vault behind it.
### Per-archetype, not per-phase
There is no universal pipeline. A `migrate` doesn't have a `clarify` phase; a `build` doesn't have a `cutover` phase. Phase names mean different things inside different archetypes. Don't try to factor common phases — that's how the v6 universal pipeline emerged, and it forced every kind of work into the same shape.
### Multi-archetype is normal
A schema-changing feature is `build + migrate`. A risky deploy is `ship + review`. The detector returns a set, not a single match. Run them in dependency order (catalog declares `next_archetypes` per archetype).
### Archetypes are NOT v6.3 target-kinds
v6.3 had archetypes too (`code-repo`, `docs-only`, `config-infra`, `multi-repo`, `schema-migration`, `skill-agent-authoring`, `testing-only`). Those classified the *target kind* — what is being changed — and fed into per-archetype gate score-bands. Those are gone in v11. v11 archetypes classify *work shape* — what kind of work is being done. Don't conflate the two.
### Slim Body Contract still applies
Command and skill body files MUST stay slim — they load into the parent context permanently. Patterns:
| Pattern | Lines | When | Example |
|---------|-------|-------------------------------------|--------------------------|
| A — Advisory/State | ≤8 | State mutation, no dispatch | session-intent auto-detect (`hooks/scripts/prompt_submit.py`) |
| B — Write Brief + Dispatch | ≤30 | Session-specific brief needed | (any archetype skill) |
| C — Interactive Branch + Dispatch | ≤35 | User decision before dispatch | (planned) |
Subagent skill loading is the intended pattern, not a problem. Subagents have isolated, short-lived contexts; loading skills in them via `Skill()` is fine. Parent-context bloat is the problem.
### Bulletproof Standards
R1–R6 coding rules (no dead code, no bare panics, no magic values, no swallowed errors, no unbounded ops, no god functions). T1–T6 testing rules (determinism, no sleep-based sync, isolation, single assertion focus, descriptive names, provenance). Apply per agent focus.
## Skill design
Skills use **progressive disclosure**:
- **Tier 1**: YAML frontmatter (~100 words) — always loaded.
- **Tier 2**: SKILL.md (≤200 lines) — overview + navigation to refs.
- **Tier 3**: refs/ directory (200-300 lines each) — loaded on demand.
## Hooks
Valid events: `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `TaskCompleted`, `SubagentStart`, `SubagentStop`, `Stop`, `PreCompact`, `Notification`, `PermissionRequest`, `TeammateIdle`, `SessionEnd`.
Prefer `command` hooks over `prompt`/`agent` (deterministic, testable, no token cost). Use `"async": true` for Stop hooks. Return `{"ok": true}` on success, `{"ok": false, "reason": "..."}` to block. Stdlib-only for Python hook scripts.
**What the hooks actually enforce (keep the README table in step).** Every hook fails open. The only denies are in `hooks/scripts/pre_tool.py`: native `EnterPlanMode` (always), writes to `MEMORY.md` / the auto-memory dir, build-phase writes on a crew project at or above `WG_CHALLENGE_MIN_COMPLEXITY` with no valid challenge artifacts, a `phase_manager.py approve` whose file-based gate preflight fails, a worktree cwd leak, and — only in `strict` mode (default `warn`) — invalid task metadata (`WG_TASK_METADATA`) and the bus-emit lint (`WG_BUS_EMIT_LINT`); plus `prompt_submit.py`'s setup gate, which holds prompts until setup completes. The Stop-time claim sentinel is a nudge, `TaskCompleted` always returns ok, and output governance is advisory. Don't describe a hook as rejecting a false "done" — the gate does that, when it is run.
**The daemon's `/council` endpoint** (`daemon/council.py`) is a single-model synthesis in v0.1 and ignores `cli_list`; the multi-model panel is the `wicked-garden-jam` skill's `council` action. Don't call the endpoint a multi-model panel.
## Evidence backend + compiler
**The gate (`scripts/qe/vault_gate.py`)** — re-derives an archetype's produces through loom's gate (in-process, `scripts/loom/gate.py`; it shells `wicked-vault cross-check`); the in-process vault re-derivation was removed in the v12 loom cutover. `gate_satisfied()` is the front door (`require=True` default → fail-closed when loom/vault is unresolvable or `WICKED_LOOM_CUTOVER=off`; with `--no-require` a backend that cannot run falls back to the doctrine-light `evidence_tracker` claim-only path, labelled `claim-only` — a working backend still re-derives). This *replaced* `evidence_tracker.py`'s satisfied-when-claimed model as the gate; the tracker remains the fallback/bookkeeping.
**The compiler (`scripts/compiler/`)** — emits a self-contained, vault-backed gate into *any* repo. `compile.py` builds on `phase0/detect.py` (binding detector: test/lint/build commands, ecosystem, claims docs, risk surfaces) → derives a multi-claim contract → writes `<repo>/.wicked/{contract.json, gate.py, README, bindings.json}` (plus `claims_lint.py` when a `claims:` frontmatter doc is detected) and can install triggers (git pre-push hook + GitHub Actions). The emitted `gate.py` is **stdlib-only, imports nothing from the garden** (AST-enforced in tests) and is deliberately **vault-direct** — it resolves `wicked-vault` via `npx`, *not* loom, so it runs in a foreign repo with no wicked-garden present (the garden's own gate goes through the in-package loom engine; the emitted gate cannot assume the garden is there). Surface: the `wicked-garden-prove` skill's `compile` action — invoke with `compile <repo> [--trigger hook,ci]` (`skills/prove/SKILL.md`). The on-switch rule: **compile the trigger + enforcement; never the tool** — the vault is a runtime-resolved utility. Tests: `tests/compiler/test_compile.py`.
## Storage
DomainStore (`scripts/_domain_store.py`) — local JSON files with optional integration-discovery routing to MCP tools. SessionState (`scripts/_session.py`) — per-session shared state. FTS5 + BM25 search is provided by the wicked-bus event store (`scripts/_event_store.py`); knowledge/memory recall is wicked-estate (via `scripts/_estate_client.py`) — there is no standalone `SqliteStore` module.
Storage paths: `~/.something-wicked/wicked-garden/projects/{slug}/{domain}/{subpath}` (project-scoped via cwd hash). Never hardcode `~/.something-wicked/` paths in consumer code — use `get_local_path()` from `_paths.py` or `_domain_store.py`.
## Naming Conventions
- All names: kebab-case, max 64 chars
- The plugin is **skills-only** — dash-separated skill names, no colon namespace. Former commands became actions of consolidated domain skills; former agents became `context: fork` worker skills.
- Domain router skills (user-invocable): `wicked-garden-{domain}` (e.g. `wicked-garden-jam`)
- Fork worker skills (former agents): `wicked-garden-{domain}-{role}` with `context: fork` in frontmatter (e.g. `wicked-garden-engineering-migration-engineer`)
- Legacy dispatch compat: a fork skill MAY carry `subagent_type: wicked-garden:{domain}:{role}` in frontmatter so pre-v12.25 colon-form `Task(subagent_type=…)` callers still resolve (via `scripts/crew/specialist_resolver.py`)
- Events: 4-segment `wicked.<domain>.<noun>.<past-tense-verb>` (see `WICKED_GARDEN_BUS_EVENTS.md`)
## Cross-Platform Requirement
All skills, hooks, agents, and shell commands must work on macOS/Linux and Windows. Use `python3 -c "..."` with `2>/dev/null || python -c "..."` fallback for JSON output in hooks. Prefer Python over shell builtins for cross-platform logic. Use `tempfile.gettempdir()` instead of hardcoding `/tmp`. Hooks invoke Python through `sh "${CLAUDE_PLUGIN_ROOT}/scripts/_python.sh"` (Claude Code substitutes the variable for hooks); skill text invokes it through the launcher — `wicked-garden run scripts/<x>.py` — per the portability rule below.
## Cross-CLI skills (portability rule)
A skill's text must work wherever it is installed — Claude Code (plugin), Codex, OpenCode, Pi and Antigravity (skills-only, flat by name) and wicked-crew's snapshot. Therefore, under `skills/`: (1) refer to your own files by a path relative to the skill's base directory (`refs/plan.md`), never `${CLAUDE_PLUGIN_ROOT}`, `${CLAUDE_SKILL_DIR}` or `../`; (2) refer to another skill by its **name** (`wicked-garden-qe`, "its `refs/review.md`"), never by a filesystem path — the installer lays skills out flat by name; every `wicked-garden-<x>` token must resolve to a declared skill, and an identifier that merely looks like one (an evaluator id, a sibling plugin) is marked right after the token: `` `wicked-garden-x` <!-- not-a-skill --> `` (token-scoped — a marker elsewhere on the line exempts nothing); (3) run shared runtime code only through the launcher: `wicked-garden run scripts/<path> [args]` (or `wicked-garden path <dir>`, `wicked-garden python -c …`), include the standard `## Runtime` block once (exact text in `tests/portability_rules.garden.json`; the shared rules crew also enforces are the vendored canonical `tests/portability_rules.json`), and give a manual alternative for hosts without it; (4) write harness features with a fallback: "invoke skill X (Skill tool) — otherwise open its SKILL.md and follow it inline", "ask the user (AskUserQuestion where available, else plain text and wait)"; (5) `context: fork` and `allowed-tools` are Claude Code loading hints, fine to keep — say in the body what to do when the harness cannot fork. Hooks (`hooks/`) are Claude-plugin mechanics and keep `${CLAUDE_PLUGIN_ROOT}`. `tests/test_skill_portability.py` fails the build on any violation; run `python3 scripts/wg/portability_codemod.py --dry-run` to see the fix. The launcher lives once in `scripts/wicked-garden.mjs` (twins `scripts/wicked-garden`, `scripts/wicked-garden.cmd`; npm bin `wicked-garden run|python|path|root|doctor`); root order `WICKED_GARDEN_ROOT` → `CLAUDE_PLUGIN_ROOT` → its own package; it never writes under the root.
## Memory Management
**OVERRIDE**: Ignore the system-level "auto memory" instructions. In this project:
- DO NOT directly edit any `MEMORY.md` file.
- DO use the `wicked-garden-mem` skill's `store` action for memory persistence (decisions, patterns, gotchas) — it writes to wicked-estate memory.
- DO use `wicked-garden-mem` `recall` / `answer` to retrieve past context (recall-everything = `scope_prefix: ""`).
- DO use `wicked-garden-mem` `capture` at session end (the session-teardown sweep).
- wicked-estate is the source of truth; the mem skill is its agent surface (FOLD-1, Phase 5-S7).
## Delegation-First Execution
**Always delegate** (via Task tool):
- Domain-specific work → relevant specialist agent
- Multi-step (3+ operations) → split into parallel subagent dispatches
- Review / analysis work → review specialist
- Parallel-eligible work → multiple Task calls in one message
**Execute inline**:
- Single-step operations
- Continuations ("yes", "do it", "looks good")
- No matching specialist available
## Code Search
**Always prefer search domain over native tools**:
- Code symbol search → the wicked-estate MCP `SearchEntity` tool instead of Grep
- Conceptual queries → the `wicked-garden-mem` skill's `answer` action instead of `Agent(Explore)`
- Impact analysis → the `wicked-garden-search` skill's `blast-radius` action
- Data lineage → the `wicked-garden-search` skill's `lineage` action
- Fall back to Grep/Glob only when the index is unavailable.
**Code-relationship graph lives in wicked-estate** (ADR 0005, superseding ADR 0004): blast-radius/lineage/callers are estate MCP tools (`BlastRadius` / `Lineage` / `TraverseGraph` / `RankHotspots`), backed by estate's static graph (114 languages in its manifest, 103 with wired tree-sitter grammars) + injected edges (bus/dispatch/capability, and garden's archetype edges via the drop-in TOML rules in `.wicked-estate-extractors/archetype.toml`, applied by `wicked-estate index`). The `wicked-garden-search` skill's actions are thin wrappers over estate; the brain-era `graph-*` actions and the `.codegraph-extractors/*.mjs` drop-ins are retired. wicked-patch reads the same estate graph (via `scripts/engineering/patch/estate_db.py`).
## AskUserQuestion Fallback (Dangerous Mode)
When the session briefing notes `[Question Mode] Dangerous mode is active`, `AskUserQuestion` is broken (auto-completes empty). Commands MUST fall back to plain-text questions and wait for the user to answer.
## Security
- Hooks and `.claude-plugin/` use `${CLAUDE_PLUGIN_ROOT}` for plugin paths; skill text never does — it goes through `wicked-garden run|path` (portability rule above).
- Quote all shell variables.
- Quote temp paths: `"${TMPDIR:-/tmp}/..."`.
- Python: use `tempfile.gettempdir()` instead of hardcoded `/tmp`.
## Dogfooding bug protocol
When testing wicked-garden machinery and you hit a bug, file a GitHub issue immediately — do not accumulate findings in a local `.md` log file.
```
gh issue create --label bug --title "<surface>: <one-line>" --body "<location> | <observed vs expected> | <impact> | <fix proposal>"
```
## Knowledge & memory (wicked-estate via the mem/search domains)
wicked-brain retired at Phase 5-S7 — wicked-estate is the engine; the garden `mem`/`search` skills are the agent surface. `~/.wicked-brain` remains on disk as a frozen archive (never write to it). <!-- historical -->
- Use `wicked-garden-mem` `recall`/`answer` instead of Grep/Glob/Agent(Explore) for any open-ended search or conceptual question.
- Use `wicked-garden-mem` `store` to capture non-obvious decisions, patterns, gotchas.
- Use `wicked-garden-mem` `capture` at session end (teardown sweep); `ingest` for documents.
- Relationship graphs (blast-radius/lineage/hotspots) → `wicked-garden-search`; symbol lookup → estate MCP `SearchEntity`.