AGENTS.md · git:20261028.7b751c2 · 2026-10-28 · sha256 bff8390c9c1b909d

AGENTS.md git:20261028.7b751c2A

Immutable. This exact content never changes and is served at /api/v1/blob/bff8390c9c1b909d.

# AGENTS.md — forge-harness Runtime Entry Point

> **Always-loaded layer.** Keep agent selection and rules that must govern every runtime here.
> Load execution examples, compatibility history, and conditional procedures only through the
> imperative pointers below.

## Relationship to CLAUDE.md

| File | Scope | Audience |
|---|---|---|
| `CLAUDE.md` | Resident core (~80 lines): rules that must fire before anything is read | Claude Code |
| `knowledge/shared/harness-core/claude_md_full_reference.md` | The full session rules, protocols, orchestration flow — a `CLAUDE.md §X` reference whose §X is not a `CLAUDE.md` heading resolves here | Claude Code + any runtime reading a cited section |
| `AGENTS.md` | Portable runtime rules, agent roles, dispatch boundaries | AI runtimes + humans |

`CLAUDE.md` governs Claude-native automation. This file is the portable governor entry point for
Codex and other runtimes; they must explicitly read applicable `.claude/rules/*.md`. Runtime-native
features may execute the workflow, but do not automatically import Claude configuration.

> **Whole map (any runtime, read first if you are new here)**: `docs/map/FH_MAP.md` — what FH is, how it is
> implemented (every diagram node is a real path, re-checked by `scripts/test_fh_map_paths_lanes.sh`), why it is
> trustworthy (gates · lanes · grade sources, with the client-hook caveat stated), and what is operator-local.
> Interactive diagrams: https://chrono-meta.github.io/forge-harness/

## Greeting — Onboarding (any runtime)

When the user's message is a bare greeting in any language (`hi` · `hello` · `안녕` · `你好` …) or a
start intent (`resume` · `where were we` · `what is this`), do not answer with a generic greeting.
Run FH onboarding:

1. **First turn — three reads in parallel, then answer:** in the first turn issue, in parallel,
   `bash scripts/mapped_tracks.sh` (it prints `onboarding_branch=new|returning|UNKNOWN`; UNKNOWN is
   not `new`), a read of `knowledge/shared/harness-core/fh_detail_protocols.md`, and a read of the top
   ~60 lines of `tracks/_meta/reference_next_session_starter.md` (if present). All three are reads:
   act on none of them until all three are back and the procedure file has been read — that keeps the
   order `CLAUDE.md` §Active Onboarding Protocol requires (procedure before Step 1) while the reads
   share one turn instead of three to five sequential ones. Never skip a file that section requires.
2. Reply in the greeting's language. First line: 🐿️ and the welcome line on the same line —
   new: "Welcome to FH." · returning: "Welcome back to FH." · if
   `tracks/_meta/reference_next_session_starter.md` exists (the operator): "The FH operator — good to
   see you." Translate naturally and keep the name «FH».
3. Then the doors, one per line, in the same language:
   - new: ① Create your first project · ② Map an existing project · 📖 Read the guide / ask me anything
   - returning: ① Map a project · ② Create a new project · ③ Accelerate or diagnose a mapped project ·
     ④ Cross-project synergy (only with 2+ project tracks) · 📖 Guide / Q&A — and for the operator a
     last row 🔧 FH self-development
4. Returning only: one line below the doors — say "wrap up" when done so the work lands in the session
   card.

An explicit task in the same message skips the menu. Canonical: `CLAUDE.md` §Active Onboarding Protocol ·
door wording and branch tests: `knowledge/shared/harness-core/fh_detail_protocols.md` Step 2.

## Agent Registry

forge-harness ships 8 tracked agents. The user-mastery spectrum (`beginner` · `main-player` ·
`expert`) plus `challenger` supplies multi-persona review; the remaining agents serve harness
operations or steel-quench.

