* ci(guidance): add check-guidance.py — guidance must reference the tree that exists Four mechanical drift classes become build failures: every repo path named by agent guidance (root AGENTS.md/CLAUDE.md, crates/** AGENTS/CLAUDE/ CONTRACT/README, .claude/rules/*.md, .claude/skills/*/SKILL.md) must resolve in the tracked tree; every rules/skills frontmatter paths: glob must match at least one tracked file (the dead-trigger class that let skills.md never fire); every crate directory appears in its family's AGENTS.md crate table (the guidance half of check-target-tree.py); and every crate has a README.md (measured 62/62, so it gates). Extraction is designed against false positives: fenced blocks, placeholder tokens, MCP method names, dated-correction (✎) lines, and 'check-guidance: path-ok' lines are not claims; resolution honors the citation forms measured on the live tree (root-relative, doc-relative, name-prefix, crate-qualified-by-context, module-relative within the citing crate). KNOWN_MISSING is a shrink-only suppression table — a row whose reference stops dangling fails the gate until deleted, and surviving rows print as warnings every run. Fails closed on unreadable files, unparseable frontmatter, broken crate discovery, and near-empty scans (floor constants). Self-test in test-check-guidance.py (23 cases, refusals first, real repository last), wired beside check-target-tree.py in code_style.yml; the test planner classifies all three paths as static-control (verified exit 0). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(guidance): consolidate crate-tier CLAUDE.md files; rename module specs to CONTRACT.md Steps 2+3 of the guidance unification (docs/reborn/guidance-conventions.md): - Rename the four Module Specs table specs CLAUDE.md -> CONTRACT.md (llm, filesystem, webui, composition), matching the identity/trust precedent. Charter gates repointed (llm module_charter, webui handlers_module_charter) and every live reference updated; pointer stubs left behind so tooling that loads CLAUDE.md still lands on the spec. - Fold the nine substantive out-of-table CLAUDE.md files: wasm, mcp, sandbox, auth, assistant, trace_commons, extension_manager become AGENTS.md-canonical (gates repointed with pinned phrases kept verbatim: the wasm_sandbox_core arch pin, mcp module_charter, auth module_charter, assistant reborn_services_module_charter); network and secrets fold into their README Invariants sections and drop the crate guidance pair entirely. - Mark with the convention's absence-claim annotation the five crate-tier lines grandfathered by check-guidance KNOWN_MISSING (llm CONTRACT.md x3, composition CONTRACT.md, hooks AGENTS.md) and mark trace_commons' prescribed tests/queue.rs mirror as prescriptive-future. - tests/CLAUDE.md: replace the retired root Current-Limitations citation with the measured ironclaw_observability description. End state: zero prose CLAUDE.md outside the Module Specs table at the crate tier (the four ironclaw_agent_loop src/tests directory guides stay, same footing as the tests-tree harness guides). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(guidance): unify the root pair — AGENTS.md canonical, CLAUDE.md adapter Step 1: root AGENTS.md (198 lines) and root CLAUDE.md (286 lines) shared zero identical lines — the forked-pair drift the guidance convention forbids at crate level, live at the root. Root AGENTS.md is now the canonical tool-neutral contract (build/run/debug commands, hard invariants including the unified extension model and the credential_name/extension_name identity rules, the Module Specs table — now uniformly CONTRACT.md and gaining the existing ironclaw_trust/CONTRACT.md row — testing discipline, tree map, discovery, change discipline; 152 lines). Root CLAUDE.md is an @AGENTS.md adapter plus the genuinely Claude-specific tail: skills/rules index, codebase-graph MCP recipes, and the REPL info!/warn! logging rule (51 lines). Cut while merging, each measured against the tree: the v1 Job State Machine (no such state machine exists under crates/), Current Limitations (stale — the observability claim no longer matches the crate), the Skills System section (.claude/rules/skills.md and the domain crate own it), Extracted Crates, the re-derivable key-traits list, and the long channel-onboarding narrative (now three lines pointing at crates/extensions/AGENTS.md and the worked slack example). Every live citation of the root pair's moved sections is repointed (crates/ routing map + README, the deslop-reborn command, types/type-placement rules, skills/common/config crate docs, a loop_host doc comment). The git-ignored .codebase-memory/artifact.json mention carries the absence-claim annotation for the check-guidance KNOWN_MISSING handoff. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(guidance): make CLAUDE.md a symlink to AGENTS.md at every tier The loader question is now measured, not assumed. Headless canary experiment with a discriminating control: a symlinked nested CLAUDE.md's target content IS injected when a file in that directory is read, an @AGENTS.md import inside a nested CLAUDE.md also expands, and a nested AGENTS.md alone is NOT read. So one uniform rule holds everywhere: wherever an AGENTS.md exists, CLAUDE.md sits beside it as a symlink — same bytes, zero maintenance, no second document to drift. 64 pointer stubs become symlinks. The four spec crates keep CONTRACT.md as canonical; their AGENTS.md routes there, so the spec stays one hop away while the working rules now auto-inject instead of costing a voluntary read. Also reconciled check-guidance.py's shrink-only KNOWN_MISSING table: all 8 rows deleted because the content pass fixed the underlying lines, and the three absence-claims the gate then surfaced carry markers. The table is empty. Caveat recorded for the convention: nested injection fires only below cwd, and appears not to fire in subagent sessions — family docs must stand alone when read deliberately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(guidance): amend the convention with measured loader mechanics and budgets The first version made crate AGENTS.md canonical and CLAUDE.md a pointer, which moved working rules out of Claude Code's auto-inject path. Records what was measured instead: subtree CLAUDE.md injects lazily, symlinks and @imports both carry content, nested AGENTS.md is not read natively, and injection does not fire in subagent sessions — so every doc must stand alone when read deliberately. Adds size budgets per tier, extends scope to .claude/rules and .claude/skills (where the worst drift was), names check-guidance.py as the enforcement with its suppression markers, warns that some guidance is test-parsed (including the heading-shadowing trap), and adds the remove/rename checklist that mirrors add. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(guidance): composition keeps a real CLAUDE.md, not a symlink The blanket symlink pass broke composition_root_embeds_no_prompt_content, and the gate is right to refuse: its ownership walks do not follow symlinks, so stepping over one would let it report clean on a subtree it never read. This crate keeps a regular pointer file, with the reason written in the file so the next person does not 'fix' the inconsistency back into a break. The uniform alias rule now has two stated exceptions: the root (real file, it carries a Claude-only tail) and composition (real file, this gate). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(guidance): enforce the CLAUDE.md alias rule; scope path-ok to the marked reference The branch's central invariant — a `CLAUDE.md -> AGENTS.md` symlink beside every AGENTS.md at the root and under crates/ — was unguarded: the audit proved a committed symlink deletion left the gate green (a working-tree deletion only tripped the accidental "cannot read guidance file" refusal). Check 5 now judges the git index (`git ls-files -s` + `cat-file`): the alias must be tracked, mode 120000, targeting exactly `AGENTS.md`. The two real-file exceptions are named rows with reasons (the root adapter's Claude-only tail; composition's symlink-refusing ownership walks), and a row that stops matching the tree fails the gate rather than lingering. Sabotage-verified on the real tree: `git rm --cached` on an alias went red naming the pair; converting one to a tracked regular file went red; restore went green (65 aliases verified). Also from the audit: - A `path-ok` marker now vouches for the one reference immediately preceding it instead of exempting its whole line — the audit slipped a fresh dangling path onto a marked line and passed. The `✎` glyph stays line-scoped by documented design. Both in-tree marker usages already sit marker-after-reference and keep working. - Document the structural blind spot: a dead reference whose first segment died with its whole tree (the v1 `src/…` monolith) reads as historical narration and cannot be flagged; only review catches it. - Re-measure the fail-closed floor comment — the shipped one claimed 174 guidance files / ~800 references / 30 globs against a tree that measures 237 / ~2070 / 38 — and add a floor for alias-site discovery. Self-test grows six cases: index-deleted alias, regular-file alias, wrong-target alias, the load-bearing root exception row, exception rows matching reality, and the marker-narrowing exploit. The `--tracked-files` override marks symlinks as `<path> -> <target>`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(guidance): repoint dead skill refs, record alias carve-outs, honest size budgets Content half of the guidance-unification audit fixes: - architecture-video SKILL.md told readers to read `src/tools/README.md` and `src/workspace/README.md` — the v1 monolith is gone (`git ls-files | grep -c '^src/'` is 0) and the gate structurally cannot flag first-segment-dead paths. Repointed at the Reborn successors: `crates/extensions/AGENTS.md` and `crates/domains/ironclaw_memory/README.md`. - guidance-conventions.md now records what only commit messages knew: the composition real-file exception beside the root one; the four sanctioned ironclaw_agent_loop sub-module CLAUDE.md guides; and the alias rule's actual scope (root + crates/**), naming the two out-of-scope AGENTS.md (docs/reborn/contracts, ironclaw_silk_decoder) instead of a "wherever" wording the tree contradicted. - Size budgets re-derived from measurement (family <=220, crate <=160) with the four crate-tier exceptions named and reasoned. The shipped <=150/<=80 numbers were exceeded by 3 family and 24 of 54 crate docs on day one, which made the budget unreadable as a signal. No document was padded or truncated to fit. - Root CLAUDE.md used the dated-correction glyph on the deliberately untracked `.codebase-memory/artifact.json` reference — suppression duty outside the glyph's documented historical-prose meaning. Swapped for `<!-- check-guidance: path-ok -->` beside the reference. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * review(7306): CodeRabbit triage — guidance gate runs for the files it governs, brace globs, honest floors, identity-column family tables, doc-truth fixes Trigger (Major, the inert-guard finding): fast-checks was gated on has_code, whose regex covers none of .claude/, the root AGENTS.md/CLAUDE.md pair, or docs/ — so a PR editing only a rule's paths: trigger skipped the gate built for exactly that change. New has_guidance output OR-s those surfaces into fast-checks only (clippy/JS lanes stay code-scoped); has_code keeps its pinned meaning. Pinned by a ws12_workflow_contracts.py row and verified by replaying representative change lists through the workflow's own extracted EREs. check-guidance.py: glob_to_regex now translates {a,b} brace alternation (nested; unmatched braces stay literal) so a legitimate crates/**/*.{rs,toml} trigger counts as live instead of being reported dead; MIN_RULE_GLOBS 1->20 and MIN_ALIAS_PAIRS 10->40 (~half of measured 38/65, so a degraded parser refuses instead of passing); family-table coverage now requires the crate in a row's identity (first) column — an incidental mention in another row's prose no longer counts (measured 0 regressions on the live tree). Self-tests: +3 (brace trigger end-to-end, duplicate KNOWN_MISSING rows, identity-column regression) and the real-repository case documents its deliberate git coupling. Floors sabotage-verified. Doc truth, measured against code: composition CONTRACT — WS stream shares SseCapacity (stream_events_ws try_acquire, pinned test) replacing 'No WS surface to bound', webui_v2_app returns Result<Router, WebuiServeError>; llm CONTRACT — the circuit breaker wraps failover (apply_decorator_chain order), not the reverse; filesystem CONTRACT — dependency rule now names the real manifest set (+libsql_runtime, +observability); extension_manager AGENTS — the loops layer flip landed (layer = "loops"); four stale 'has no CLAUDE.md' claims updated for the new symlink aliases (config, common, event_store x2); root AGENTS — clippy line gains -- -D warnings (CI denies warnings; unflagged clippy exits 0 with them) and the error bullet routes to .claude/rules/error-handling.md; assistant/webui validation sections document the real lane structure (self-dev-dep unifies test-support on, so the missing shape is the no-dev-deps production lane, the #7119 class). Stale pre-family paths in .rs prose: 594 crates/ironclaw_* citations measured; 130 sit in comments, of which 106 repointed to their family homes (every rewritten path verified to resolve), 10 of those needed deeper repoints (files that moved crates: capability_host.rs, channel_pairing.rs, approval_store_contract.rs, secret_store.rs, loop_contracts instruction_bundle.rs, assistant communication_context.rs, loop_host surface_disclosure.rs, resolver_tests.rs), 24 left deliberately (flat- spelling narration about the family move itself, deleted-crate history, synthetic fixture names, and two #6945-class pointers whose target is gone at every spelling). 464 string-literal citations left: the specificity test resolves legacy spellings through the crate inventory by design. Triage of PR #7306 review comments; no gate weakened, both alias exceptions preserved. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * review(7306): drop the one comment repoint in tests/e2e_trace_runtime_policy_org_ceiling_yolo.rs reborn_pr_test_plan.py has no mapping for this root test (it matches neither the tests/reborn_* partition inventory nor any other arm), so ANY PR touching it fails 'Detect Reborn test scope' — a pre-existing planner gap, confirmed against origin/main with a one-file changed list. The stale crates/ironclaw_runtime_policy comment path inside it stays until the planner learns the file; noted for follow-up rather than smuggling planner surgery into a review-triage branch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(contributing): stop annotating the loose iteration clippy line as 'zero warnings' Same class as the root AGENTS.md fix: unflagged clippy exits 0 with warnings, so the annotation overclaimed. CONTRIBUTING's two-tier design (loose iteration block, then a stricter pre-PR block that already carries -- -D warnings) is deliberate and stays; only the claim is aligned. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: recount the frozen WebUI route table after the #7306 merge — 93 -> 97 #7236 (main) added the four operator inspector routes without bumping the stated counts; re-derived on the merged tree: rg -c 'pub const WEBUI_V2_ROUTE_' crates/product/ironclaw_webui/src/webui_v2/descriptors.rs -> 97. Updates the two live claims (webui README, PROPOSAL SS6.9.4 with its strike-through recount convention); historical/superseded 92-row mentions stay as written. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ci): the code-style roll-up must judge fast-checks for guidance-only PRs The has_guidance trigger made fast-checks RUN for .claude/ and root-pair changes, but the roll-up's has_code==false branch exits 0 before it ever reads fast-checks' result — so check-guidance.py could fail and Code Style would still report success. The gate ran and could never block: exactly the inert-guard shape this change exists to remove, reintroduced one layer up. Fixed the way main's docs-publication gate already does it — judged before the early exit, with the reason in a comment. Sabotage-verified: has_guidance=true plus fast-checks=failure now exits 1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2.4 KiB
IronClaw — Claude Code adapter
@AGENTS.md
Everything above (from AGENTS.md) is the canonical, tool-neutral contract.
The rest of this file is Claude-specific.
Skills and rules
- Project skills live in
.claude/skills/— start fromironclaw-reborn-orientation; usereborn-featurefor cross-layer product work,reborn-extension-surfacesfor integrations,ironclaw-reborn-testingfor test tiers,ironclaw-reborn-architecture-reviewfor boundary changes, andironclaw-reborn-skill-maintainerbefore editing any guidance file. - Path-scoped rules in
.claude/rules/*.mdload automatically when you read matching files — they are canonical for their topics (testing, database, types, cargo-features, review discipline, …); do not restate them here.
Codebase knowledge graph (MCP)
The codebase-memory MCP server indexes crates/ into a knowledge graph;
prefer it over Grep for code structure (cross-crate call chains are
invisible to text search). .codebase-memory/graph.db.zst is the committed
bootstrap snapshot; local databases and
.codebase-memory/artifact.json stay
git-ignored (per-environment state, deliberately untracked). Check
freshness first: bash scripts/codebase-graph.sh status.
- Missing →
index_repository(repo_path=".", persistence=true)once. - Stale →
detect_changes(since="<indexed-commit>"), or re-runindex_repositoryto refresh the shared snapshot. - Where is a symbol →
search_graph(name_pattern=…), thenget_code_snippet(qualified_name=…). - Who calls X / what X calls →
trace_path(function_name=…, mode="calls"); value flow →mode="data_flow"; cross-crate feature path →mode="cross_service". - Structure of an area →
get_architecture(…); graph-augmented text search →search_code(pattern=…); arbitrary queries →query_graph(<Cypher>).
The graph is a point-in-time index — verify anything it asserts against live
code before acting. Grep/Glob/Read remain correct for text, config, and
non-code files. For narrative what/why orientation, read the relevant
openwiki/ page (generated — never hand-edit).
REPL/TUI logging rule
info! and warn! output appears in the REPL and corrupts the terminal UI.
Use debug! for internal diagnostics (trace analysis, reflection results,
engine internals); reserve info! for user-facing status the REPL
intentionally renders. Background tasks must NEVER use info!.