# Harness hooks index

One-line discoverability layer for every harness-installed hook in this repo. Each entry cites the hook by **existence + event + purpose** and notes whether an escape hatch exists. The hook source file remains the canonical reference for full semantics (env-var names, sentinel paths, cap counts, deny-message wording, exit codes, payload field handling, settings.json registration, postinstall mechanics).

Skills that cite a hook should link this index once per skill rather than re-inlining hook internals.

Orchestrator-mode and cascade-routing concerns previously enforced by this package now live in external automated CLI drivers. This index documents only the hooks element-interactions still ships.

## Session-scoped activation

Every hook below applies **only to sessions where the achilles protocol is active**. The hooks are installed globally (`~/.claude/settings.json`), but a plain development session — one that never invokes an achilles skill, dispatches a protocol-role subagent, or types an achilles `/<skill>` command — passes through every gate untouched: no commit-grammar enforcement, no protected-artifact denies, no `.achilles/` summary artifacts. The shared detection logic lives in [`hooks/lib/achilles-activation.sh`](../../../hooks/lib/achilles-activation.sh); activation signals are (in order) `ACHILLES_PROTOCOL=1` (force on), the per-session marker written by the activation watcher, a protocol-shaped current tool call, and a transcript signature (achilles Skill invocation, typed `/<skill>` command, or Read of an achilles `SKILL.md`). Payloads without a `session_id` are treated as active (fail closed): a real harness always supplies one, so only synthetic invocations hit that branch.

**Lifecycle — one-way once active.** A session activates at the first achilles signal and can then be deactivated by exactly two things: **the pipeline completing** (the watcher observes a sanctioned ledger write landing terminal status `complete` / `aborted` on `onboarding-status.json` / `perf-onboarding-status.json` and retires the marker) or **the Claude session being terminated**. There is no mid-session off switch: `ACHILLES_PROTOCOL=0` suppresses *activation* (useful for fixtures and synthetic payloads) but never deactivates a session whose marker exists, and the marker state dir (`~/.claude/achilles/`) is itself protected **unconditionally** — Bash mutations are denied by `protected-artifact-bash-guard` and Write|Edit by `harness-self-protection-guard` even in otherwise-inactive sessions, because the activation state is the root of trust for every other gate. Every deny payload appends the canonical `achilles_scope_notice()` block instructing both the agent and the user: to work on an unrelated task or start a new workflow, **end the session and start a fresh one**. After completion, enforcement gates go quiet (historical transcript signatures do not re-activate) while the summary/cleanup hooks (`run-summary-writer`, `perf-summary-writer`, `playwright-cli-cleanup-on-stop`) still run via the `.completed` marker; a fresh explicit achilles invocation re-opens the protocol.

### Skill / Agent / UserPromptSubmit