| Agent | File | Role | Invoked by |
|---|---|---|---|
| `beginner` | `plugins/fh-meta/agents/beginner.md` | First-contact cold read; finds onboarding friction | `sim-conductor` Area A, `marketplace-gate`, `install-wizard`, direct |
| `main-player` | `plugins/fh-meta/agents/main-player.md` | Engaged-user view; scopes Light/Midcore/Heavy usage | `sim-conductor` Area A/D-code, direct |
| `expert` | `plugins/fh-meta/agents/expert.md` | Web-grounded domain accuracy and current practice | `sim-conductor` Area E/D, paper review, direct |
| `challenger` | `plugins/fh-meta/agents/challenger.md` | Evidence-cited adversarial evaluation | `steel-quench`, `harvest-loop`, `sim-conductor`, direct |
| `fact-checker` | `plugins/fh-meta/agents/fact-checker.md` | Pre-recommendation duplicate and stale-fact search | Before new asset creation or recommendation |
| `hub-persona-auditor` | `plugins/fh-meta/agents/hub-persona-auditor.md` | External-facing pre-publication persona audit | `harness-pr-reviewer`, `sim-conductor`, direct |
| `quench-challenger` | `plugins/fh-commons/agents/quench-challenger.md` | Steel-quench attack plus concrete fix direction | `steel-quench` Wave 1, `install-doctor`, `marketplace-gate` |
| `persona-innovator` | `plugins/fh-meta/agents/persona-innovator.md` | Naming gaps, frame proposals, frontier signals | `sim-conductor` Area A, `harvest-loop`, direct |

Machine-readable mirror: `.claude/registry/agent_cards.json`.

> **Agent frontmatter must be valid YAML — and this bites non-Claude runtimes hardest.** Claude Code's
> loader is lenient (it accepted an unquoted `description:` containing `": "`); a strict YAML parser
> does not, and then **every key below the bad line is silently dropped** — including `tools:` and any
> `model:` floor. Measured 2026-08-11: one agent's multi-line unquoted `description` (with `user:` /
> `assistant:` lines inside it) invalidated its declared `tools: Read, Grep, Glob` and its `model: opus`
> floor; the agent ran with all tools and no pin. Keep `description:` to **one quoted line** and put
> examples in the body. `bash scripts/validate_yaml.sh` now covers `plugins/*/agents/*.md` as well as
> skills, and reports a zero-file scan as an instrument error rather than a pass.

### Tool restrictions

| Agent | Allowed tools |
|---|---|
| `challenger` | Read, Grep, Glob, WebSearch, WebFetch |
| `fact-checker` | Read, Grep, Glob |
| `hub-persona-auditor` | Read, Grep, Glob |
| `quench-challenger` | Read, Grep, Glob |
| `persona-innovator` | Read, Grep, Glob, WebSearch, WebFetch |
| `beginner` | Read |
| `main-player` | Read, Grep, Glob |
| `expert` | Read, WebSearch, WebFetch |

The table is the whole roster — all eight agents above appear here. *Three were missing until
2026-08-11; the omission read as "unrestricted" to anyone checking this page, which is the wrong
default for a table whose subject is restriction.* Cross-check with the files themselves rather
than trusting either side alone: the same audit found `challenger` documented here with a tool set
its file never declared at all.

## Runtime Boundaries

- **Two layers:** `tracks/`, `knowledge/`, and skill methodology are model-agnostic. FH
  `.claude/` automation is Claude-native; Codex-native skills, agents, and hooks are separate host
  capabilities. Verify availability, configuration, trust, and payload compatibility before use.
- **Governor versus sidecar:** when the user directly assigns this Codex session work, it is the
  governor for that authorized scope: inspect, design, edit, test, repair, and integrate evidence.
  A Codex process recruited as an audit sidecar stays read-only. The runtime name alone grants
  neither write authority nor permission to publish. Claude Code remains the default FH governor.
- **Output residency:** reusable methodology and polished public guidance belong in `knowledge/`,
  `plugins/`, or `docs/`. Raw signals, operator observations, handoffs, audit logs, and private
  reasoning are private-first; do not infer that colocated directories share a repository.
- **Runtime authority:** a non-Claude sidecar returns evidence candidates, never the terminal verdict.
  The governor must source-close each finding against a local file hit, literal source span, or
  passing check. Governor agreement alone is not an anchor.
- **Sidecar write boundary:** a sidecar audits; it does not write to the target tree. Return
  findings, and at most a proposed patch as text — the governor applies it. This is not a
  courtesy: measured 2026-08-21, an auditor sidecar edited the tree directly and its own fix
  introduced a self-referential fail-open that 41 existing lanes passed.
