{"id":49014658,"url":"https://github.com/bookedsolidtech/rea","last_synced_at":"2026-05-13T03:07:51.574Z","repository":{"id":352239679,"uuid":"1214363694","full_name":"bookedsolidtech/rea","owner":"bookedsolidtech","description":"Zero-trust governance layer for Claude Code. Policy-enforced MCP gateway with autonomy controls, middleware chain, audit log, HALT kill-switch, and prompt-injection defense.","archived":false,"fork":false,"pushed_at":"2026-05-09T21:29:16.000Z","size":2327,"stargazers_count":0,"open_issues_count":19,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-09T23:59:53.848Z","etag":null,"topics":["agentic-ai","ai-agents","ai-governance","ai-safety","anthropic","anthropic-claude","audit-log","claude-code","developer-tools","guardrails","llm-guardrails","llm-security","mcp","mcp-gateway","mcp-server","model-context-protocol","policy-enforcement","prompt-injection","typescript","zero-trust"],"latest_commit_sha":null,"homepage":"https://github.com/bookedsolidtech/rea","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bookedsolidtech.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":"THREAT_MODEL.md","audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-18T13:25:28.000Z","updated_at":"2026-05-09T21:28:29.000Z","dependencies_parsed_at":"2026-04-23T07:00:54.782Z","dependency_job_id":"6e9091d6-db5d-4cec-9fe3-9b054f46b73f","html_url":"https://github.com/bookedsolidtech/rea","commit_stats":null,"previous_names":["bookedsolidtech/rea"],"tags_count":50,"template":false,"template_full_name":null,"purl":"pkg:github/bookedsolidtech/rea","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bookedsolidtech%2Frea","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bookedsolidtech%2Frea/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bookedsolidtech%2Frea/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bookedsolidtech%2Frea/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bookedsolidtech","download_url":"https://codeload.github.com/bookedsolidtech/rea/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bookedsolidtech%2Frea/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32965830,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-12T23:30:32.555Z","status":"online","status_checked_at":"2026-05-13T02:00:07.132Z","response_time":115,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agentic-ai","ai-agents","ai-governance","ai-safety","anthropic","anthropic-claude","audit-log","claude-code","developer-tools","guardrails","llm-guardrails","llm-security","mcp","mcp-gateway","mcp-server","model-context-protocol","policy-enforcement","prompt-injection","typescript","zero-trust"],"created_at":"2026-04-19T01:12:47.934Z","updated_at":"2026-05-13T03:07:51.557Z","avatar_url":"https://github.com/bookedsolidtech.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# REA\n\n**Agentic governance layer for Claude Code — policy enforcement, hook-based safety gates, audit logging, and a stateless pre-push Codex review gate.**\n\n[![npm version](https://img.shields.io/npm/v/%40bookedsolid%2Frea?color=cb3837\u0026label=npm)](https://www.npmjs.com/package/@bookedsolid/rea)\n[![CI](https://github.com/bookedsolidtech/rea/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/bookedsolidtech/rea/actions/workflows/ci.yml)\n[![npm provenance](https://img.shields.io/badge/npm%20provenance-attested-blue?logo=npm)](https://docs.npmjs.com/generating-provenance-statements)\n[![license](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)\n[![DCO](https://img.shields.io/badge/DCO-required-green)](https://developercertificate.org/)\n[![Node](https://img.shields.io/badge/node-%3E%3D22-brightgreen)](https://nodejs.org/)\n\n\u003e Status: `0.11.0` — published to npm with SLSA v1 provenance. See\n\u003e [CHANGELOG.md](./CHANGELOG.md) for the per-release history.\n\nREA is a single npm package that gates and audits agentic tool calls made by\nClaude Code — shell commands, filesystem writes, and MCP tool invocations —\nagainst an operator-defined policy file. It ships an MCP middleware gateway,\na set of hook scripts, a pre-push Codex review gate, a hash-chained audit\nlog, and a hard kill-switch. Every layer fails closed.\n\n**What changed in 0.11.0.** Through 0.10.x the push-review gate asked \"has a\nqualifying Codex receipt been recorded for this HEAD SHA?\" and consulted a\n`.rea/review-cache.jsonl` + audit-record lookup to decide. Agents spent a\nmeaningful fraction of every push cycle fabricating attestations with `rea\ncache set` and `rea audit record codex-review --also-set-cache`, and the\nbash core around the gate grew to ~1,250 lines. 0.11.0 deletes that stack\nand replaces it with a single subcommand — `rea hook push-gate` — that\n**runs Codex on every push**, parses the verdict from the streamed review\noutput, writes the findings to `.rea/last-review.json`, and blocks exit\ncode `2` on `[P1]` or (by default) `[P2]` findings. Readers landing on\n0.9/0.10-era docs should treat the \"record-and-cache\" flow as gone — see\nthe [migration section](#migration-from-010x) below.\n\n---\n\n## Table of contents\n\n- [Quickstart](#quickstart)\n- [What REA is](#what-rea-is)\n- [What REA is NOT](#what-rea-is-not)\n- [The pre-push Codex gate](#the-pre-push-codex-gate)\n- [MCP gateway](#mcp-gateway)\n- [Policy file](#policy-file)\n- [Hooks shipped](#hooks-shipped)\n- [Slash commands](#slash-commands)\n- [Curated agents](#curated-agents)\n- [CLI reference](#cli-reference)\n- [Migration from 0.10.x](#migration-from-010x)\n- [Contributor quality gates](#contributor-quality-gates)\n- [Threat model and security](#threat-model-and-security)\n- [Non-goals](#non-goals)\n- [License and contributing](#license-and-contributing)\n\n---\n\n## Quickstart\n\n```bash\nnpx @bookedsolid/rea init\n```\n\nThe `init` wizard detects your project, writes `.rea/policy.yaml`, copies\ncurated hooks and slash commands into `.claude/`, wires `.mcp.json` to run\n`rea serve` as a governance gateway, installs `.husky/commit-msg` and\n`.husky/pre-push` hooks, and appends a managed fragment to `CLAUDE.md`. Run\nit non-interactively with `-y`:\n\n```bash\nnpx @bookedsolid/rea init -y --profile bst-internal\n```\n\nNode 22+ and pnpm 9.12+ are required. The package is published with npm\nprovenance (SLSA v1) from the `main` branch via GitHub Actions OIDC.\n\n**Your first push.** After a feature commit, `git push` will:\n\n1. `.husky/pre-push` checks `.rea/HALT` and delegates to `rea hook push-gate`.\n2. `rea hook push-gate` loads `.rea/policy.yaml`, resolves a base ref, and\n   shells out to `codex exec review --base \u003cref\u003e --json --ephemeral`.\n3. Codex streams JSONL events back; the gate parses `[P1]`/`[P2]`/`[P3]`\n   findings out of the `agent_message` text.\n4. A severity-sorted summary is printed to stderr; full findings with file\n   and line detail are written atomically to `.rea/last-review.json`.\n5. An audit record (`rea.push_gate.reviewed`) is appended to\n   `.rea/audit.jsonl`.\n6. Exit code is `0` (pass), `1` (HALT), or `2` (blocked by verdict or\n   Codex error).\n\nOn a blocking verdict the push fails; the in-session Claude agent reads the\nstderr summary and the `.rea/last-review.json` payload, fixes the issues,\ncommits, and pushes again. No cache, no receipt to fabricate.\n\nVerify the install:\n\n```bash\nrea doctor\n```\n\nFreeze everything if something unexpected happens:\n\n```bash\nrea freeze --reason \"incident triage; investigate unexpected .env write\"\n# later\nrea unfreeze\n```\n\n---\n\n## What REA is\n\nREA is a governance layer for Claude Code. It ships four things.\n\n### 1. A policy runtime\n\n`.rea/policy.yaml`, validated by a strict zod schema — unknown fields are\n**rejected**, not ignored. The policy defines:\n\n- `autonomy_level` (L0–L3) and a hard `max_autonomy_level` ceiling\n- `blocked_paths` (globs; `.rea/` is always blocked regardless)\n- `block_ai_attribution` — enforced by the commit-msg hook\n- `review.codex_required` — whether the pre-push gate runs Codex at all\n- `review.concerns_blocks` — whether `[P2]` verdicts halt the push\n- `review.timeout_ms` — hard cap on the Codex subprocess\n- Redaction patterns, injection tuning, audit rotation, and MCP gateway knobs\n\nPolicy is re-read on every middleware invocation and every hook run. Editing\n`.rea/policy.yaml` takes effect on the next tool call — no restart, no\ncache invalidation.\n\n### 2. A kill switch\n\n`.rea/HALT` is a single file. If it exists, every governed tool call is\ndenied — the MCP gateway middleware returns an error, the bash hooks `exit\n1`, and the pre-push gate returns exit `1` with the reason printed to\nstderr. Use `rea freeze --reason \"...\"` to create it and `rea unfreeze` to\nremove it. Both operations write audit records. The middleware never\nclears HALT on its own.\n\nHALT is checked before policy in every flow. A corrupted `.rea/policy.yaml`\ndoes not prevent the kill-switch from firing.\n\n### 3. A hook layer\n\nEleven shell scripts ship in `hooks/` and are copied into `.claude/hooks/`\nby `rea init`. All eleven are wired into the default `.claude/settings.json`\nand fire on Claude Code's `PreToolUse` / `PostToolUse` events (secret\nscanning, dangerous-command interception, blocked-path enforcement,\nsettings protection, attribution rejection, env-file protection,\ndisclosure-policy routing, dependency audit, changeset security,\nPR-issue-link advisory, architecture advisory). Each hook uses\n`set -euo pipefail` (or `set -uo pipefail` for stdin-JSON consumers) and\nruns a HALT check near the top. See [Hooks shipped](#hooks-shipped) for\nthe full inventory.\n\n**Bash-tier scanner (parser-backed since 0.23.0).** Two hooks —\n`protected-paths-bash-gate.sh` and `blocked-paths-bash-gate.sh` — are\nshims that forward stdin to `rea hook scan-bash`, a CLI subcommand\nthat parses the Bash command via `mvdan-sh@0.10.1`, walks the AST,\nand emits a verdict JSON. Pre-0.23.0 these were 500-line bash regex\npipelines; the rewrite closes 24 known-bypass classes\n(helix-021..023 + discord-ops Round 13 + codex round 1) by replacing\nre-tokenization heuristics with structural matches against the parsed\nargv tree. The other nine hooks remain regex-based bash. The shim\nre-verifies the verdict JSON shape on return so a tampered\n`REA_NODE_CLI` env var cannot bypass. See\n[`docs/architecture/bash-scanner.md`](docs/architecture/bash-scanner.md)\nfor the AST-walker design and [`docs/migration/0.23.0.md`](docs/migration/0.23.0.md)\nfor consumer migration notes.\n\nThe hook layer runs independently of the MCP gateway — bypassing one does\nnot disable the other. That redundancy is intentional.\n\n### 4. An MCP gateway\n\n`rea serve` is an MCP stdio server that proxies downstream MCP servers\ndeclared in `.rea/registry.yaml` through a middleware chain. Every tool\ncall — native rea tools or proxied downstream tools — is classified,\npolicy-checked, redacted, audited, and size-capped before it executes. See\n[MCP gateway](#mcp-gateway) for the chain ordering and supervisor\nbehavior.\n\n**Plus** a stateless pre-push Codex review gate (new in 0.11.0) that fires\nvia `.husky/pre-push` on every `git push` and is covered in the next\nsection.\n\nREA does one thing: gate and audit agentic tool calls against\noperator-defined policy. That is the whole product.\n\n---\n\n## What REA is NOT\n\nThese are non-goals. PRs adding any of these will be closed with a pointer\nto build a separate package that composes with REA.\n\n- **Not a project manager.** No task CRUD, no GitHub issue sync, no board\n  scaffolding.\n- **Not an Obsidian integration.** No vault journaling, no note creation,\n  no pre/post-compact hooks.\n- **Not an account manager.** No `rea account` tree, no Keychain, no OAuth,\n  no multi-tenant token vault. Env vars only.\n- **Not a Discord bot.** A Discord webhook URL in `policy.yaml` is the\n  entire surface area — one outbound POST, opt-in, no MCP tools.\n- **Not a daemon supervisor.** `rea serve` is started by Claude Code via\n  `.mcp.json`. Claude Code owns the lifecycle. There is no `rea start`,\n  no `rea stop`, no systemd unit.\n- **Not a hosted service.** No REA Cloud, no SaaS tier, no multi-tenant\n  workload isolation.\n- **Not a 70-agent roster.** 23 curated agents ship in the package.\n  Profiles layer additional specialists.\n- **Not a full policy engine.** No OPA/Rego, no CEL, no attribute-based\n  access control. A YAML file with a small, fixed schema is the entire\n  policy language.\n- **Not a CI replacement.** REA gates agent behavior at author time. CI\n  still runs lint, typecheck, tests, and build on every PR.\n- **Not a secret manager.** REA detects secrets in writes and redacts them\n  in audit records; it does not store, rotate, or provision them.\n\nThe non-goals are the product.\n\n---\n\n## The pre-push Codex gate\n\nThe 0.11.0 gate is stateless. Every `git push` runs Codex on the diff, and\nthe gate's decision is a function of the review output — not of a cached\nreceipt or an audit record from a prior run.\n\n### Flow\n\n```\n$ git push\n    │\n    ▼\n┌─────────────────────────────────────────────────────────┐\n│ .husky/pre-push                                         │\n│   1. Check .rea/HALT — exit 1 if present                │\n│   2. Locate rea binary (node_modules, dist, PATH, npx)  │\n│   3. exec rea hook push-gate \"$@\"                       │\n└─────────────────────────────────────────────────────────┘\n    │\n    ▼\n┌─────────────────────────────────────────────────────────┐\n│ rea hook push-gate                                      │\n│   1. HALT check (again, defense-in-depth)               │\n│   2. Load .rea/policy.yaml (zod-validated)              │\n│   3. codex_required=false → status:disabled, exit 0     │\n│   4. REA_SKIP_PUSH_GATE / REA_SKIP_CODEX_REVIEW=\u003creason\u003e│\n│      → skipped, exit 0 (audit records skip_var)         │\n│   5. Parse pre-push stdin refspecs                      │\n│   6. Resolve base ref (--base → --last-n-commits N      │\n│      → policy.review.last_n_commits → refspec →         │\n│      upstream → origin/HEAD → main/master → empty-tree) │\n│   7. Empty-diff check → status:empty-diff, exit 0       │\n│   8. codex exec review --base \u003cref\u003e --json --ephemeral  │\n│   9. Parse [P1]/[P2]/[P3] findings                      │\n│  10. Infer verdict: P1 → blocking; else P2 → concerns;  │\n│      else pass                                          │\n│  11. Atomic write .rea/last-review.json (redacted)      │\n│  12. Render stderr banner                               │\n│  13. Append audit record rea.push_gate.reviewed         │\n│  14. Exit 0 (pass/disabled/skipped/empty-diff) |        │\n│       1 (HALT) | 2 (blocked, timeout, or error)         │\n└─────────────────────────────────────────────────────────┘\n```\n\n### Verdicts and exit codes\n\n| Verdict | Default behavior | Exit code | Notes |\n| --- | --- | --- | --- |\n| `pass` | Push proceeds | `0` | No `[P1]` or `[P2]` findings in the review |\n| `concerns` | Push blocks (default) | `2` | `[P2]` findings present; override with `REA_ALLOW_CONCERNS=1` or `review.concerns_blocks: false` |\n| `blocking` | Push blocks always | `2` | `[P1]` findings present; no override |\n| HALT | Push blocks | `1` | `.rea/HALT` is active; run `rea unfreeze` |\n| `disabled` | Push proceeds | `0` | `review.codex_required: false` in policy |\n| `skipped` | Push proceeds | `0` | `REA_SKIP_PUSH_GATE=\u003creason\u003e` or `REA_SKIP_CODEX_REVIEW=\u003creason\u003e` set; audited |\n| `empty-diff` | Push proceeds | `0` | No file changes between base and head |\n| `error` | Push blocks | `2` | Codex not installed, timeout, subprocess error, malformed policy, head-sha resolution failure |\n\n### The auto-fix loop\n\nPrevious gate: pre-run Codex manually, record an attestation with `rea\naudit record codex-review --also-set-cache`, push, and hope the\nattestation's SHA matches the tip. Agents working at speed ended up\nfabricating attestations or running Codex out-of-band and recording the\nverdict without anyone actually reading the output. Friction was paid on\nevery push.\n\nNew gate: the gate **is** the review. Codex runs on the same diff the push\nis about to send, so the verdict is causally tied to the push. When the\ngate blocks:\n\n1. The stderr banner prints the verdict, base ref, head SHA, finding\n   count, duration, and up to 20 severity-sorted findings with file:line\n   pointers. Because the pre-push hook's stderr reaches Claude as the\n   tool output of `Bash(git push)`, the banner is the primary fast-path\n   signal for the in-session agent.\n2. `.rea/last-review.json` is written atomically with the full findings,\n   each carrying `severity`, `title`, `body`, and optional `file`/`line`.\n   This file is the source of truth for the auto-fix loop — the stderr\n   banner is capped at 20 findings; the JSON is not.\n3. Claude reads both, applies fixes, commits (with `-s` and no AI\n   attribution), and pushes again. The gate runs Codex fresh on the new\n   diff. Repeat until `pass`.\n\nSee [CHANGELOG 0.11.0](./CHANGELOG.md) for the longer rationale on why\nthe cache-attestation design was removed.\n\n### `.rea/last-review.json` schema\n\n```jsonc\n{\n  \"schema_version\": 1,\n  \"generated_at\": \"2026-04-22T18:04:01.123Z\",\n  \"verdict\": \"blocking\",                 // \"pass\" | \"concerns\" | \"blocking\"\n  \"base_ref\": \"origin/main\",\n  \"head_sha\": \"c5ec101…\",\n  \"finding_count\": 3,\n  \"findings\": [\n    {\n      \"severity\": \"P1\",                  // \"P1\" | \"P2\" | \"P3\"\n      \"title\": \"missing input validation on /auth/callback\",\n      \"file\": \"src/routes/auth.ts\",      // optional\n      \"line\": 42,                        // optional\n      \"body\": \"The callback accepts raw state without…\"\n    }\n    // …\n  ],\n  \"review_text\": \"[P1] missing input validation…\\n[P2] …\",\n  \"event_count\": 37,\n  \"duration_seconds\": 12.4\n}\n```\n\nThe file is:\n\n- **Atomic.** Written to `.rea/last-review.json.tmp.\u003cpid\u003e-\u003crand\u003e`, fsynced,\n  then `rename(2)`d. Partial writes never surface to readers.\n- **Redacted.** Both `findings[].title`/`body` and `review_text` are run\n  through the same `SECRET_PATTERNS` list the redact middleware uses. If\n  Codex quotes a credential out of the diff it never hits disk in cleartext.\n- **Overwritten every push.** There is no rolling history on disk; the\n  audit log is the rolling history.\n- **Gitignored.** The default `rea init` install adds `/.rea/last-review.json`\n  to `.gitignore`.\n\n### Environment variables\n\n| Variable | Purpose |\n| --- | --- |\n| `REA_SKIP_PUSH_GATE=\u003creason\u003e` | Value-carrying waiver. When set to a non-empty string, the gate short-circuits to `status:skipped` (exit 0) and appends `rea.push_gate.skipped` with the reason and `skip_var: REA_SKIP_PUSH_GATE` as metadata. HALT **always** wins over this — a frozen install still blocks. Use sparingly; every use is audited. |\n| `REA_SKIP_CODEX_REVIEW=\u003creason\u003e` | Equivalent alias for `REA_SKIP_PUSH_GATE`, added in 0.12.0. Same exit behavior; audit metadata records `skip_var: REA_SKIP_CODEX_REVIEW` so operators can grep their audit log to see which variant agents used. When both env vars are set, `REA_SKIP_PUSH_GATE` wins. |\n| `REA_ALLOW_CONCERNS=1` | One-push override for `concerns` verdict. Accepts `1`, `true`, or `yes` (case-insensitive). Does **not** override `blocking`. The audit record is stamped `concerns_override: true` so reviewers can see the override was used. |\n\n### Policy knobs\n\n```yaml\n# .rea/policy.yaml\nreview:\n  codex_required: true        # default true — run Codex on every push\n  concerns_blocks: true       # default true — [P2] halts the push\n  timeout_ms: 1800000         # default 1800000 (30 minutes; raised from\n                              #   600000 in 0.12.0 — see CHANGELOG)\n  last_n_commits: 10          # OPTIONAL — narrow review to the last N commits\n                              #   (diff vs HEAD~N). Defaults unset.\n  auto_narrow_threshold: 30   # OPTIONAL — auto-narrow when commit count\n                              #   behind base \u003e N (0 disables, default 30)\n```\n\n| Key | Type | Default | Purpose |\n| --- | --- | --- | --- |\n| `review.codex_required` | boolean | `true` | Master on/off. `false` short-circuits the gate to `status:disabled`, still audited. `-no-codex` profiles set this to `false`. |\n| `review.concerns_blocks` | boolean | `true` | When `true`, `[P2]` verdicts return exit 2. Flip to `false` for a looser posture where only `[P1]` halts the push. |\n| `review.timeout_ms` | number | `1800000` | Hard cap on the `codex exec review` subprocess in milliseconds. Exceeding it kills the subprocess and returns exit 2 with a `timeout` kind. Positive integer; zero/negative is rejected at load. **Raised from 600000 (10 min) to 1800000 (30 min) in 0.12.0** after operator data showed realistic feature-branch reviews routinely exceeded 10 minutes; pin `timeout_ms: 600000` explicitly to retain the old default. |\n| `review.last_n_commits` | number | unset | When set, the gate diffs against `HEAD~N` instead of running the upstream → origin/HEAD → main/master ladder. Useful when a feature branch has accumulated many commits and the full base diff overwhelms the reviewer. Positive integer. CLI `--last-n-commits N` overrides this; `--base \u003cref\u003e` overrides both. When `HEAD~N` is unreachable the resolver clamps based on whether the repo is a shallow clone: **(full clone, branch shorter than N)** clamps to the empty-tree sentinel so the root commit's changes are included (reviewing all `K+1` commits on the branch); **(shallow clone)** clamps to `HEAD~K` SHA — the deepest locally resolvable ancestor — so the review does not balloon to every tracked file (older history exists on the remote but isn't fetched). A stderr warning surfaces the requested-vs-clamped numbers in both cases. Audit metadata records `base_source: 'last-n-commits'`, `last_n_commits: \u003ccount actually reviewed\u003e`, and `last_n_commits_requested: N` (only present when clamped). |\n| `review.auto_narrow_threshold` | number | `30` | Added in **0.13.0**. When the resolved diff base is more than N commits behind HEAD AND the base was resolved from the active refspec's `remoteSha` (i.e. previously-pushed remote tip of this branch — commits already Codex-reviewed) AND no explicit narrowing was set, the gate auto-scopes to the last 10 commits and emits a stderr warning. Set to `0` to disable. **Suppressed** when any of `--base`, `--last-n-commits`, `policy.review.last_n_commits`, OR the base was resolved via the upstream / origin-head / origin-main ladder (initial push, no upstream, fallback to trunk). Auto-narrow never fires on initial pushes — earlier commits on the branch may not have been reviewed yet, and skipping past them would silently bypass the gate's coverage contract. Audit metadata records `auto_narrowed: true` and `original_commit_count: N` so operators can grep for narrowed reviews. Background: large feature branches (50+ commits relative to a previously-pushed tip) routinely produced non-deterministic Codex verdicts and 30-minute timeouts; J makes the protective default automatic without compromising first-push coverage. |\n\n### Auto-narrow on large divergence (0.13.0)\n\nWhen pushing a long-running branch that has already been pushed before (so\nthe remote tip is the previously-reviewed Codex baseline), follow-up\npushes that pile up many commits since the last push can timeout the\nreviewer or produce inconsistent verdicts. **Auto-narrow** detects this\ncase and scopes the review down to recent commits automatically:\n\n```\n$ git push origin feature/big-thing\nrea: auto-narrow — 80 commits behind \u003cprevious-remote-tip-sha\u003e (threshold 30);\n  reviewing the last 10 commits instead.\n  Override: pass `--last-n-commits N` or `--base \u003cref\u003e`, set\n  `review.last_n_commits` in .rea/policy.yaml, or disable with\n  `review.auto_narrow_threshold: 0`.\n```\n\nThe probe runs `git rev-list --count base..HEAD` after base resolution.\n**Auto-narrow only fires when the base was resolved from the active\nrefspec's `remoteSha`** — i.e. the previously-pushed tip of this branch,\nwhere the older commits have already been Codex-reviewed in a prior push.\nInitial pushes (where the resolver falls back to `origin/main` or the\nupstream ladder) are NEVER auto-narrowed: skipping past those earlier\ncommits would silently bypass the advertised pre-push review for any\nhook/policy/security change made early in the branch.\n\nWhen eligible and the count exceeds `review.auto_narrow_threshold`\n(default 30) and no narrowing override is in effect, the gate re-resolves\nto `HEAD~10` and proceeds with the smaller diff. Every reviewed event\nincludes `auto_narrowed: true` + `original_commit_count: \u003cN\u003e` in audit\nmetadata.\n\nTo opt out for one push: pass `--last-n-commits N` or `--base \u003cref\u003e`. To\nopt out persistently: set `review.last_n_commits` (any value), or set\n`review.auto_narrow_threshold: 0`.\n\n### Extension-hook chaining (0.13.0)\n\nDrop executable scripts into `.husky/commit-msg.d/` or `.husky/pre-push.d/`\nand rea will run them after its own governance work, in lexical order, with\nthe same positional args. Useful for layering commitlint, conventional-\ncommits linters, branch-policy checks, or any other per-commit / per-push\nwork without losing rea coverage.\n\n```bash\nmkdir -p .husky/pre-push.d\ncat \u003e .husky/pre-push.d/10-commitlint \u003c\u003c'EOF'\n#!/bin/sh\n# Verify every new commit on the pushed range has a conventional message.\nexec npx --no-install commitlint --from \"origin/main\" --to \"HEAD\"\nEOF\nchmod +x .husky/pre-push.d/10-commitlint\n```\n\nRules:\n\n- **Sourced AFTER rea's body** — HALT, attribution blocking, and Codex\n  review run first; fragments only fire when rea succeeds. A non-zero exit\n  from rea short-circuits before any fragment runs.\n- **Lexical order** — `10-foo` runs before `20-bar` runs before `90-baz`.\n  The standard convention is to prefix with a two-digit ordering number.\n- **Executable bit gates** — only files with `chmod +x` are run. A README\n  or `.disabled` file in the directory is silently skipped.\n- **Non-zero exit fails the hook** — the next fragment does not run, the\n  push / commit is blocked. This matches husky's normal hook chaining\n  semantics.\n- **Missing directory is a no-op** — backward compatible with consumers\n  who never opt into fragments.\n- **Fragments cannot replay pre-push stdin** — git delivers refspec data\n  on stdin which rea consumes during its own review. Fragments that need\n  refspec data should run before rea (use a custom hook in\n  `core.hooksPath` instead). Fragments that need ambient repo state can\n  call `git rev-parse` themselves.\n\n`rea doctor` lists every fragment it sees and warns when a non-executable\nfile is sitting in either directory (silently skipped at hook-fire time).\n\n### Codex CLI dependency\n\nThe gate shells out to `codex`. **`codex` is a hard prerequisite** when\n`policy.review.codex_required: true` (the default for every profile other\nthan the `-no-codex` variants). As of 0.12.0 `rea doctor` runs a\n`codex CLI on PATH` check that **fails** when codex is required by policy\nbut the binary is not on `PATH` — surfacing the prereq during install\nrather than at first push:\n\n```\n[fail] codex CLI on PATH\n       codex not found on PATH. policy.review.codex_required: true requires\n       the codex binary. Install: https://github.com/openai/codex\n       (e.g. `npm i -g @openai/codex`). To disable the push-gate instead,\n       set policy.review.codex_required: false in .rea/policy.yaml.\n```\n\nIf a push is attempted without codex on PATH, the gate also returns exit 2\nwith the same install hint:\n\n```\ncodex CLI not found on PATH. Install with `npm i -g @openai/codex`,\nor set `review.codex_required: false` in .rea/policy.yaml to disable\nthe push-gate.\n```\n\nOperators who do not have Codex available can either:\n\n- Run `rea init --profile bst-internal-no-codex` (or `open-source-no-codex`),\n  which sets `review.codex_required: false` on install.\n- Flip `review.codex_required: false` in an existing policy file.\n\n### Standalone usage\n\n`rea hook push-gate` is invoked by `.husky/pre-push`, but it is also a\nfirst-class CLI. Run it manually to test a review without pushing:\n\n```bash\n# Review the working tree against the resolved base (@{upstream}, else\n# origin/HEAD, else main/master, else empty-tree).\nrea hook push-gate\n\n# Review against an explicit base.\nrea hook push-gate --base origin/main\nrea hook push-gate --base refs/remotes/upstream/main\n\n# Narrow the review to the last N commits (diff vs HEAD~N). Loses to\n# --base when both are set; mirrors policy.review.last_n_commits.\nrea hook push-gate --last-n-commits 10\n```\n\nExit codes match the pre-push contract. The JSON payload is written to\n`.rea/last-review.json` regardless of invocation context.\n\n### What happens to a protected ref?\n\nThe gate has no concept of protected vs. unprotected branches; it reviews\nwhatever diff git is about to push. Protect-main is enforced by GitHub\nbranch protection (required status checks, required reviews, no direct\npushes to `main`), not by the gate. The gate's job is to surface blocking\nissues before the push reaches the remote.\n\n---\n\n## MCP gateway\n\n`rea serve` is an MCP stdio server. Claude Code starts it via `.mcp.json`\nat the start of a session; it runs for the life of that session. The\nserver proxies downstream MCP servers declared in `.rea/registry.yaml`\nthrough a fixed middleware chain.\n\n### Middleware chain\n\nEvery native rea tool call AND every proxied downstream call flows through\none chain. The order matters — each layer fails closed.\n\n```\ntool call\n    │\n    ▼\n┌───────────────────────────────────────────────────┐\n│ audit.enter        — hash-chained record start    │\n│ kill-switch        — deny if .rea/HALT exists     │\n│ tier               — read/write/destructive class │\n│ policy             — autonomy gate (L0–L3)        │\n│ blocked-paths      — .rea/ + operator paths       │\n│ rate-limit         — token bucket per server      │\n│ circuit-breaker    — trip on downstream failure   │\n│ injection (args)   — prompt-injection in args     │\n│ redact (args)      — secrets in arguments         │\n│                                                   │\n│ ==== EXECUTE ====                                 │\n│                                                   │\n│ result-size-cap    — bounded response             │\n│ redact (result)    — secrets in result            │\n│ injection (result) — prompt-injection in result   │\n│ audit.exit         — hash-chained record close    │\n└───────────────────────────────────────────────────┘\n    │\n    ▼\nresult\n```\n\n`.rea/` is hardcoded as an always-blocked path. It cannot be unblocked from\npolicy. Policy is re-read on every invocation — any edit to `policy.yaml`\ntakes effect on the next tool call.\n\n### `__rea__health` meta-tool\n\nThe gateway advertises a single built-in tool, `__rea__health`, in every\n`listTools` response. Calling it returns gateway version, uptime, HALT\nstate, policy summary, and per-downstream health. The handler\n**short-circuits the middleware chain** — it is callable under HALT and at\nany autonomy level — because it is the tool an operator reaches for when\neverything else is frozen. Every invocation still writes an audit record.\n\nThe wire response is sanitized by default: `halt_reason` and\n`downstreams[].last_error` surface as `null`. Full detail lives in the\naudit record. Operators who genuinely need error strings on the MCP wire\ncan opt in via `policy.gateway.health.expose_diagnostics: true`; the\nshort-circuit still runs the full redact + injection-classify sanitizer\npass before emitting.\n\n### Audit log\n\n`.rea/audit.jsonl` is a hash-chained, append-only JSONL file. Each record\nis a single line with:\n\n- `seq` — monotonic integer\n- `ts` — ISO-8601 UTC\n- `session_id` — generated at `rea serve` boot\n- `server_name`, `tool_name`, `tier` (`read` | `write` | `destructive`)\n- `status` (`allowed` | `denied` | `error`)\n- `metadata` — tool-specific structured fields (argument digest, target,\n  deny reason, verdict)\n- `prev_hash` — SHA-256 of the previous record; tampering is detectable by\n  `rea audit verify`\n\nRecords are redacted on write (secrets swapped for `[REDACTED:*]`,\ninjection payloads swapped for `INJECTION_REDACTED_PLACEHOLDER`), never\nLLM-reachable. Rotation is policy-driven (`policy.audit.rotation.max_bytes`\nand/or `max_age_days`); rotation preserves the hash chain by seeding the\nnew file with a rotation marker record.\n\n### TOFU drift detection\n\nDownstream MCP servers are fingerprinted on first sight and stored in\n`.rea/fingerprints.json`. On every `rea serve` boot, each server's canonical\nshape (command path, env-key set, vault list) is hashed and compared\nagainst the stored fingerprint:\n\n- `first-seen` — new server; fingerprint recorded.\n- `unchanged` — match; proceed.\n- `drifted` — mismatch; fail-close. The operator uses `rea tofu list` to\n  inspect and `rea tofu accept \u003cname\u003e --reason \"...\"` to rebase.\n\nThe drift-accept operation appends a `tofu.drift_accepted_by_cli` audit\nrecord with the reason. The next boot classifies the server as\n`unchanged`.\n\n### Downstream environment safety\n\n`rea serve` does **not** forward `process.env` wholesale. Each downstream\nchild gets:\n\n1. A fixed allowlist of neutral OS vars (`PATH`, `HOME`, `TZ`,\n   `NODE_OPTIONS`, …).\n2. Names opted into via `registry.yaml#servers[].env_passthrough` — the\n   schema refuses secret-looking names (`*_TOKEN`, `*_KEY`, `*_SECRET`, …),\n   so secrets must be named explicitly.\n3. Values from the registry's `env:` mapping, which may contain `${VAR}`\n   placeholders resolved against the host environment. A `${VAR}` whose\n   host variable is unset is treated as fatal — the downstream is marked\n   unhealthy rather than handed an unresolved placeholder.\n\n### Live state\n\n`.rea/serve.state.json` is the on-disk live snapshot. It is written once\nat boot and again on every circuit transition or supervisor event,\ndebounced through a 250 ms trailing timer and flushed atomically via\ntemp-file + rename. `rea status` reads this file to render a\nper-downstream table; a new `rea serve` whose predecessor crashed can\ndetect the abandoned file and take over ownership rather than stalling.\n\n### Optional Prometheus metrics\n\n`rea serve` can expose a loopback-only Prometheus endpoint when\n`REA_METRICS_PORT` is set:\n\n```bash\nREA_METRICS_PORT=9464 rea serve\ncurl http://127.0.0.1:9464/metrics\n```\n\nMetrics: per-downstream call and error counters, in-flight gauge,\naudit-lines-appended counter, circuit-breaker state gauge, and a\nseconds-since-last-HALT-check gauge. The listener binds to `127.0.0.1`\nonly, serves only `GET /metrics`, and never binds by default. No TLS;\nscrape through SSH or a reverse proxy for cross-host access.\n\n---\n\n## Policy file\n\n`.rea/policy.yaml` fields. The schema is zod-strict — unknown fields are\nrejected at parse time, not ignored.\n\n### Required fields\n\n| Field | Type | Purpose |\n| --- | --- | --- |\n| `version` | `\"1\"` | Schema version; only `\"1\"` accepted in the current major |\n| `profile` | string | Profile name (see below) |\n| `installed_by` | string | Stamped by `rea init` — identifies the installing version |\n| `installed_at` | ISO-8601 | Stamped by `rea init` — install timestamp |\n| `autonomy_level` | `L0` \\| `L1` \\| `L2` \\| `L3` | Current autonomy. `L0` = read-only; `L3` = full tool access |\n| `max_autonomy_level` | `L0` \\| `L1` \\| `L2` \\| `L3` | Hard ceiling. `autonomy_level` cannot exceed this |\n| `promotion_requires_human_approval` | boolean | Require operator confirmation to raise autonomy |\n| `block_ai_attribution` | boolean | Enforce no-AI-attribution in commits and PR bodies |\n| `blocked_paths` | string[] | Glob patterns. `.rea/` is always blocked regardless |\n| `notification_channel` | string | Optional Discord webhook URL; empty string = disabled |\n\n### Optional blocks\n\n```yaml\ninjection_detection: block        # \"block\" | \"warn\" — legacy 0.2.x knob\ninjection:\n  suspicious_blocks_writes: true  # suspicious verdict on write/destructive tier denies\ncontext_protection:\n  delegate_to_subagent:\n    - pnpm run build\n    - pnpm run test\n  max_bash_output_lines: 100\nreview:\n  codex_required: true\n  concerns_blocks: true\n  timeout_ms: 1800000\n  # last_n_commits: 10            # optional — narrow review to HEAD~N\n  # auto_narrow_threshold: 30     # optional — auto-narrow when commits\n                                   # behind base \u003e N (0 disables, default 30)\nredact:\n  match_timeout_ms: 100\n  patterns:\n    - name: custom-api-key\n      regex: 'acme_[A-Za-z0-9]{32}'\n      flags: 'g'\naudit:\n  rotation:\n    max_bytes: 52428800           # 50 MiB\n    max_age_days: 30\ngateway:\n  health:\n    expose_diagnostics: false\n```\n\nUser-supplied `redact.patterns[]` are validated via `safe-regex` at load —\nany pattern flagged unsafe fails the load with a specific error naming\nthe offender.\n\n### Autonomy levels\n\n| Level | Effect |\n| --- | --- |\n| `L0` | Read-only — every write/destructive tier call denies |\n| `L1` | Default. Reads allowed; writes allowed; destructive tier denied |\n| `L2` | Writes and destructive tier allowed |\n| `L3` | No autonomy gate — only hook-layer and policy-layer checks remain |\n\n`autonomy_level \u003e max_autonomy_level` is rejected at parse time.\n`promotion_requires_human_approval: false` requires the CLI flag\n`--i-understand-the-risks` on any operation that raises autonomy.\n\n### Profiles\n\nSeven profiles ship in `profiles/`. The profile name is recorded in\n`policy.yaml#profile` and governs which agents `rea init` copies and what\ndefaults apply.\n\n| Profile | Intended use | Codex default |\n| --- | --- | --- |\n| `minimal` | Smallest possible install — curated 23 + opinionated minimal hooks | `true` |\n| `client-engagement` | Consulting engagement where the repo is client-owned | `true` |\n| `bst-internal` | Booked Solid internal projects; conservative posture | `true` |\n| `bst-internal-no-codex` | Same as above; no Codex CLI available | `false` |\n| `lit-wc` | Lit web-component library projects | `true` |\n| `open-source` | OSS library / CLI projects; liberal but audited | `true` |\n| `open-source-no-codex` | Same; no Codex CLI available | `false` |\n\nThe `-no-codex` variants default `review.codex_required: false` on\ninstall so teams without a Codex bench get a first-class opt-out. Flip\n`--codex` / `--no-codex` on the `rea init` command line to override.\n\n---\n\n## Hooks shipped\n\nFourteen hooks ship in `hooks/` and are copied into `.claude/hooks/` by\n`rea init`. All fourteen are wired by default in the shipped\n`.claude/settings.json`.\n\n| Hook | Event | Purpose | Default |\n| --- | --- | --- | --- |\n| `dangerous-bash-interceptor.sh` | `PreToolUse: Bash` | Block categories of destructive shell commands (`rm -rf`, `git reset --hard`, `--no-verify`, …) | Registered |\n| `env-file-protection.sh` | `PreToolUse: Bash` | Block reads of `.env*` files | Registered |\n| `dependency-audit-gate.sh` | `PreToolUse: Bash` | Verify packages exist on the registry before install | Registered |\n| `security-disclosure-gate.sh` | `PreToolUse: Bash` | Route security-keyword `gh issue create` to private disclosure | Registered |\n| `pr-issue-link-gate.sh` | `PreToolUse: Bash` | Advisory warn when `gh pr create` has no linked issue | Registered |\n| `attribution-advisory.sh` | `PreToolUse: Bash` | Block commits/PRs containing AI attribution markers | Registered |\n| `protected-paths-bash-gate.sh` | `PreToolUse: Bash` | Bash-tier parity with `settings-protection.sh` — refuses shell writes to `.claude/`/`.husky/`/policy paths (0.21.0+) | Registered |\n| `blocked-paths-bash-gate.sh` | `PreToolUse: Bash` | Bash-tier parity with `blocked-paths-enforcer.sh` — refuses shell writes to `blocked_paths` policy entries (0.22.0+) | Registered |\n| `local-review-gate.sh` | `PreToolUse: Bash` | Refuse `git push` (and optionally `git commit`) until a recent `rea.local_review` audit entry covers HEAD (0.26.0+) | Registered |\n| `secret-scanner.sh` | `PreToolUse: Write\\|Edit\\|MultiEdit\\|NotebookEdit` | Scan file writes for credential patterns | Registered |\n| `settings-protection.sh` | `PreToolUse: Write\\|Edit\\|MultiEdit\\|NotebookEdit` | Block agent writes to `.claude/settings.json`, hook dirs, policy | Registered |\n| `blocked-paths-enforcer.sh` | `PreToolUse: Write\\|Edit\\|MultiEdit\\|NotebookEdit` | Enforce `blocked_paths` from policy | Registered |\n| `changeset-security-gate.sh` | `PreToolUse: Write\\|Edit\\|MultiEdit\\|NotebookEdit` | Guard changesets against GHSA leaks and malformed frontmatter | Registered |\n| `architecture-review-gate.sh` | `PostToolUse: Write\\|Edit\\|MultiEdit\\|NotebookEdit` | Flag edits crossing architectural boundaries (advisory) | Registered |\n\nThe 0.10.x review-gate scripts (`push-review-gate.sh`,\n`push-review-gate-git.sh`, `commit-review-gate.sh`) and the 1,250-line\nshared bash core (`hooks/_lib/push-review-core.sh`) were removed in\n0.11.0. The `hooks/_lib/` directory now contains only the three shared\nhelpers — `common.sh`, `halt-check.sh`, `policy-read.sh` — used by the\nremaining hooks.\n\nEvery hook uses `set -euo pipefail` (or `set -uo pipefail` for stdin-JSON\nconsumers) and performs a HALT check near the top. Both the hook layer\nand the MCP gateway middleware fail closed; bypassing one does not\ndisable the other.\n\n---\n\n## Slash commands\n\nFive commands ship in `commands/` and are copied into `.claude/commands/`\nby `rea init`.\n\n| Command | Purpose |\n| --- | --- |\n| `/rea` | Session status — autonomy level, HALT state, recent audit entries, next action |\n| `/review` | Invoke the `code-reviewer` agent on current changes |\n| `/codex-review` | Invoke the `codex-adversarial` agent via the Codex plugin |\n| `/freeze` | Prompt for a reason and write `.rea/HALT` |\n| `/halt-check` | Smoke test — verify every hook and middleware respects HALT |\n\n---\n\n## Curated agents\n\n23 specialist agents ship in `agents/` and are copied into `.claude/agents/`\nby `rea init`. Profiles layer additional specialists on top for specific\nproject shapes.\n\n| Agent | When to use |\n| --- | --- |\n| `rea-orchestrator` | **First stop for any non-trivial task.** Reads policy, checks HALT, routes to the right specialist(s), coordinates multi-step work, enforces the plan/build/review loop. |\n| `principal-engineer` | Cross-module structural decisions, architectural pivots, \"patch vs redesign\" calls; reviews direction, not code. |\n| `principal-product-engineer` | Translates consumer signal into engineering priority; canary-vs-broad rollout calls. |\n| `release-captain` | Release readiness, changelog quality, breaking-change disclosure, rollback plan, post-publish verification. |\n| `security-architect` | Threat model, trust boundaries, defense-in-depth strategy; maintains `THREAT_MODEL.md`. |\n| `data-architect` | Schema design, migrations, persisted-shape evolution; owns audit-log fields, last-review.json, policy.yaml field shape. |\n| `platform-architect` | Build, CI, packaging, publish pipeline integrity; owns GitHub Actions, npm provenance, Changesets VP flow, vitest pool config. |\n| `devex-architect` | Consumer install experience; owns `rea init` / `rea upgrade` topology, `rea doctor` output, hook error message contract, the install idempotency invariant. |\n| `code-reviewer` | Structured review of a working-tree diff; surfaces correctness, clarity, and consistency issues without adversarial framing. |\n| `codex-adversarial` | Adversarial review via the Codex plugin (`/codex:adversarial-review`). Independent model perspective; produces an audit entry with verdict. |\n| `security-engineer` | Security-sensitive implementation and review — auth flows, secret handling, injection surfaces. |\n| `accessibility-engineer` | WCAG review, ARIA semantics, keyboard navigation, screen-reader fact-checking. |\n| `typescript-specialist` | Strict-mode TypeScript correctness, generics, narrowing, inference edge cases. |\n| `frontend-specialist` | UI component work, framework idioms (React, Lit, Astro), CSS architecture. |\n| `backend-engineer` | API design, database schema, background jobs, MCP server implementation. |\n| `ast-parser-specialist` | Shell grammars (mvdan-sh AST), parser quirks, AST-walker patterns; the parser-tier counterpart to shell-scripting-specialist. |\n| `shell-scripting-specialist` | POSIX + bash 3.2 (macOS) hook bodies, awk portability across BSD/GNU/mawk, `_lib/cmd-segments.sh` quote-mask logic. |\n| `adversarial-test-specialist` | Bypass corpus, sibling-class sweep methodology, \"for every closure, find the X-prime that's still open\" reasoning. |\n| `mcp-protocol-specialist` | Model Context Protocol mechanics, `@modelcontextprotocol/sdk` usage, stdio/streamable-HTTP transports, MCP-vs-Bash-tier hook matcher semantics. |\n| `observability-specialist` | Audit-log shape, event vocabulary, hash-chain integrity, structured-logging contracts, SLSA provenance pipeline. |\n| `figma-dx-specialist` | Figma's coding surfaces (Dev Mode, Code Connect, plugin/REST APIs, Variables, DTCG export, Figma-as-MCP); primary consumer is create-helix-app. |\n| `qa-engineer` | Test strategy, fixture design, regression reproducers, flake triage. |\n| `technical-writer` | User-facing documentation, API references, migration guides, changelog narratives. |\n\nThe `rea-orchestrator` is the single entry point for non-trivial tasks.\nThe CLAUDE.md fragment installed by `rea init` instructs the host agent\nto route there first; delegation contracts are defined in each agent's\nmarkdown file.\n\n---\n\n## CLI reference\n\n```\nrea \u003ccommand\u003e [options]\n```\n\nRun `rea \u003ccommand\u003e --help` for full per-command options.\n\n### `rea init`\n\nInteractive wizard — write `.rea/policy.yaml`, install `.claude/`, the\ncommit-msg hook, and a CLAUDE.md fragment.\n\n```bash\nrea init\nrea init -y --profile bst-internal       # non-interactive\nrea init --from-reagent                  # migrate from .reagent/\nrea init --profile open-source-no-codex  # disable Codex by default\nrea init --force                         # overwrite existing artifacts\n```\n\n### `rea upgrade`\n\nSync `.claude/`, `.husky/`, and managed fragments with this rea version.\nPrompts on drift; silently refreshes unmodified files.\n\n```bash\nrea upgrade --dry-run   # show what would change; write nothing\nrea upgrade             # interactive\nrea upgrade -y          # non-interactive, keep drifted files\nrea upgrade --force     # non-interactive, overwrite drift\n```\n\n### `rea serve`\n\nStart the MCP gateway. Invoked by Claude Code via `.mcp.json`; not a\ndaemon. Stdio transport only.\n\n```bash\nrea serve\nREA_METRICS_PORT=9464 rea serve\nREA_LOG_LEVEL=debug rea serve\n```\n\n### `rea freeze` / `rea unfreeze`\n\nWrite or remove `.rea/HALT`. Every call writes an audit record.\n\n```bash\nrea freeze --reason \"incident triage\"\nrea unfreeze\nrea unfreeze -y   # skip confirmation\n```\n\n### `rea check`\n\nOn-disk status — autonomy, HALT, profile, recent audit entries. No live\nprocess probe.\n\n### `rea status`\n\nRunning-process view — reads `.rea/serve.pid` + `.rea/serve.state.json`\nto render per-downstream health.\n\n```bash\nrea status\nrea status --json   # pipe to jq\n```\n\n### `rea doctor`\n\nValidate the install — policy parses, `.rea/` layout, hooks, Codex plugin\npresence, TOFU fingerprint store.\n\n```bash\nrea doctor\nrea doctor --metrics   # also print 7-day Codex telemetry summary\nrea doctor --drift     # report drift vs. install manifest (read-only)\n```\n\nIn non-git directories the commit-msg and pre-push checks are skipped\ncleanly. Audit hash-chain integrity is verified by `rea audit verify`,\nnot by `rea doctor`.\n\n### `rea audit rotate` / `rea audit verify`\n\n```bash\nrea audit rotate                      # force rotation now\nrea audit verify                      # re-hash the chain; exit 1 on first tamper\nrea audit verify --since \u003cfile\u003e       # walk forward from a rotated file\n```\n\n### `rea tofu list` / `rea tofu accept`\n\n```bash\nrea tofu list\nrea tofu list --json\nrea tofu accept my-mcp-server --reason \"added vault path /Volumes/Work\"\n```\n\n### `rea hook push-gate`\n\nPre-push Codex review gate. Normally invoked by `.husky/pre-push`; run\nmanually to test.\n\n```bash\nrea hook push-gate\nrea hook push-gate --base origin/main\n```\n\n---\n\n## Migration from 0.10.x\n\n`rea upgrade` handles the policy and on-disk pieces. You run it once:\n\n```bash\nrea upgrade\n```\n\nIt performs:\n\n1. **Backup** — writes `.rea/policy.yaml.bak-\u003ctimestamp\u003e` before any edit.\n2. **Strip removed fields** — removes `review.cache_max_age_seconds` and\n   `review.allow_skip_in_ci` from the policy file. Both were cache-gate\n   concepts with no meaning under the stateless gate.\n3. **Add defaults** — inserts `review.concerns_blocks: true` if absent.\n4. **Prune settings.json** — removes hook registrations for the removed\n   scripts (`push-review-gate`, `commit-review-gate`) from\n   `.claude/settings.json`, leaving the other registrations intact.\n5. **Refresh `.claude/hooks/`** — deletes the removed scripts with a\n   change-log entry.\n6. **Rewrite `.husky/pre-push`** iff it carries a rea marker. A\n   foreign `.husky/pre-push` (no marker) is left untouched and a loud\n   warning is printed.\n7. **Refresh `.git/hooks/pre-push`** fallback with the new 15-line stub\n   (when `core.hooksPath` is unset and git is using the default hooks\n   directory).\n\n### What the new `.husky/pre-push` looks like\n\nFifteen lines of POSIX `sh`. HALT check, locate the rea binary, `exec rea\nhook push-gate \"$@\"`. That is the entire body — all real work lives in\nthe TypeScript gate composer at `src/hooks/push-gate/index.ts`.\n\n### Rollback\n\nIf the stateless gate's behavior is blocking a specific workflow you\ncannot yet address:\n\n```bash\nnpm install -g @bookedsolid/rea@0.10.3\n# restore policy from the backup rea upgrade wrote\ncp .rea/policy.yaml.bak-\u003cts\u003e .rea/policy.yaml\n# re-run the 0.10.3 install to put the old hooks back\nrea init --force\n```\n\nThe 0.10.3 cache-attestation gate remains on npm and continues to work.\nRollback is a supported path — the `rea upgrade` backup is specifically\nthere to make it a one-liner.\n\n### What you will not need to do anymore\n\n- `rea cache check` / `rea cache set` / `rea cache list` / `rea cache clear`\n  — all removed. The stateless gate consults no cache.\n- `rea audit record codex-review --also-set-cache` — removed. The gate\n  writes its own audit records from the actual Codex run.\n- Setting `REA_SKIP_PUSH_REVIEW` — removed. Use either\n  `REA_SKIP_PUSH_GATE=\u003creason\u003e` or `REA_SKIP_CODEX_REVIEW=\u003creason\u003e`\n  (both value-carrying and always audited; identical effect, distinct\n  `skip_var` in audit metadata) or flip `review.codex_required: false`\n  in policy. `REA_SKIP_CODEX_REVIEW` was reinstated in 0.12.0 as an\n  audited alias for `REA_SKIP_PUSH_GATE` — it had been documented in the\n  gateway-tier reviewers but not in the push-gate, leaving agents\n  setting the documented variant blocked.\n\n---\n\n## Contributor quality gates\n\nBefore push, run the four checks locally. CI runs them as required status\nchecks on every PR to `main`:\n\n```bash\npnpm lint        # ESLint 10 — zero warnings\npnpm type-check  # tsc --noEmit (strict)\npnpm test        # vitest run\npnpm build       # tsc -p tsconfig.build.json\n```\n\nAdditionally, every PR needs:\n\n- **DCO sign-off** on all commits (`git commit -s`). The DCO bot rejects\n  unsigned commits.\n- **Changeset** entry (`pnpm changeset`) unless the change is purely\n  non-publishable (CI, docs, meta). CI flags missing changesets.\n- **Secret scan** clean. Gitleaks runs in CI and via the\n  `secret-scanner.sh` hook.\n- **No AI attribution** anywhere — commit messages, PR bodies, code\n  comments, changeset content. The commit-msg hook and\n  `attribution-advisory.sh` reject structural attribution.\n\nSecurity-sensitive paths (`src/gateway/middleware/**`, `src/policy/**`,\n`src/hooks/**`, `hooks/**`, `.github/workflows/**`) require explicit\nmaintainer review and a threat-model update in the same PR.\n\nReleases flow through Changesets: a \"Version Packages\" PR is auto-opened\nwhen a changeset lands on `main`. Merging it triggers `npm publish\n--provenance` via OIDC from `.github/workflows/release.yml`. Do not\nmanually `npm publish`.\n\n---\n\n## Threat model and security\n\n- [SECURITY.md](./SECURITY.md) — disclosure policy, supported versions,\n  GHSA coordination. 72-hour acknowledgment target, 90-day window. Do\n  not report vulnerabilities via public GitHub issues.\n- [THREAT_MODEL.md](./THREAT_MODEL.md) — attack surface, mitigations,\n  residual risks. The contract rea holds itself to.\n\nShort version: the MCP gateway and the hook layer run independently.\nBoth fail closed. `.rea/` is always blocked. The audit log is\nhash-chained. Policy is re-read on every invocation. npm publish uses\nOIDC provenance, not long-lived tokens. The pre-push gate runs Codex\non every push and treats Codex responses as untrusted input — findings\nflow through the same redact pattern set used by the middleware before\nanything hits disk.\n\n---\n\n## Non-goals\n\nSee [What REA is NOT](#what-rea-is-not) above. Every \"but what if we\njust added X\" belongs in a separate package that composes with REA. The\nnon-goals are the product.\n\n---\n\n## License and contributing\n\n[MIT](./LICENSE). See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full\ncontributor guide and [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) for\nthe Contributor Covenant.\n\n- DCO sign-off required (`git commit -s`) — no CLA.\n- Conventional commits, TypeScript strict, ESLint zero-warnings,\n  Prettier, vitest.\n- Changeset on every publishable change; merge the auto-generated\n  Version Packages PR to release.\n- Security-sensitive paths gated by CODEOWNERS; human review required.\n\nThis repo dogfoods itself. rea's governance layer enforces rea's own\ncommit, hook, and attribution rules. The install under `.rea/`,\n`.claude/`, and `.husky/` is the reference example of the\n`bst-internal` profile.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbookedsolidtech%2Frea","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbookedsolidtech%2Frea","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbookedsolidtech%2Frea/lists"}