ReadonlybuiltinOptional ReadonlyeventWhat each hook event CARRIES and HONOURS — EventCapabilityTable.
The single table three flat lists had been approximating: hookEvents
(membership), noEffectHookEvents (blocks ignored) and
permissionDecisionHookEvents (deny needs a field) all ask about an event,
none relate it to its PAYLOAD, and the fourth — injectableEvents — sits on
a different port entirely. A list per question cannot answer a question
about a PAIR, which is what "is this role legal on this event?" is.
Optional (additive, non-breaking): absent ⇒ the flat lists still decide, and the (role, event) compatibility check does not run for that adapter. Present ⇒ it is the source the derived lists are read from, so the two cannot drift.
ReadonlyhookHook event names the harness fires.
Optional ReadonlyhookThe hook-event catalog as a HarnessVocabulary — a status and a
recorded vendor capture per term, rather than bare membership in
hookEvents. When present it is what verifyHookEvents classifies against,
so a name the catalog doesn't hold produces an unrecognised ADVISORY
(naming vigiles's capture as the possibly-stale party) instead of the old
behaviour, where an unknown name drew an accusation or silence depending on
its edit distance to the list.
Optional (additive, non-breaking). Absent ⇒ one is synthesised from
hookEvents via vocabularyFromLists, so a legacy adapter keeps working
and its unknowns become advisories rather than silence.
Optional ReadonlyinstructionWhat this harness loads WITHOUT being asked, how it MEASURES that, and what it does when there is too much — InstructionBudget.
On the dialect because it is a FORMAT fact (which files, counted in which unit), and because the browser engine is handed a dialect. Optional: absent ⇒ the weight report does not run for that adapter, which is the honest answer for a harness whose limits nobody has read.
ReadonlyinstructionInstruction-file targets the harness reads (also the h1 heading).
Optional ReadonlyknownMCP servers the harness provides itself, available to a contract WITHOUT the
plugin declaring them — e.g. Claude Code's built-in ide integration
(mcp__ide__getDiagnostics). The mcp-tool-resolves check allowlists these
so a reference to a built-in server is never flagged as an undeclared one.
Optional (additive, non-breaking for existing adapters) — defaults to none.
ReadonlymcpMatches an MCP tool reference, e.g. mcp__server__tool.
ReadonlynameStable identifier, e.g. "claude-code".
ReadonlyneverTools the platform never exposes to a subagent (a listed one is dead).
Optional ReadonlynoThe subset of hookEvents where a block decision (exit 2 / a deny field)
is SILENTLY IGNORED ENTIRELY — no veto AND no model feedback (Claude Code's
SessionStart / SessionEnd / Notification / PreCompact: exit 2 there writes
stderr only to the user). The basis for the hook-block-ineffective
"wrong-event" check, which fires ONLY on these (so it stays FP-safe and never
cries wolf on a PostToolUse feedback/nudge hook). Optional (additive,
non-breaking) — absent ⇒ the harness's block semantics are undeclared and the
check does not run for it.
Superseded by eventCapabilities, from which this list is
now DERIVED (blockIneffectiveEvents) and against which it is asserted. Kept
because removing a public port field breaks third-party adapters; it will go
in the next major.
🔴 THE NAME IS WRONG AND THAT MATTERED. "No effect" reads as "a hook here does
nothing", but it MEANS "no effect OF A BLOCK" — Claude Code's SessionStart
is in this list and injects context perfectly well; exit 2 is the only thing
it ignores. Deriving the list caught this: the obvious predicate
(honours === []) silently dropped SessionStart and would have changed what
hook-block-ineffective flags.
Optional ReadonlypermissionThe subset of blocking events whose deny REQUIRES the structured
permissionDecision field (e.g. Claude Code's PreToolUse), where the
legacy top-level decision field is silently ignored. The basis for the
hook-block-ineffective "wrong-field" check. Optional (additive). *
Superseded by eventCapabilities (denyShape: "permission-decision"), from which this list is derived and against which it
is asserted. Kept for third-party adapters; goes in the next major.
ReadonlypluginThe env token expanded to the plugin root in hook commands.
Optional ReadonlysideTools that PRODUCE side effects (write, exec, network, spawn) — the
complement of read-only within builtinAgentTools. The basis for
effect-surface analysis and the pure: contract: a tool here is denied to a
pure skill and counts toward a harness's side-effect surface. Bash is
listed (undecidable at the tool-name level → conservatively side-effecting);
an MCP tool not classifiable from the name is treated as unknown-effect.
Optional (additive, non-breaking) — absent ⇒ no tool is known-side-effecting.
ReadonlyskillThe SKILL.md frontmatter keys this harness READS. The compiler emits a key
iff it is listed here, so a harness that reads only the cross-tool shape
declares ["name", "description"] and the CC-only keys are omitted from its
output rather than written as inert noise.
Conformance requires name and description (a SKILL.md without them has
no identity) and refuses a key outside
RENDERABLE_SKILL_FRONTMATTER_KEYS — a key the compiler cannot render
is a declaration nothing acts on.
Optional ReadonlysubagentThe subagent-tool catalog as a HarnessVocabulary. Same contract as
hookEventVocabulary; absent ⇒ synthesised from builtinAgentTools
(available) + neverAvailableTools (withheld).
The third status is why this exists: the vendor removes Agent only at the
spawn depth limit and ExitPlanMode only outside plan mode, and removes
most built-ins from a background subagent but not a foreground one — so
"available to a subagent" is not a property of the name, and a two-way
split had to encode one of those conditions as an unconditional fact.
Built-in tools a subagent may list in its
tools:contract.