- **[achilles-protocol-activation-watcher](../../../hooks/achilles-protocol-activation-watcher.sh)** — `PreToolUse:Skill`, `PreToolUse:Agent`, `UserPromptSubmit`, `PostToolUse:Write|Edit` (completion detection: a sanctioned ledger write landing terminal status `complete`/`aborted` retires the session's activation marker and stamps `.completed`). OBSERVE-mode (never denies, never emits output). Writes the per-session activation marker (`~/.claude/achilles/sessions/<session_id>.active`) the moment an achilles Skill is invoked, a distinctly-achilles role-prefixed subagent is dispatched (`workflow-reviewer-`, `perf-reviewer-`, `phase-validator-`, `phase4-*`, `composer-`, `probe-`, `process-validator-`, `contribution-handover-` — generic-sounding prefixes like `cleanup-` deliberately excluded), or the user types an achilles `/<skill>` command. Prunes markers older than 7 days. The enforcement gates re-check the same signatures inline via the shared lib, so this hook is a cache writer, not a correctness dependency — hook-ordering races cannot open a gap. [escape hatch: n/a (never denies); `ACHILLES_PROTOCOL=0` suppresses marking]

## PreToolUse

### Edit / Write

- **[selector-development-activation-gate](../../../hooks/selector-development-activation-gate.sh)** — `PreToolUse:Edit|Write` (frontend source paths only). Denies selector-development frontend edits when the workspace lacks a recognised frontend framework dep or a `tests/e2e/*.spec.ts` directory. [escape hatch: no]
- **[selector-development-inertness-guard](../../../hooks/selector-development-inertness-guard.sh)** — `PreToolUse:Edit|Write` (frontend source paths only). Denies selector-development frontend edits whose diff is anything other than a single-attribute additive change matching the project's selector convention. [escape hatch: yes (env override)]
- **[selector-development-pipeline-stepper](../../../hooks/selector-development-pipeline-stepper.sh)** — `PreToolUse:Bash|Edit|Write` (gate) + `PostToolUse:Bash|Edit|Write` (record). Enforces the 8-step selector-development pipeline (before-snapshot → patch → typecheck → unit → e2e → after-snapshot → visual-diff → commit); denies steps whose predecessor is not recorded as pass; records each step's outcome on the per-scope receipt. [escape hatch: no]

### Agent

- **[subagent-schema-preread-gate](../../../hooks/subagent-schema-preread-gate.sh)** — `PreToolUse:Agent`. Denies schema-validated role-prefixed dispatches whose brief omits the schema citation. [escape hatch: no]
- **[standard-mode-first-pass-guard](../../../hooks/standard-mode-first-pass-guard.sh)** — `PreToolUse:Agent`. First-pass / first-cycle strict-dispatch enforcement for `coverage-expansion` + `journey-mapping`. Denies: (a) Pass-1 `[group]` / `[P3-batch]` dispatches under `mode: standard`; (b) `phase4-prioritise-author:` dispatches before ≥ 2 distinct cycle-1 sections have been dispatched; (c) single-subagent walkthroughs of journey-mapping cycle 1 (≥ 3 canonical section IDs in one description with no prior cycle-1 dispatches). Pass-2+ and cycle-2+ are silent-allowed under `runMode: standard` / `cycleStrictness: standard`; under `depth` the denials apply to every pass / cycle. Mode read from `tests/e2e/docs/onboarding-status.json` (fallback `coverage-expansion-state.json` / `.phase4-cycle-state.json`). [escape hatch: no]
- **[workflow-approver-registry](../../../hooks/workflow-approver-registry.sh)** — `PreToolUse:Agent`. Registration hook (never blocks). Records every approver-prefixed dispatch (`workflow-reviewer-*`, `phase-validator-*`) by `tool_use_id` into `tests/e2e/docs/.workflow-approvers.json` so the ledger write-gate can verify WHO is approving, not just WHAT. [escape hatch: n/a (never denies)]
- **[workflow-reviewer-brief-gate](../../../hooks/workflow-reviewer-brief-gate.sh)** — `PreToolUse:Agent`. Denies `workflow-reviewer-*` dispatches whose brief lacks any of: the literal `onboarding-status.json` ledger reference, a verification verb (`Read` / `verify` / `inspect`), or ≥ 400 characters of substance. Closes the "just approve, everything's good" brief-injection surface. [escape hatch: yes (`WORKFLOW_REVIEWER_BRIEF_GATE=off`)]
- **[onboarding-ledger-gate](../../../hooks/onboarding-ledger-gate.sh)** — `PreToolUse:Agent`. Pipeline state-machine enforcement. Reads `tests/e2e/docs/onboarding-status.json` and denies (a) non-`workflow-reviewer-*` Agent dispatches at any transition point where the prior phase's `reviewerVerdict` is still `pending`; (b) out-of-order phase / pass / cycle dispatches (e.g. `phase4-*` while `currentPhase = 2`, `composer-j-…-2` while `pass-1.reviewerVerdict != approved`, `phase4-cycle-2-section-*` while `cycle-1.reviewerVerdict != approved`). `workflow-reviewer-*` dispatches always allowed. Silent-allow on missing / malformed ledger so a brand-new run can start. [escape hatch: no]
- **[perf-onboarding-ledger-gate](../../../hooks/perf-onboarding-ledger-gate.sh)** — `PreToolUse:Agent`. Pipeline state-machine enforcement for the perf-onboarding pipeline. Reads `tests/perf/docs/perf-onboarding-status.json` and denies (a) non-`perf-reviewer-*` Agent dispatches at any transition point where the prior phase's `reviewerVerdict` is still `pending`; (b) out-of-order phase dispatches (e.g. `load-run-*` while `currentPhase = 2`); (c) out-of-order Phase-5 pass dispatches (passes ordered load → stress → spike → soak — a pass cannot start until the prior pass has `reviewerVerdict: approved`). `perf-reviewer-*` dispatches always allowed (subject to the 3-cycle cap). Silent-allow on missing / malformed ledger. [escape hatch: no]
- **[journey-mapping-skill-preread-gate](../../../hooks/journey-mapping-skill-preread-gate.sh)** — `PreToolUse:Agent` (also `PreToolUse:Write|Edit`; one script, two events). Denies (a) `phase4-cycle-*` / `phase4-prioritise-author:` Agent dispatches; (b) writes to `tests/e2e/docs/journey-map.md` / `journey-map-coverage.md`; (c) subagent spill writes to `tests/e2e/docs/.subagent-returns/phase4-*` — when the session transcript shows neither `Skill('journey-mapping')` nor `Read` of `skills/journey-mapping/SKILL.md`. Each surface gets a deny message tuned to the caller. Both the orchestrator session (writes + dispatches) and the dispatched-subagent sessions (spill writes) are gated. [escape hatch: yes (`JOURNEY_MAPPING_PREREAD_GATE=off`)]

### Write|Edit

- **[perf-onboarding-ledger-write-gate](../../../hooks/perf-onboarding-ledger-write-gate.sh)** — `PreToolUse:Write|Edit`. Schema + state-machine integrity gate for writes to `tests/perf/docs/perf-onboarding-status.json`. Validates against the perf-onboarding-status schema (inlined in `hooks/lib/validator.bundle.mjs`; source `schemas/perf-onboarding-status.schema.json`); enforces state-machine transitions, actor-identity on approval writes, mode-authorisation, reviewerCycles discipline, and per-phase positive-deliverable checks (Phase 1: `perf-onboarding.config.json` + non-empty `tests/perf/lib/`; Phase 2: `readiness.md`; Phase 3: `scenario-model.md` + sentinel + ≥1 `scenarios/*.js`; Phase 4: ≥1 `baselines/*.json`; Phase 5: ≥1 `results/*.json`; Phase 6: `threshold-verdict.json` with `deliberateBreach` present; Phase 7: `perf-report.md` + sentinel). [escape hatch: no]
- **[onboarding-ledger-write-gate](../../../hooks/onboarding-ledger-write-gate.sh)** — `PreToolUse:Write|Edit`. Schema + state-machine integrity gate for writes to `tests/e2e/docs/onboarding-status.json`. Validates against the onboarding-status schema inlined in the self-contained `hooks/lib/validator.bundle.mjs` (built by `scripts/build-validator.mjs`; source `schemas/onboarding-status.schema.json` — no node_modules or repo root needed at hook runtime); additionally denies `runMode` set/change writes that lack a co-located verbatim `modeAuthorizer` quote, denies phase-skip ledger transitions that lack a `status: skipped` + `approvedDeviations[]` entry with a non-empty `authorizer`, denies `reviewerVerdict: approved` paired with a null `handoverEnvelope`, denies any orchestrator-context write that transitions a `reviewerVerdict` to `approved` (actor-identity check — only writes from registered `workflow-reviewer-*` / `phase-validator-*` subagent contexts may land approvals), and enforces per-phase positive-deliverable checks at every Phase-N → `completed` transition (Phase 4 requires `journey-map.md` + sentinel + cycle-state with cycles 1+2; Phase 5 requires `coverage-expansion-state.json` with ≥1 pass record; Phase 6 requires `adversarial-findings.md`; Phase 7 requires `.env.example`; Phase 8 requires both `qa-summary-deck.html` and `.pdf`). The Phase-5 check is strengthened to require the **full five-pass run + cleanup** recorded in `coverage-expansion-state.json` (passes 1-5 + a cleanup record), not just pass-1 — the state file must still be present and complete at the completion write (deletion happens post-approval per cross-cutting §12; `breadth` runs are the single-pass exception). Also enforces **reviewerCycles discipline**: any write that changes a phase's `reviewerVerdict` must increment that phase's `reviewerCycles` by exactly 1, and a 3rd-round rejection may not stay `rejected` — at `reviewerCycles == 3` the verdict must be `escalated-to-user` with pipeline `status: blocked` (user-authorised skips are exempt from the counter). When `node` or the validator bundle is unavailable the schema check is skipped, but the actor-identity, state-machine, mode-auth, reviewerCycles, and per-phase deliverable checks still fire (jq-driven). [escape hatch: no]
- **[harness-self-protection-guard](../../../hooks/harness-self-protection-guard.sh)** — `PreToolUse:Write|Edit`. Denies Write|Edit to the installed harness surface: any path under `*/.claude/hooks/*` or the `*/.claude/settings.json` / `settings.local.json` files. Hook changes go through the repo (`hooks/<file>.sh`) + `npm run sync-hooks`, never by editing the installed copy. Project-local `.claude/skills/*` writes are allowed. Closes the Write|Edit vector that `protected-artifact-bash-guard` covers only for the Bash vector. (Residual self-edit race documented in the hook header; bounded by install-time re-copy.) [escape hatch: no]
- **[hook-authored-state-guard](../../../hooks/hook-authored-state-guard.sh)** — `PreToolUse:Write|Edit`. Denies direct Write|Edit to hook-authored state — `*/.workflow-approvers.json` (approver registry) and `*/.ledger-integrity.json` (integrity sidecar) — mirroring `ledger-integrity-chain`'s sidecar self-deny. Also gates **monotonicity** of the orchestrator-written progress files `.phase4-cycle-state.json` and `coverage-expansion-state.json`: a write that shrinks or removes elements from `cycles.N.dispatched-sections`/`returned-sections` or `passes.N.dispatched-journeys`/`returned-journeys` is denied, as is a first write whose `returned-*` roster is already non-empty (returns cannot predate any dispatch). [escape hatch: operator-only]
- **[journey-map-sentinel-gate](../../../hooks/journey-map-sentinel-gate.sh)** — `PreToolUse:Write|Edit`. Denies writes to `tests/e2e/docs/journey-map.md` whose line-1 is not the literal `<!-- journey-mapping:generated -->` sentinel, and writes to `journey-map-coverage.md` when the map is absent or sentinel-less. Also denies the first-write of `journey-map.md` if `.phase4-cycle-state.json` is absent or shows zero cycle-1 section dispatches. Edits to an already-sentinel-bearing map are silent-allowed. [escape hatch: no]
- **[ledger-integrity-chain](../../../hooks/ledger-integrity-chain.sh)** — `PreToolUse:Write|Edit` (verify, DENY) + `PostToolUse:Write|Edit` (record). Tamper-evident hash chain for the onboarding status ledger **and** the two orchestrator-written progress files (`.phase4-cycle-state.json`, `coverage-expansion-state.json`): sanctioned Write/Edit writes append the resulting file hash to the `tests/e2e/docs/.ledger-integrity.json` sidecar (the ledger uses the legacy flat `records[]` chain; the progress files use a per-file chain under `keyedRecords["<basename>"]`); out-of-band mutations (which never fire Write|Edit hooks) drift from the sidecar and the next gated write is denied until the operator intervenes. Also detects the rm-reset trick and denies direct writes to the sidecar itself. DETECTS what `protected-artifact-bash-guard` fails to PREVENT — the two ship as a pair. [escape hatch: operator-only (restore the file or delete the sidecar in a human terminal)]

### Bash

- **[perf-load-safety-gate](../../../hooks/perf-load-safety-gate.sh)** — `PreToolUse:Bash` (`k6 run` commands only). Hard ceiling on autonomous k6 load runs: denies VUs > 1000, duration > 3600 s, origins not in the `perf-onboarding.config.json` allowlist, and production origin load-tests unless `production.allowed` is explicitly `true`. The ceilings are baked into the gate (not read from config) so the orchestrator cannot raise them. [escape hatch: no]
- **[commit-message-gate](../../../hooks/commit-message-gate.sh)** — `PreToolUse:Bash` (`git commit` only — the trigger tolerates `command`/`env` wrappers and `-c key=val` global flags, so `git -c … commit` is gated). Denies coverage-expansion / journey-mapping commits that violate the conventions (wrong type, multi-journey, hook-bypass flags), and denies any commit carrying **AI-attribution metadata** — a `Co-Authored-By:` trailer naming claude / anthropic / `noreply@anthropic.com`, a "Generated with [Claude Code]" marker, or a `claude.ai/code` URL — scanning the full command surface plus any `-F` file contents, independent of the `-m` subject. (A prose mention of "claude" in a normal subject still ALLOWs; the match targets attribution trailers/markers, not any mention.) [escape hatch: no]
- **[pr-attribution-gate](../../../hooks/pr-attribution-gate.sh)** — `PreToolUse:Bash` (`gh pr create` / `gh pr edit` only — the trigger tolerates `command`/`env` wrappers). Denies any pull request carrying **AI-attribution metadata**, using the same match as `commit-message-gate` — a `Co-Authored-By:` trailer naming claude / anthropic / `noreply@anthropic.com`, a "Generated with [Claude Code]" marker, or a `claude.ai/code` URL — scanning the full command surface plus any `--body-file` / `-F` file contents. Closes the surface the commit gate structurally cannot see: a PR description never passes through git. (A prose mention of "claude" in a normal body still ALLOWs; `gh pr view`/`list`/`checkout`/`merge`/`comment` are not gated.) [escape hatch: no]
- **[playwright-cli-isolation-guard](../../../hooks/playwright-cli-isolation-guard.sh)** — `PreToolUse:Bash` (`playwright-cli`). Denies `playwright-cli` invocations missing the role-prefixed `-s=<slug>` isolation flag. Checks session-slug shape only, not actor identity. [escape hatch: no]
- **[protected-artifact-bash-guard](../../../hooks/protected-artifact-bash-guard.sh)** — `PreToolUse:Bash`. Denies Bash commands that mutate pipeline-state artifacts out of band (redirection, `cp`/`mv`/`rm`/`tee`/in-place editors, interpreter one-liners naming a protected artifact). Protected list includes `onboarding-status.json`, `journey-map.md`, `.phase4-cycle-state.json`, `coverage-expansion-state.json`, `.workflow-approvers.json`, `adversarial-findings.md`, `.ledger-integrity.json`, `flake-quarantine.md`, and `~/.claude/hooks` / `~/.claude/settings*.json`. Interpreter one-liners are denied only when they carry a write-shape token; a recognisable read (`json.load`, `readFileSync`, …) is allowed, and an unclassifiable interpreter one-liner mentioning a protected path yields `permissionDecision: ask`. PREVENTS the obvious shell vectors; `ledger-integrity-chain` DETECTS the rest. [escape hatch: no]

### MCP (tracker tools)

- **[adversarial-verification-gate](../../../hooks/adversarial-verification-gate.sh)** — `PreToolUse:mcp__.*` (tracker mutation tools only). Blocks QA sign-off that has not been adversarially verified. **DENY** on a ticket transition to a completed state (`done|complete|closed|resolved|shipped|released`); **WARN** on a verdict-shaped comment (`qa report`, `acceptance criteri`, `verdict`, `sign-off`, `AC-<n>`). Passes when `.achilles/adversarial-verification/<ticket>.json` exists, contains a `negativeControl` object, and is **newer than the most recently edited spec** — a receipt older than the tests it vouches for is treated as absent. Tracker reads are never gated; non-tracker MCP tools exit immediately. Defence in depth for `ticket-driven-testing` §8: the skill's own instructions do fire the check, but instructions are advisory and can be skimmed, truncated, or superseded — and a gate keyed on the ACTION is independent of whether any skill reached the agent at all. Cannot verify that a receipt is *honest* — it raises the cost of skipping from "forget" to "author a false artifact", which is the ceiling for a harness gate. [escape hatch: yes (`CIVITAS_DISABLE_ADVERSARIAL_GATE=1`)]

## PostToolUse

- **[playwright-artifact-archiver](../../../hooks/playwright-artifact-archiver.sh)** — `PostToolUse:Bash` (Playwright run commands), plus `Stop` / `SubagentStop` as the backstop for interrupted runs. Playwright wipes its `outputDir` at the START of every run and reuses per-test `test-results/<slug>/` directories, so run N's traces, videos, screenshots and `error-context.md` are destroyed by run N+1. This copies each run's evidence into `<project>/.achilles/runs/<runId>/artifacts/<original-relative-path>` with a `manifest.json` (sources + how each path was resolved, counts, bytes, skips, prunes). Copy, never move — `show-report` / `show-trace` against `test-results/` are unaffected. Paths are discovered (`--output=` on the command, then `outputDir` / html `outputFolder` / json `outputFile` in the nearest config, then `PLAYWRIGHT_JSON_OUTPUT_NAME` / `PLAYWRIGHT_JUNIT_OUTPUT_NAME` from the command line or environment, then the Playwright defaults); an unresolvable path degrades to the default and says so in the manifest. Retention keeps the newest `ACHILLES_ARTIFACT_RETAIN` runs (default 5) and prunes oldest-first; runs above `ACHILLES_ARTIFACT_MAX_MB` (default 512) archive the small evidence and skip only trace/video blobs. Nothing is ever discarded silently — every prune and skip is named in the manifest and in a `systemMessage`, and a copy that lands fewer files than intended (disk full, permissions) is marked `incomplete` and deliberately does not stamp the idempotency fingerprint, so the next invocation retries rather than treating the run as safely archived. Never denies, never deletes anything outside its own runId-shaped directories, and always exits 0: losing a run because the archiver broke is worse than losing the archive. [escape hatch: yes (`ACHILLES_ARTIFACT_RETAIN=0` disables archiving)]
- **[subagent-return-schema-guard](../../../hooks/subagent-return-schema-guard.sh)** — `PostToolUse:Agent` (WARN by default). Validates subagent returns against `schemas/subagent-returns/<role>.schema.json` via the self-contained `hooks/lib/validator.bundle.mjs` (all schemas inlined at build time) and sanity-checks the §2.0 handover envelope's `cycle` field. Role mapping lives in `hooks/lib/schema-role-map.sh` (shared with the preread gate; now maps `phase4-prioritise-author*` → `phase4-prioritise-author` and `phase4-cycle-*` → `section-agent`, and treats `phase1-*`/`stage2-*`/`cleanup-*`/`companion-*`/`fd-*` as envelope-sanity-only). Appends one JSON line per validation (`{role, valid, errors[]}`) to `<project>/.achilles/schema-guard-log.jsonl` — the dataset for the WARN→strict flip criterion (<2% false-positive over ≥200 logged validations). `SCHEMA_RETURN_GUARD=strict` promotes a failure to a blocking `exit 2`; the default stays WARN. [escape hatch: yes (`SCHEMA_RETURN_GUARD` default is non-blocking WARN)]
- **[workflow-reviewer-attestation-gate](../../../hooks/workflow-reviewer-attestation-gate.sh)** — `PostToolUse:Agent` (WARN — PostToolUse cannot deny an already-produced return). For `workflow-reviewer-*` approve verdicts: warns when the attestation + checklist evidence cite zero file-path-shaped substrings, or cite paths that do not exist on disk. Flags ungrounded approvals in the audit trail; the ledger write-gate's actor-identity check still gates the subsequent write. [escape hatch: no]

## Stop

- **[run-summary-writer](../../../hooks/run-summary-writer.sh)** — `Stop`. Writes `<project>/.achilles/run-summary.json`, the authoritative self-report consumed by external benchmark drivers (e.g. `Feyzabora/bookhive-benchmark`). Reads the artifacts the skills actually write (onboarding ledger phases, adversarial-findings ledger IDs + severity counts, journey-map headings, newest Playwright `results.json`); when no result file exists the tests block is null-statused, never a fake pass. Never blocks. [escape hatch: n/a (never denies)]
- **[perf-summary-writer](../../../hooks/perf-summary-writer.sh)** — `Stop`. Writes `<project>/.achilles/perf-summary.json`, the authoritative perf self-report for the perf-onboarding pipeline. NO-OP when `tests/perf/docs/perf-onboarding-status.json` does not exist (non-perf projects unaffected). Reads perf ledger phases + runMode, scenario files, k6 handleSummary results, and baseline snapshots; metrics and verdict are null when no result file is present — never a fabricated pass. Never blocks. [escape hatch: n/a (never denies)]
- **[selector-development-revert-on-stop](../../../hooks/selector-development-revert-on-stop.sh)** — `Stop`. Warns at orchestrator Stop when a selector-development scope is active and its receipt's last passing step is not `visual_diff` or `commit` — i.e. the pipeline stopped mid-flight; surfaces the recovery instruction. [escape hatch: no]

## SubagentStop

- **[playwright-cli-cleanup-on-stop](../../../hooks/playwright-cli-cleanup-on-stop.sh)** — `SubagentStop`. Reaps orphaned per-subagent browser sessions via `playwright-cli close-all`. Never blocks. [escape hatch: no]