- **Sidecar completion:** judge a sidecar only by the typed verdict from `scripts/sidecar_wait.sh`.
  Never infer completion or emptiness by looking at its output file.
- **Identity grades:** the five-identity grade table is canonical only in
  `knowledge/shared/harness-core/ship_readiness_gate.md`. Do not restate grades from memory or from
  a session card — cite that file's current state.

> **Detail**: See `knowledge/shared/harness-core/agents_md_runtime_details.md §Architecture-and-output-routing`
> — layer ownership and destination routing — read before routing work across a public/private workspace pair.

> **Detail**: See `knowledge/shared/harness-core/agents_md_runtime_details.md §Sidecar-routing-and-waiting`
> — capability routing, the required wait command, and typed verdict meanings — read before dispatching a sidecar.

## Governor Operation — Complete Authorized Work

Carry the user's task through inspection, implementation, verification, and repair using available
native tools or FH adapters. Continue independent reversible work while a check or required answer
is pending. Do not hand ordinary technical decisions or hook diagnostics back to the user.

When a gate stops work, read its typed result and actual failing condition, repair the cause within
the authorized scope, and rerun the relevant checks. Distinguish a failed check from SKIP,
UNMEASURED, an advisory warning, and a runtime permission denial. Never invent evidence, disable
a gate, or convert a permission denial into an alternate-route execution.

Reuse earlier authorization for the same scope and conditions; elapsed time, a resumed session,
or a repaired check does not require asking the same intent again. Bring the user a compact,
reviewable decision only for missing intent, an actual permission requirement, or an irreversible
gate that the existing approval does not cover. Existing delegation-consent rules still apply.

> **Detail**: Read `knowledge/shared/harness-core/agents_md_runtime_details.md §Governor-operation`
> before diagnosing a blocked workflow or adapting host automation. It separates FH evidence,
> task authorization, runtime permissions, and hook compatibility.

## Mandatory Non-Claude Checklist

Because non-Claude runtimes do not auto-load Claude path rules, apply these rules explicitly:

1. **FH asset change:** before editing, read `.claude/rules/fh_4axis_gate.md`; before the first commit,
   run its required axes. Treat `templates/regression_guard.sh` exit 0 as PASS or SKIP; use its typed
   result channel and never report SKIP as checked.
   🟥 **New blocking condition, 2026-08-30**: editing a `.md` under `knowledge/` or `docs/` now
   **blocks the commit** if a world-scoped novelty/absence claim ("선례가 없다", "유일하게",
   `no prior art`, `unprecedented`, …) stands with **no external anchor within ±6 lines**.
   Anchors the check accepts: a URL · arXiv/DOI · `WebSearch`/`WebFetch` · `출처` · `원문 확인` ·
   `서베이`. Override is `FH_NOVELTY_OK=1`, and it appends to `tracks/_meta/.novelty_override_log`.
   ⚠️ The check sees only that an anchor **exists**, never that it supports the claim.
1-b. **Before you trust the gate at all: check that this checkout is WIRED.** 🟥 FH's shipped Git
   pre-commit/pre-push blocking claims in `CLAUDE.md` and item 1 above apply **only in a checkout
   where `core.hooksPath` points at `templates/.git-hooks`.** Host lifecycle hooks need separate
   configuration, trust, and event-contract verification; Git wiring does not establish coverage. Git tracks the hook files; it does **not**
   carry that config value. Measured 2026-09-21, same commit, two checkouts: **15 layers compared,
   only 4 READ layers matched — all 11 ENFORCE/EVIDENCE/PATTERN layers were opposite.** The same
   commit passed silently in one and was blocked by Axis 2+3 in the other; what differed was the
   wiring, not the code.
   🟥 **The dangerous direction is the quiet one**: a gate that PASSED and a gate that NEVER RAN
   print the same thing — nothing. A third direction is quieter still: with the pattern layer
   absent the confidentiality scan still runs and still goes green, while company-name and
   real-name classes are simply `UNSCANNED`.

   ```
   bash scripts/env_layer_fingerprint.sh          # PRESENT/ABSENT/UNMEASURED per layer, no values
   bash scripts/gate_bootstrap_ephemeral.sh --check   # rc=1 while anything is missing
   bash scripts/gate_bootstrap_ephemeral.sh --apply   # wires hooksPath + UTF-8 locale
   ```

   Three things are needed and only two are mechanizable: ⓐ the `core.hooksPath` wiring ⓑ a
   **UTF-8 locale** (under `LC_CTYPE=POSIX` all four non-vacuity legs of an honest Korean marker
   are rejected as "vacuous" — over-blocking, the opposite failure) ⓒ the two gitignored evidence
   files, which **a human writes**. 🟥 The bootstrap script deliberately does **not** create
   markers — auto-generating evidence is closing the gate with a forgery.
   ⚠️ `scripts/fh_node_check.sh` cannot warn you here: it travels the same gitignored channel as
   the `settings*.json` it would read, so on an unwired node the detector is absent too.
   Detail: `knowledge/shared/harness-core/checkout_layer_drift.md` §8.

2. **Company residency:** raw company source, secrets, hostnames, internal names, stack traces, and
   unredacted findings never leave the local machine, including to same-family cloud models. Only a
   sanitized summary may leave; exceptions require explicit operator approval and a gitignored note.
3. **Author exposure:** before calling a material work product done, identify the author's blind spot
   and run the matching `agent-composer` Author-Exposure lens. The lens supplies evidence, not a verdict;
   unclear exposure defaults to `challenger`.
4. **Intent marshaling:** general work is in scope. Enumerate installed skills, `LOCAL_SKILL_REGISTRY`,
   and mapped project assets before composing capability. Preserve each trust tier and each outward
   action gate. Declare a gap only with the scan cited, then route through internal registry search,
   external search, and in-session synthesis. Persist and install retain their existing gates.
5. **Measurement integrity:** before trusting a scan or count, run a known-positive and known-clean
   pair, then open one hit manually. An empty or failed scan is `UNMEASURED`, not zero; extreme results
   require instrument suspicion.
6. **Irreversible intent:** before publish, delete, or history rewrite, read and apply the
   Pre-Publish or Destructive-Op gate in `CLAUDE.md`. `pre-push` is only the git-side backstop.
   **An automated verdict never clears an irreversible gate on its own, whatever its measured error
   rate.** Surface class decides, not the number: a wrong finding on a review surface costs a reader
   a minute, while on publish/delete/rewrite the wrong call is the whole loss. So improving a verdict
   engine's score is not a route to promoting it onto an irreversible surface — the terminal step
   stays a human or an explicit logged override. This matters here because a non-Claude runtime
   reading this file is itself often the verdict engine in question.
7. **Self-contrast on asset touch:** the trigger for the three-layer self-contrast (process ·
   engines · identities) is *touching an FH/PMH asset*, not being asked. Pick verification axes by
   failure mode — running all six every time is not the rule. Record, in the existing Axes 2–3
   marker fields: the soul line written before design (or `none`), each axis run and not run — by
   name, and each axis's control with whether it survived. The minimum evidence that an axis ran is
   execution output with a live control; reporting an axis as run without one, or recording only a
   reason for not choosing it, is not compliance. **`axis2-model:` is the model you are actually
   running as** (e.g. a Gemini, GPT or Claude model id) — never copied from another marker or from a
   hook hint; `axis2-engine:` names what really ran (`inline` if you reviewed it yourself). Measured
   2026-10-12: a non-Claude runtime copied `opus` / `quench-challenger` from the hook hint 3/3. The axes are named in
   `knowledge/shared/harness-core/fh_three_layer_canon.md` — **§1-a is the original four
   (2026-08-09) and §1-a-2 expanded them to six (2026-08-16)**: ⓐ different family · ⓑ standpoint ·
   ⓒ isolated grounding · ⓓ third-party encounter · ⓔ first real use · ⓕ revert-and-observe.
   Axes are separated by **what they received**, not by how adversarial they are — same input,
   same blind spot, however many reviewers you add. ✅ **The machine layer now carries all six**
   (2026-08-17): a marker dated on/after that day must write `axes-run:` with the **circled keys**
   `ⓐ=… ⓑ=→standpoint ⓒ=… ⓓ=… ⓔ=… ⓕ=…`; markers dated earlier keep the old **ASCII four**
   (`a b c d`) and are not retroactively blocked. 🟥 **The two arrays are not the same letters —
   old `b` (first real use) is now `ⓔ`, old `d` (revert probe) is now `ⓕ`.** Copying an old line
   forward silently swaps two axes and raises no error. **Which array a marker used is decided by
   the date in its filename** (`< 2026-08-17` = old four). ⚠️ The notation is NOT the discriminator
   — that claim stood in this file for part of 2026-08-17 and a hand-count of the corpus refuted it:
   2 of the 4 circled-key markers on disk are dated 2026-08-10 and carry the OLD meanings. Aligning
   the notation still helps going forward; it does not work backwards.
   `standpoint:` remains the canonical field for ⓑ (the `axes-run` entry
   is only a pointer to it, and a pointer at an empty field is blocked). 🟥 **CORRECTED 2026-08-20.** This used to say
   "its value enum is still validated by nothing" — FALSE. `validate_standpoint_leg()` in the
   pre-commit hook enforces a closed enum. Measured by varying one variable at a time:
   `standpoint: banana(qasp)` → **blocked (enum)** · `standpoint: tier2` without parens → **blocked
   (enum)** · `standpoint: tier2(qasp)` with no execution grounds → **passes with a warning** ·
   with grounds → **passes**. So the enum is enforced and the `tier2`+ execution grounds are
   **advisory** — a first version of this correction said grounds were required, which over-shot.
   The hook also cannot check whether `tier2` is **true**. Those two, together, are the gap. Format spec: `.claude/rules/fh_4axis_gate.md §Marker axis fields`.
   (Two drift corrections landed here on 2026-08-17: first this sentence said "four" while its own
   next clause described the +1 — caught by the session-close ④-b CC↔Codex parity check — and then
   the machine layer moved to six the same day.)
   ⚠️ Until 2026-08-17 this entry point added "**ⓓ has no field at all** — record it in prose".
   That is now **false**: `ⓓ=` is a required key like the rest. The retraction is kept visible
   rather than deleted, because a Codex-side reader who memorised the old line would otherwise
   keep writing markers without ⓓ and see them blocked with no idea why.
   🟥 ⓑ **standpoint is itself split** (2026-08-17): a STATIC read of the target's own files is
   `tier1b` and **executes nothing**; `tier2`+ asserts that something was RUN — the discriminator is
   mechanical, *name the command you ran and the output you saw*. Measured on one delta: the static
   arm found 1, running the target's own suite found 2 more, one of which printed neither `FAIL` nor
   `❌`. Execution is the half with no substitute; see `field_verdict_crossfamily_gate.md §7`. Read it before recording; §1-c
   holds the sample limits — read it before citing. This record is self-attested and has no hook
   behind it; it is closed by a different-family reader, not by writing it more carefully.
   🟥 **`axis2-defense:` — a marker field added 2026-08-20 that a Codex-side author WILL hit.**
   It is required when the marker records `floor-status: sonnet-floor` or `below-floor`, and it carries
   three sub-answers (on one line, or across continuation lines — the hook reads both) about **your own findings and numbers**:
   `axis2-defense: reproducibility=<exact command or file:line another session runs> fairness=<reps,
   inputs and environment named for BOTH arms> estimation-layer=<per number: measured | estimate |
   quotation; for a measurement, what showed the instrument works on this target>`.
   The hook (`validate_defense_leg`) checks **presence · completeness · non-vacuity** — `ok`/`yes`/
   `n/a` is rejected as a filled form rather than an answer, and all three sub-answers must exist.
   It cannot check whether the answers are true. Why it exists: measured n=6 in the origin field, a
   floor-tier pass runs the attack angles without defect but does **not** spontaneously ask these
   three; that is a checklist gap, not a capability gap, and a harness whose behaviour depends on
   which model drives it is defective by the Sonnet-Floor doctrine.
   Fixtures: `scripts/test_marker_defense_lanes.sh`. Spec: `plugins/fh-meta/skills/steel-quench/SKILL.md`
   §Wave 1-D. **Recorded here because a rule living in only one entry point is invisible to the other
   runtime** — that is the gate-locality principle, and this line is it being applied rather than cited.

   🟥 **`defeater:` — required on markers dated 2026-09-01 or later. A Codex-side author WILL hit this.**
   One line answering **「if this success definition is wrong, what would be OBSERVED?」**
   The hook (`validate_defeater_leg`) checks **non-vacuity only** (6+ words) — it cannot check whether
   the answer is true. Markers dated before 2026-09-01 are **not** retroactively affected
   (same grace pattern as `SOUL_PRESENT_GRACE_DATE`).
   `defeater: 없음` / `none` / `n/a` is **legal** — a declared absence is a value, not silence.
   **`affected:` — OPTIONAL since 2026-09-04 (absent = pass, gradual adoption like `tenets:`).** One
   line naming what this change touches (people · harnesses · surfaces) plus any open question
   (`… · 열린 질문 = …`). When present, the hook (`validate_affected_leg`) blocks only a bare placeholder
   (`없음` / `TBD` / `-` / `n/a`), a duplicate line, or a near-miss key (`affects:`, `affected :`) —
   it never judges whether the content is true. Origin: the AI-Native SDLC playbook's intent.md
   «Affected users and systems / Open questions» sections, absorbed as one field (PR #624).
   **`oracle:` — OPTIONAL since 2026-09-05 (absent = pass).** One line `oracle: <kind> — <grounds>`,
   kind ∈ closed enum `known-pair` · `metamorphic` · `back-to-back` · `a-b` (`A/B` accepted) · `human` ·
   `none` — the test-oracle type of ISO/IEC TR 29119-11, i.e. *what the expected result was decided
   against*. When present, the hook (`validate_oracle_leg`) checks **form only**: enum membership
   (the kind must be followed by a delimiter or end of line — `known-pair2` / `human_review` are not
   members), non-vacuous grounds (≥2 words, no placeholder — and `none` MUST carry its reason), a
   single line, and near-miss keys by one rule: **any line whose key starts with `oracle` but is not
   exactly `oracle:`** (examples, not an enumeration: `Oracle:` `oracles:` `oracle :` `oracle :`
   `oracle_type:` — a qasp-side author will reach for that one — `oracle-type:` `oracle.evidence:`,
   bare `oracle`) plus the typos `orcale:` `oralce:` `오라클:`, blocked even when a correct `oracle:`
   line is also present. Consequence: the `oracle*` key namespace is reserved by this field — no
   separate `oracle-…:` field can be added later. It never judges whether that oracle was actually
   used. Named residuals (marker-wide, not specific to this leg): grounds containing the hint's
   literal `<...>` are blocked (same boundary as `affected:`/`defeater:`); a line that STARTS with
   U+3000 or carries an embedded CR is outside `[[:space:]]`/line-wise grep and is not seen. Fixtures:
   `scripts/test_marker_oracle_lanes.sh` · wiring `scripts/test_hook_leg_wiring_lanes.sh` W6.
   🟥 A near-miss key (`defeaters:`, `반증:`, `defeater :`) is **blocked even when a correct
   `defeater:` line also exists** — the author believes they wrote it and the gate cannot read it,
   which is the quietest failure. Two `defeater:` lines are also blocked (readers take the first,
   so an appended correction is silently shadowed).

   Two more fields landed the same day, neither of them blocking-on-absence:
   - `tenets:` — **optional**. If you cite IDs, every `FH-T\d\d` on that line must exist in
     `.claude/soul_tenets.txt` (a typo is blocked rather than silently dropped). Citations are read
     **from that line only** — naming an ID elsewhere in the marker is description, not citation.
   - `soul-check:` — a closed enum **when present**; its absence passes (adoption is incremental).

   External grounding for the shape (not invented here): atomic testable tenets
   ([arXiv 2605.24229](https://arxiv.org/abs/2605.24229)) · defeaters and counterevidence
   ([Assurance 2.0](https://arxiv.org/abs/2004.10474)) · the ≤7 / priority-ordered /
   **opposite-must-be-defensible** discipline
   ([AWS tenets](https://aws.amazon.com/blogs/enterprise-strategy/tenets-supercharging-decision-making/)).
   Fixtures: `scripts/test_marker_soul_tenet_lanes.sh` · `scripts/test_hook_leg_wiring_lanes.sh`.
   Spec: `.claude/rules/fh_4axis_gate.md` §Marker axis fields.
   🟥 **Why this entry exists at all**: the CC-side spec did not describe `soul:` for **nine days**
   while the hook was already blocking on it, and a blind floor-tier sim measured three arms writing
   every other marker field and omitting that one. The defect was the wiring, not the model — and
   a rule living in only one entry point is invisible to the other runtime.

   ⚠️ **Also for Codex-side authors: `sim_isolated_run.sh` was not isolated until 2.14.0.**
   Arms could read outside the clone — including the answer key of the very measurement they were
   part of. Any sim number produced with ≤2.13.0 needs re-measuring.

8. **Branch-surface claims:** GitHub branch protection is two independent layers — legacy
   protection and rulesets coexist, and the strictest wins. Read both
   `/repos/{owner}/{repo}/branches/{branch}/protection` and
   `/repos/{owner}/{repo}/rules/branches/{branch}` before declaring any branch surface open or
   closed. In the reference repository (forge-harness), reading the protection object alone
   misjudged the force-push surface three times; the symmetric single-endpoint case is untested,
   but the same failure shape applies.

9. **Shared checkout:** when more than one session works in one clone, the working tree and `HEAD`
   are shared, so a branch switch moves the other session's ground. Before `git switch`, read the
   live head with `git branch --show-current`; immediately after cutting a branch, run
   `git log main..HEAD --oneline` — a non-empty result means the branch was cut on top of someone
   else's commits, and a later squash of the parent closes the child PR. The claim files under
   `.git/fh-claims/` are a snapshot written at claim time, not a lock: they do not update when
   somebody moves a branch, so they answer a different question than the two commands above.
   Record a switch with `scripts/branch_claim.sh claim`; the pre-commit hook blocks a commit whose
   claim does not match the live head. In a shared checkout `git add -A` and `git stash` both reach
   the whole tree, including another session's uncommitted work — stage by explicit path instead.

> **Detail**: See `knowledge/shared/harness-core/agents_md_runtime_details.md §Mandatory-checklist-procedures`
> — exact supporting procedures and canonical doctrine links — read when any checklist trigger fires.

## Invocation

Use available Codex-native skills and tools for authorized governor work. Prefer
`FH_BACKEND=codex ... fh-run` when a workflow needs an FH adapter. A Claude
`Agent(subagent_type=...)` or slash-command step needs an explicit equivalent: a permitted native
agent reading the spec, `fh-run`, or direct `codex exec`. Preserve the specified isolation, tool
limits, model floor, consent, and return gate. Use native goal/session control when available;
FH supplies the quality gate after goal completion. The tiers below classify the shipped FH
implementation, not the maximum capabilities of the Codex host.

| Tier | Definition | Skills |
|---|---|---|
| **M1 — Full** | No Claude-native dependency | `token-budget-gate`, `asset-placement-gate`, `phantom-quench`, `deep-clarify`, `convergence-loop`, `ko-tech-writer` (visual-QA degrades to text-only; the spoken register's Step 5-s renders audio through a shell TTS call — available here — but its **listening** pass is human in every runtime, so it degrades to declared-unmet, not to a Codex-specific gap) |
| **M2 — Partial** | Core works; native agent or slash-command steps need adaptation | `deliberation`, `steel-quench`, `harness-doctor`, `context-doctor`, `sim-conductor`, `harvest-loop` |
| **M3 — Claude-bound implementation** | Shipped workflow requires Claude-specific hook/configuration or session context | `goal-quench`, `harness-pr-reviewer`, `install-wizard` |

> **Detail**: See `knowledge/shared/harness-core/agents_md_runtime_details.md §Invocation-patterns`
> — single, parallel, and wave composition examples — read when choosing a dispatch shape.

### Before dispatching without being asked

FH treats isolated delegation as part of what a harness *is*, so it leans toward dispatching rather
than absorbing separable work inline. One boundary comes with that, and it is runtime-agnostic:

```
unprompted dispatch is available only when a standing request from the user is RECORDED —
  in a durable local file, carrying all three of:
    the user's own words, quoted   · a dated lease   · a scope line
no such record, or the lease has lapsed, or you cannot tell (fresh clone · a runtime whose
  own prompt may restrict this)
  → the request is absent, and absent is not granted → ask per invocation
```

Four notes for anyone porting this. A record is only a record if the *user* authored the quoted
words — an agent writing the file on its own initiative has produced nothing. Consent is **leased,
not owned**: past the lease date the record stops counting and you go back to asking. Every run that
proceeds *without* a prompt should say that it is doing so, so an unnoticed grant cannot accumulate
silently. And the request buys not-being-asked about the dispatch; it never relaxes a gate at what
the dispatched agent then touches (publish, delete, history rewrite).

The Claude-side rationale — including why the boundary is phrased around a *conditional* rather
than a prohibition — lives in `CLAUDE.md §Agent Dispatch Operation` and is specific to that runtime.
The constraint above is not.

### Builder dispatch brief — every builder, asked for or not

A brief (FH calls it a *Context Card*: purpose · done so far · this task · constraints) for a
**builder** — a delegated agent that edits code or files — carries two more lines, whatever runtime
launches it:

```
1. Smallest fix first. If the fix needs a new mechanism (a cache, a budget, a new rule),
   stop and report why before building it — in your reply to whoever dispatched you,
   with no code change for the new mechanism.
2. Do not run commands that discard uncommitted work in the tree you were given
   (git stash · git checkout -- … · git restore · git reset · git clean, or the like).
   If you ran one anyway, put the work back first, then report it in the same reply —
   not only at the end. If you cannot put it back, stop and say where it is (stash ref, reflog).
```

A disposable worktree you created yourself for a revert probe is not «the tree you were given»;
reverse a fix there with `git apply -R`.

Both lines come from one day's measured builder runs (2026-10-28): an unrequested cache and read
budget that drew five new review findings, and a `git stash` + `checkout --` that was restored but
surfaced only in the hand-back. Canonical text and evidence: `claude_md_full_reference.md §Context Card`.

> **Detail**: See `knowledge/shared/harness-core/agents_md_runtime_details.md §Codex-entry-points`
> — runnable `fh-run` and `codex exec` forms — read before invoking FH from Codex.

> **Detail**: See `knowledge/shared/harness-core/agents_md_runtime_details.md §Compatibility-tiers`
> — tier constraints and goal-handling limits — read before adapting an M2/M3 workflow.

## Conditional Procedures

> **Detail**: See `knowledge/shared/harness-core/agents_md_runtime_details.md §Beta-removal`
> — external-validation conditions and reporting route — read when evaluating or changing beta status.

> **Detail**: See `knowledge/shared/harness-core/agents_md_runtime_details.md §Adding-agents`
> — creation gate, registry synchronization, and post-use thresholds — read before adding an agent.

> **`reps` below the bar is a TRIGGER, not a label** (2026-08-29). This repo's bar is `reps>=3`.
> When you record a measurement at reps 1–2 **and its conclusion is load-bearing** — it holds up a
> verdict, a grade, a doctrine change, or an irreversible prescription — do not write *"below the
> bar"* and move on. That was the standing default, and a label is not a measurement. Say it in one
> line instead: *"this is reps={n} — raise it to {target} by simulation?"* 🟥 The **load-bearing**
> condition is what keeps this from becoming noise: a single run done to confirm an instrument has
> nothing to raise. The same discipline applies to a field harness's own records, where it is the
> `measurement-reps` lens of `knowledge/shared/harness-core/field_harness_diagnostic.md` — 🟥 read
> that file's **Step 0 (provenance split)** before running it anywhere: a harness onboarded by FH is
> FH-derived, so an unsplit scan reads FH's own text back as a field finding.

> **Removing resident text**: if you are considering deleting a section from `CLAUDE.md` (or any
> always-loaded asset) because it looks redundant, this repo settles that by measurement rather than
> by reading. The procedure — two arms, an isolated runtime, `reps>=3`, a question set fixed before
> the arms run — is documented in the header of `scripts/probe_scope_check.sh`; the runner must first
> pass `bash scripts/ablation_calibrate.sh` (exit 0), and verdicts are recorded in
> `.claude/regression/ablation_verdicts.md`. Worth knowing before you propose a cut: a section whose
> removal makes a reader answer *confidently wrong* counts as load-bearing, not as safe to drop.
> **And the trap that produces a wrong CUT most easily**: when both arms score the *same*, that is
> equally consistent with the section being redundant and with the scorer never having moved. The
> two are indistinguishable from the outcome alone. Before writing a CUT on equal scores, name an arm
> that MUST score differently and show the metric moved on *that* pair; if it did not, the verdict is
> `INSTRUMENT-UNCONFIRMED`, not `CUT` (added to the script header 2026-08-23, §7).