> For the complete documentation index, see [llms.txt](https://docs.robotmoney.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.robotmoney.com/resources/changelog.md).

# Changelog

User-visible changes to the RobotMoney protocol, HTTP API, MCP surface, and SDK. Internal refactors, performance work, and bug fixes that don't change behaviour are omitted unless they affect integrators.

### v0.5.21 (headless authorization launch)

* **Headless execution reads distinguish submission, principal settlement, and fees.** Headless authorization rows now report `submitted` only after a provider response is observed or a transaction hash is stored, and `settled` only after the principal is independently verified in a finalized block. The fee leg is exposed separately. The old `executed` value is removed only for headless rows; non-headless linked rows are unchanged.
* **Decision-only authorizations are available for headless agents.** `POST /v1/authorizations` records approved, needs-review, or blocked decisions without creating a PaymentIntent or moving money. Review and void routes were added for recorded authorizations. Merge commit: `68ff4e63b44aca98e9cd3eb07ff11b60481b05e0`.
* **Tenant owners can set headless authorization limits.** New headless limit routes let owners configure amount and micropayment windows for agent decisions that use customer-owned rails. Merge commit: `25f3c88d80d8dd390914f4bfcfbd61e1a5c6f9b3`.
* **Tenant-created agents now return exchange metadata.** `POST /v1/agents` returns a one-time `brain_ak_` credential and the token exchange details an agent needs for `payment_intent:propose`. Merge commit: `e28be3fa67dcef098d9490ccfa234a83f4e714d5`.
* **SDK and MCP surfaces include authorization decisions.** The public SDK and MCP server can create, read, approve, and reject authorization decisions through the headless path. Merge commit: `1bf8c1fa892d6836f506b13d1531477aff266d1d`.
* **Recorded decision usage is metered.** `GET /v1/usage/authorizations` reports recorded authorization counts by tenant and by agent for later billing. Merge commit: `0ede570c4f3054739cf4b5ecc48d1e38a4580f3f`.

### v0.5.20 (grounded accounts receivable totals)

* **Total accounts-receivable questions now use deterministic invoice data.** `What's our total accounts receivable?` and `How much are we owed in total?` sum open customer AR invoices and return cited Ledger evidence. The result uses the complete `ledger_invoices` AR source, not the partial receivable- obligation projection.

### v0.5.19 (adaptive audit anchoring)

* **Demo and sandbox tenant audit chains stay database-only.** `GET /v1/audit/anchor/latest` now exposes `anchoring_mode` and `guarantee` so clients can distinguish `database_hash_chain` from a Base Sepolia anchor.
* **On-chain anchor batches close on tenant-root count or maximum wait.** The publisher uses the configured threshold or latency bound, whichever happens first.
* **Published batching measurement is updated.** Database-linked Base Sepolia receipts measured on 2026-08-11 across 36 transactions and 189 roots ranged from 47,325 to 73,620 gas per tenant root, with a weighted average of 51,474. This is an operational measurement, not a fixed gas or cost guarantee. It does not represent a full publisher-wallet cost guarantee while wallet-to-anchor reconciliation remains under investigation.

### v0.5.18 (obligation scenario filtering)

* **`GET /v1/ledger/obligations` now supports `scenario=ap|ar`.** The filter is validated and applied in the Ledger query rather than silently ignored. When direction is omitted, `scenario=ar` selects receivable rows and `scenario=ap` selects payable rows.
* **Invoices are documented as the complete receivables inventory.** The receivable-obligation filter is limited to rows that have an obligation projection and is not interchangeable with the invoice list.

### v0.5.17 (production tenancy identity conflicts)

* **Production tenant creation now handles an already-linked platform identity.** `POST /v1/tenants` and `POST /v1/orgs/{orgId}/tenants` return `409` `tenant_identity_already_linked` with the existing tenant id instead of surfacing a PostgreSQL unique-constraint error. Clients can reattach through the documented session and agent-token routes.

### v0.5.16 (explicit accounts receivable classification)

* **AR-sourced Ledger invoices and obligations now carry `metadata.scenario: "ar"`.** Consumers can identify receivables positively instead of classifying every non-AP row as AR.
* **Ledger obligation metadata is now part of the public response contract.** `GET /v1/ledger/obligations` returns each row's structured metadata, matching invoice responses.
* **Invoice and obligation pagination is documented.** Both list endpoints return an opaque `next_cursor`; receivables can additionally be selected with `GET /v1/ledger/obligations?direction=receivable`.

### v0.5.15 (tenant-aware Wiki question suggestions)

* **`GET /v1/wiki/suggested-questions` returns eligible deterministic questions for the calling tenant.** Suggestions derive from the same intent registry as deterministic Wiki question execution, so unavailable or generative-only questions are never suggested.
* **Suggestions are ranked by tenant-local deterministic question use.** The `usage_rank_score` is an all-time invocation count scoped by tenant and is never shared across tenants.
* **`GET /v1/assistant/questions` remains a separate persisted-record feed.** It does not evaluate deterministic eligibility; clients needing suggestions must call `GET /v1/wiki/suggested-questions`.

### v0.5.14 (grounded Wiki listing answers)

* **Bounded transaction, cash-flow, and invoice listings use deterministic Ledger queries.** Questions such as `Show last 10 transactions`, `Show recent cash flow`, and `List this month's invoices` return the matching records and cited Ledger evidence without generative synthesis.
* **Invoice records are now a Wiki-question evidence type.** Listing responses can cite the Ledger invoice rows they return.

### v0.5.13 (grounded Wiki aggregation answers)

* **Wiki question answers now carry `answered`.** This boolean is `true` only for grounded or deterministic answers. Clients no longer need to infer a refusal from prose.
* **Transaction counts, totals, and averages use a deterministic Ledger query when the transaction scope is unambiguous.** Month-scoped and direction-scoped questions return the exact computed value and matching transaction evidence without relying on an LLM to perform arithmetic.

### v0.5.12 (counterparty trust contract correction)

Documentation and integration-contract correction. No route, service, gate, or authentication behavior changed.

* **BrainMVB's API surface now includes all four mounted counterparty trust transitions.** Grant, pause, restore, and acknowledge require a user bearer JWT with `ledger:write`; platform shared-secret callers and API keys cannot call them.
* **Counterparty trust terminology now matches the live state machine.** The state vocabulary is `unreviewed`, `trusted`, `paused`, and `acknowledged`.
* **Trust-state docs now state the current enforcement boundary.** Trust state is advisory only. Payment execution is enforced through `verified_status`, sanctions screening, and policy checks.

### v0.5.11 (production launch documentation reconciliation)

Documentation-only correction. No API or contract behavior changed.

* **Audit proof documentation now matches `BrainAuditAnchor`.** Verification uses `isPublished(tenantId, root)` and `verifyInclusion(root, leaf, proof)`. `latestAnchor` returns the current tenant root. The contract has no batch index or `rootAt` method.
* **Batch publication is documented.** `anchorBatch` publishes up to 50 tenant roots in one Base Sepolia transaction and skips already-published pairs on a retry. Single-root `anchor` still rejects a duplicate pair.
* **Launch network and publisher statements are corrected.** RobotMoney's APIs are production available. The anchor contract is unaudited, runs on Base Sepolia, has no Base mainnet deployment, and currently uses a single EOA publisher with two-step rotation.
* **API-key availability is stated per environment.** At launch, first-class `brain_sk_` authentication is enabled for sandbox integration and disabled on the production API. The only issuable scopes are `ledger:read`, `audit:read`, and `governance:read`.

### v0.5.10 (proposal read model expansion)

Backward-compatible API read-model expansion. No new route or API version was introduced because existing compact fields remain in place and all new fields are additive.

#### Changed. Proposals and evidence

* **`GET /v1/proposals` and `GET /v1/proposals/{id}` now return richer proposal cards.** In addition to the compact fields, each proposal includes `stored_action_type`, `details`, `policy`, `presentation`, and `available_decisions`. `presentation.technical_detail` uses stable six-layer keys: `1_ingest`, `2_extract`, `3_classify`, `4_score`, `5_policy`, and `6_propose`.
* **Public proposal types are now complete across first-party agents and payment intents.** The full public set is `vendor_risk`, `payment`, `collections`, `treasury`, `cash_forecast`, `dispute`, `compliance`, `revenue_intel`, `reconciliation`, `subscription`, `fraud_anomaly`, `personal_budget`, `financial_health`, `purchase_advisor`, `tax_prep`, `travel_finance`, `bill_management`, `debt_optimization`, and `savings`.
* **Stored action names map deterministically to public proposal types.** Direct public types win first, then agent role or kind, then the explicit stored-action map. Examples: `flag_transaction -> fraud_anomaly`, `block_payment -> vendor_risk`, `propose_match -> reconciliation`, `recommend_card -> travel_finance`, `tag_tax_item -> tax_prep`, `remind -> bill_management`, and `recommend_savings_transfer -> savings`. Ambiguous names such as `notify`, `escalate`, `create_task`, and `recommend_action` resolve through agent role or kind.
* **High-risk unmatched non-money actions surface for review.** Unmatched `collections`, `fraud_anomaly`, and `vendor_risk` `agent_action` proposals now fall back to `confirm` with a signer requirement. Low-stakes proposal types and `payment` remain fail-closed when no policy rule matches.

### v0.5.9 (surface onboarding admin auth)

* Surface onboarding endpoints for Slack OAuth install, Teams install and revoke, and email recipients, routes, and domains now require a RobotMoney bearer JWT with `surfaces:admin`. The gateway derives the tenant from the principal instead of trusting tenant ids in request bodies.
* Email custom sender domains are verified by RobotMoney-side DNS checks for SPF, DKIM, and DMARC before activation. A reverify endpoint can refresh the result.
* Slack OAuth install state is signed with `SLACK_INSTALL_STATE_SECRET` instead of reusing the OAuth client secret.

### v0.5.8 (surface approval audit ordering + OpenAPI cleanup)

Safety and contract-polish release. No endpoint behavior is loosened.

#### Fixed. Surface approval ordering

* **Surface approval signatures now happen after the decision audit record.** Slack, Teams, and email approval flows re-check policy first, write the audit record, then record the approval signature that contributes to quorum. This keeps quorum-changing approval writes from preceding the audit evidence for the same human decision.
* **Dual approval still records the first approver.** The post-audit approval hook runs for both awaiting-second-approval and terminal approvals, so quorum can build without moving signing into the execution handoff.
* **Approver role checks are stricter.** A roleless actor no longer satisfies a `signer` sentinel, and disabled users no longer count as active approvers.

#### Changed. OpenAPI contract quality

* **OpenAPI lint now runs clean with zero warnings.** The contract now includes proprietary license metadata, explicit documented error responses for operations that only listed success responses, and regenerated SDK types.
* **Intentional route-shape exceptions are documented in Redocly config.** The implemented Fastify routes retain their existing paths, and the disabled legacy `POST /v1/execution/execute` route remains documented as returning `422` rather than a fake success response.

### v0.5.7 (money-path reservation lifecycle)

Safety hardening for the PaymentIntent execution path. No API, MCP, or SDK surface changed.

#### Fixed. Reservation-backed execution handoff

* **Balance reservations now have a live lifecycle.** For ledger-account-backed payments, `execute()` locks the source account, locks the latest balance snapshot, rechecks available balance net of active reservations, then creates a reservation in the same transaction that moves the PaymentIntent from `approved` to `dispatching` and enqueues the durable outbox row. The outbox row stores `reservation_id`; settlement consumes the reservation, and deterministic rail failure releases it. Check #8 already subtracted active reservations, and the locked recheck makes the handoff race-free.
* **Outbox and PaymentIntent state races fail closed.** Settlement now verifies that `dispatching -> executed` actually updated the PaymentIntent before appending the execution receipt, consuming the reservation, or recording spend. Deterministic failure similarly verifies `dispatching -> failed` before releasing a reservation. A lost race routes the worker to retry/reconcile instead of producing a mismatched outbox/PaymentIntent state.
* **Outbox idempotency fallback is tenant-scoped.** The conflict lookup now selects by both `tenant_id` and `idempotency_key`, matching the unique index and preserving correctness outside strict RLS test environments.
* **Readiness evidence is profile-gated.** `production-readiness --profile` now treats evidence strength as a release gate, not only a display field. Staging requires exercised core safety rows such as Base Sepolia on-chain E2E; mainnet requires exercised money-path, rail, audit, and contract evidence. A new `pnpm run readiness:evidence -- --profile staging` command emits a diligence-ready report with row status, evidence state, blockers, and known limitations.

#### Changed. Boot composition

* Production DB role expectations moved out of `services/api/src/main.ts` into a focused composition module. Runtime behavior is unchanged; the boot binary is smaller and the role matrix is easier to review.

### v0.5.6 (docs-accuracy remediation + error `docs_url`)

Documentation-accuracy pass across the published docs, reconciling them to the code as the source of truth: the §6 gate-check count (13 numbered + 10 hardening = 23), the MCP scope error code (`-32002`, not `-32004`), the route migration table (`/execution/*` propose/register stay live; `/agents/{id}/propose` and `/agents/register` 404), the MCP surface size (12 tools / 7 resources / 5 prompts), the self-serve signup path (`POST /v1/signup`), the credential model (`brain_sk_` is the bearer service token), the decision/status vocabularies (`allow|confirm|reject` and their SDK aliases), the webhook event catalog (`payment_intent.*`), and the deployed Base Sepolia contract addresses. No API / MCP / SDK behavior changed except the item below.

#### Changed. Error envelope `docs_url`

* **`error.docs_url` now points at the published error reference.** It previously emitted `https://docs.robotmoney.com/errors/{code}`, a path with no page (every self-help link 404'd). It now emits `https://docs.robotmoney.com/resources/errors#{code}`, which lands on the canonical error registry.

### v0.5.5 (GDPR erasure hardening)

Second-pass review remediation of the tenant blob-purge workflow (RFC 0003). Compliance- and diligence-facing; the internal worker/test detail is omitted.

#### Changed. Tenant erasure is now crash-safe and audit-atomic

* **A crashed purge worker can no longer silently strand a GDPR Article 17 erasure.** A job claimed by a worker that then dies (left in `purging`) is now reclaimed by another worker once its lease expires, and every status write is fenced on a unique lock token so a resurrected stale worker cannot overwrite the new owner's result.
* **A transient cloud error no longer masquerades as a permanent legal hold.** Per-object delete failures are classified: throttling / 5xx / network / authorization errors are retried, and only a confirmed WORM / object-lock response makes the job terminal (`blocked_legal_hold`). Previously any failed delete was treated as a legal hold, so a 503 could permanently stop an erasure.
* **Purge-lifecycle audit events are now written transactionally.** Each state transition records its audit intent in the same database transaction as the status change (via an outbox), and a publisher delivers it to the audit service idempotently. This removes the prior ordering where an audit event could be emitted before the state write (orphaning a "completed" record) and the `audit-emit-failed` sentinel that let a job complete with no real audit event. A tenant deletion now returns a truthful committed result even if the audit service is momentarily unavailable.

### v0.5.4 (audit-build binding, GDPR erasure, money-path CI)

Review-remediation batch. The internal CI/test work is omitted; the items below are API-, compliance-, or diligence-facing.

#### Fixed. Proof API

* **`GET /v1/proof/{action_id}` no longer 500s for an in-flight payment.** A PaymentIntent that is executed but still `dispatching` (settlement async, not yet anchored) now returns a **200 partial proof** (gate checks present, `merkle_root` empty until anchored) instead of an internal error. Root cause was a never-run-on-Postgres evidence query referencing non-existent columns. `policy_hash` is now hex-encoded (was a raw byte buffer).

#### Added. GDPR Article 17 erasure (RFC 0003)

* **Tenant deletion now durably and permanently erases Raw blob bytes.** `DELETE /v1/tenants/{id}` enqueues a `tenant_blob_purge_jobs` row in the deletion transaction; a privileged worker drains it via `BlobAdapter.purgeTenant` with bounded retries, a dead-letter state, legal-hold surfacing, and per-lifecycle audit events (`tenant_blob.purge_requested` / `_completed` / `_blocked_legal_hold` / `_retried` / `_exhausted`). `purgeTenant` does version-aware deletion (S3 every object version + delete marker; Azure versions + snapshots), so erasure is permanent in a versioned bucket, closing the gap where a "deleted" response left the user's PII recoverable.

#### Changed. Mainnet escrow audit binding (diligence)

* **Audit approval binds to the audited build, not just a commit.** `contracts/audit-status.json` approval now additionally requires the compiler settings, contract-source-tree hash, and creation/runtime bytecode hashes, plus an explicit `approved_chain_ids`. A CI step recomputes them from the working tree + Foundry artifact and fails the build on drift; the mainnet escrow boot fence also requires the booting chain to be in `approved_chain_ids`. A single shared validator now backs the runtime fence, the CI guard, and the readiness command (previously the runtime path was a bare `status === "approved"` check).
* **The mainnet escrow boot fence now also verifies the DEPLOYED on-chain bytecode.** With an escrow address configured on Base mainnet, the api reads the live contract code via `eth_getCode` and refuses to boot unless it matches the audited runtime bytecode. Because Solidity writes `immutable` values (the escrow arbiter) into the deployed code at construction, the audited hash and the on-chain code are compared with those immutable byte ranges masked; an approved `contracts/audit-status.json` now carries the masked `runtime_bytecode_sha256` plus the `immutable_references` ranges. A wrong, unaudited, or tampered deployment becomes a refused boot rather than a silent funds-custody risk.

### v0.5.3 (CI + demo integrity)

Internal hardening. No API, protocol, MCP, or SDK surface change. Recorded here because it restores an end-to-end proof artifact integrators rely on, and one item affects anyone bootstrapping the schema.

#### Fixed. CI + golden-path

* **The golden-path smoke runs end-to-end as a post-merge CI gate again.** Its job depends on the unit+integration job, which had been red on an unrelated, masked test-schema failure, so the smoke was silently skipped and the full `seed → ingest → normalize → propose → policy → execute → proof` chain was not actually exercised in CI. The prerequisite suite is green again and the smoke passes front to back (propose → `approved` → execute → `dispatching`).
* **The demo seed no longer trips the §6 duplicate-payment gate (check 11.5).** A freshly-seeded counterparty's payment instructions were stamped `now()`, which the `destination_recently_changed` rule correctly reads as a vendor-account-swap signal. The seed's backdate mitigation had been scoped to the on-chain recipient only; it now backdates every seeded counterparty for the tenant, so the default ACH demo settles cleanly. The §6 gate itself is unchanged and still fail-closed.
* **The migration set is self-contained for `pgcrypto`.** A migrations-only bootstrap (for example a test schema that does not run the `postgres-init` extension script) now creates `pgcrypto` via migration `0031`, so the migration `0027` payment-instruction trigger's `digest()` call resolves instead of failing at first insert. This affects anyone building a schema from the migration set alone.

### v0.5.2 (control-plane hardening)

Follow-up review fixes. All stricter / fail-closed.

#### Changed. Safer defaults + provenance

* **The default tenant policy never auto-executes money.** A freshly provisioned tenant's default now requires human **confirmation** for `outbound_payment` / `onchain_tx` above the confidence floor (with a single-signer approval); non-money actions still auto-allow. The prior blanket `auto` rule (which the repo's own policy linter flags as unsafe-for-money) is gone. A tenant signs a constrained autonomy policy to earn unattended money movement.
* **High-trust provider source types are reserved to authenticated ingestion.** `source_type: "plaid"` / `"stripe"` are refused on the generic `/raw/ingest` route with `raw_source_reserved` (403); they may only arrive via the HMAC-verified `/raw/webhooks/{provider}` path, so a `raw:write` caller can't mint high-trust evidence by choosing the label.

#### Fixed. Audit-control plumbing

* The committed `contracts/audit-status.json` now ships in the production image, so the mainnet escrow boot fence can actually pass once the audit is approved (previously it was excluded and failed closed forever).
* `pnpm run production-readiness` now models the same two-part mainnet-escrow condition as the runtime boot fence (committed approved record **and** env attestation), so the report can no longer show green for a deployment the runtime would reject.

### v0.5.1 (autonomy + provenance hardening)

A safety-hardening batch. All changes are stricter (fail-closed), never more permissive.

#### Changed. Tighter defaults + authorization

* **Default confidence floor raised to `0.6`.** A freshly provisioned tenant's default policy now rejects auto-execution of an intent backed only by an uncorroborated, document-extracted obligation (capped at `0.5`); a corroborated obligation (reconciliation lifts it to \~`0.7`+) still passes. Tenants with their own signed policy are unaffected.
* **Signed per-agent action allowlist (`PolicyDocument.agent_actions`) is now enforced on every action-resolution path** (explicit request, event map, intent-classifier match, and default action), not just explicit requests. A denied action can no longer be smuggled in via an event mapping or a default.
* **Evidence trust derives from the raw artifact's `source_type`**, not the caller-chosen parser label, so a `raw:write` principal can no longer mint high-trust evidence by labelling its parser `plaid`/`stripe`.

#### Added. Obligation-direction safety

* **`obligation_direction_invalid` (422).** A new obligation-linked PaymentIntent must target a known `payable` obligation; a `null`/unknown or `receivable` (wrong-way) direction is refused at creation. The §6 gate's check 6.7 continues to reject `receivable` at execute for already-created intents.

#### Added. Operational / diligence

* **`contracts/audit-status.json`** is the committed source of truth for the external smart-contract audit; mainnet escrow now boots only when that record says `approved` (a bare env flag no longer bypasses a pending audit).
* **`BlobAdapter.purgeTenant`** primitive for GDPR Art. 17 tenant erasure (deletes Raw bytes under a tenant prefix; WORM/legal-hold-protected blobs are surfaced, not force-deleted).

### v0.5 (M2M Commerce + Self-Serve Onboarding)

Two additive tracks: **machine-to-machine (M2M) agent commerce** (RFC 0001) and **self-serve onboarding** (RFC 0002). Everything money-moving here is **shadow-first / fail-closed**. The new settlement rails are unregistered at boot and the new contracts are unaudited testnet/reference code. Self-serve signup is gated behind `BRAIN_SELF_SERVE_SIGNUP` (default off, sandbox-first).

#### Added. Self-serve onboarding (RFC 0002)

* `POST /v1/signup`. Open, sandbox-first tenant + owner creation (email + password). Returns a verification token directly only outside production (no email provider wired yet). Registered only when `BRAIN_SELF_SERVE_SIGNUP` is enabled; returns 404 when the flag is off.
* `POST /v1/auth/verify-email`. Verify the owner's email with the issued token.
* `POST /v1/auth/login`. Email + password login for the human owner; mints an owner JWT.
* `POST /v1/tenants/{tenant_id}/wallets`. Link a wallet to a tenant; a linked wallet can then sign in over SIWX as the owner.
* Agent on-chain registration is async: a newly registered agent starts `pending_onchain` and a relayer submits the `BrainMCPAgentRegistry` registration (the relayer is fail-closed until configured).

#### Added. M2M / x402 settlement (RFC 0001)

* `x402_settle` action type. USDC-on-Base settlement via the `x402_base` rail.
* `escrow_release` action type. Milestone / dispute-split release via the `escrow_base` rail (`BrainEscrow`).
* Both settlement rails are **unregistered at boot and fail closed** until promoted; they throw rather than fake-settle.
* Five dormant-until-wired §6 gate checks (3.5 on-chain-settlement-permitted, 5.5 agent-counterparty-attested, 6.5 x402-payment-context, 6.6 escrow-state-bound, 8.5 micropayment-cap-in-window). Each adds a row only when the intent carries settlement/escrow context **and** its on-chain loader is configured; the canonical path is unchanged for non-settlement payments.
* On-chain-settlement reconciliation matcher; agent counterparties; `chain_tx_hash` on `ledger_transactions`.

#### Added. Smart contracts (Base; unaudited)

* `BrainEscrow`. Custodial escrow with partial release, refund, and dispute splits (**UNAUDITED reference implementation**, testnet only).
* `BrainReputationRegistry`. An ERC-8004-style per-agent reputation pointer / score root (RFC 0001, **UNAUDITED testnet**). Policy reads it as a **tighten-only** threshold input. Never a money gate or a §6 precondition.

#### Errors

* `signup_email_taken` (409), `signup_token_invalid` (400), `wallet_already_linked` (409), `auth_invalid_credentials` (401), `auth_email_unverified` (403).

### v0.4 (Agent Autonomy v3)

Hardens the 19-agent internal library for production autonomous execution. **Money-movers stay shadowed by default**. Going live is a deliberate, per-agent promotion (strict caps + allowlisted rails); no agent moves money until promoted.

#### Added. HTTP API

* `POST /v1/agents/route`. Routing decision only (no run).
* `POST /v1/agents/run`. Route → resolve action → dry-run gate → persist run → propose (shadow-aware; a shadowed agent's financial proposal terminates as `shadow_completed`).
* `POST /v1/agents/events`. Enqueue an event-driven route/run job.
* `GET /v1/agents/runs`, `GET /v1/agents/runs/{run_id}`, `GET /v1/agents/runs/{run_id}/why`. Run history + the structured-reason / trace / gate / receipt bundle.
* `GET /v1/agents/routing-decisions/{id}`. Routing decision detail.
* `POST /v1/agents/{agent_id}/halt`, `POST /v1/agents/halt-category`. Kill-switch: pause an agent's in-flight intents + quarantine it, or emergency-stop a whole category.
* `POST /v1/payment-intents/{id}/pause`, `POST /v1/payment-intents/{id}/resume`. Pause/resume an approved intent (resume re-runs the live §6 gate).
* `GET /v1/payment-intents/{id}/replay-investigation`. Typed forensic record (intent + executions + rail receipts + linking ids).

#### Added. Policy DSL (signed)

* `agent.id`, `tenant.category`, `action.in` / `action.not_in`, `agent.behaviorHash`, `agent.spend_in_window`, `agent.tx_count_in_window`, and rule-level `approval_required_above`. All covered by the policy content hash, so they're signed.

#### Added. Smart contracts

* `BrainSmartAccount.pauseSessionKey(holder)` / `unpauseSessionKey(holder)`. Disable execution while preserving the key record, window spend, limits, and metadata (distinct from `revokeSessionKey`, which is permanent removal).
* `BrainMCPAgentRegistry.registerAgent` now takes a `behaviorHash`; `updateBehaviorHash(...)` re-attests on a model/prompt/tool change. The §6 gate adds check 1.5 (runtime `behaviorHash` must match the registered value).

#### Changed

* `Agent.state` adds `quarantined` (additive enum widening).
* Typed rail receipts (`ach` / `wire` / `erp` / `onchain`): the audit-after step refuses to commit unless the receipt validates against the rail's schema.

#### Errors

* `agent_proposal_duplicate` (409). Proposal-layer idempotency collision.

#### SDK (`@brain/sdk`)

* New `agents.route/run/enqueueEvent/listRuns/getRun/why/getRoutingDecision/halt/haltCategory` and `payments.pause/resume/replayInvestigation`. Generated types regenerated from the OpenAPI spec.

### v0.3.1 (poc-investor-demo)

#### Breaking changes

* **`BRAIN_DEMO_MODE` env var now requires literal `"true"` or `"false"`.** Previously `z.coerce.boolean()` silently coerced `"false"`, `"0"`, `"no"` to `true`. Update any `.env` or CI config using those forms.
* **`Brain.getMaskedApiKey()` renamed to `getMaskedToken()`.** Follows the `apiKey → token` rename in this release.

#### Added

* `Dockerfile`. Multi-stage build for the `brain-server` single-process boot binary.
* `GET /v1/demo/token`. Mints a 15-minute read-heavy JWT for the golden demo tenant (requires `BRAIN_DEMO_MODE=true`, refused in `NODE_ENV=production`).
* `POST /v1/audit/anchor/publish`. On-demand anchor trigger (requires `audit:admin`, 60s per-tenant cooldown).
* Live viem anchor broadcaster. `AUDIT_PUBLISHER_KEY` + `AUDIT_ANCHOR_ADDRESS` wires on-chain anchoring to Base Sepolia.
* `CORS_ALLOWED_ORIGINS` config variable. Replaces the previous reflect-any-origin behaviour.
* `tools/demo-reset`. Wipes and re-seeds golden-path demo-tenant business entities; audit log preserved.

## Current: Six-Layer Protocol with MCP

The current release introduces a Normalized Ledger between Raw and Wiki, splits Execution into a dedicated Agent layer, and adds the MCP server.

### Added

* **Normalized Ledger layer.** Eleven entities: accounts, balances, transactions, counterparties, obligations, documents, categories, transfers, invoices, payment intents, reconciliation matches.
* **Payment Intents.** Agent-proposed financial actions live as Ledger rows, queryable like any other entity.
* **Pre-execution gate.** Deterministic check against live Ledger state before any payment executes: 13 numbered checks plus 10 hardening additions (23 entries total; several record `not_applicable` until their loaders are wired). See [the pre-execution gate](/how-it-works/the-pre-execution-gate.md).
* **MCP server.** `POST /v1/agents/mcp`, JSON-RPC 2.0 over single-shot HTTP. 12 tools, 7 resource templates, 5 canned prompts.
* **Agent contributions.** External agents with `raw:write` scope can push artifacts into the Raw layer with cryptographic attribution.
* **`/v1/audit/entity/{type}/{id}` endpoint.** Pull every audit event that touched a specific Ledger row.

### Changed

* **Ledger is now the source of truth.** Wiki is downstream of Ledger and regenerable from Ledger plus Raw at any time.
* **Wiki no longer authoritative for financial state.** Wiki holds human-readable memory only; balances, transactions, and obligations come from Ledger.
* **Execution renamed to Agent.** The Agent layer covers proposal, scope enforcement, and the propose-only MCP surface.
* **Routes added.** `/payment-intents/*`, `/agents/run`, and `/agents/mcp` are the v0.3 paths that are mounted today. The legacy `/execution/*` routes remain **live and fully supported**: the generic propose/approve flow (`/execution/propose`, `/execution/approve`) and external-agent registration (`/execution/agents/register`) still run through them and have no v0.3 replacement. The reserved `/agents/{id}/propose` and `/agents/register` paths appear in the OpenAPI spec but are **not yet implemented and return 404**; do not migrate to them.

### Six Layers (Was Five)

* The previous protocol had five layers: Raw, Wiki, Policy, Execution, Audit.
* The current protocol has six: Raw, **Ledger**, Wiki, Policy, **Agent** (renamed from Execution), Audit.

## Migration from the Previous Version

| If you were using              | Use instead                                                              |
| ------------------------------ | ------------------------------------------------------------------------ |
| `/execution/propose`           | Still live (no replacement); or `/agents/run` for routed agent proposals |
| `/execution/execute`           | `/payment-intents/{id}/execute`                                          |
| `/execution/agents/register`   | Still live (no replacement); `/agents/register` is not yet implemented   |
| `/execution/mcp`               | `/agents/mcp`                                                            |
| Wiki for current balances      | `brain.accounts.list` (Ledger)                                           |
| Wiki for transaction filtering | `brain.transactions.list` (Ledger)                                       |

Only `/execution/execute` and `/execution/mcp` have v0.3 replacements; both carry `Deprecation`/`Sunset` headers. The propose/approve and agent-registration routes under `/execution/*` are **not deprecated** and remain the supported path.

## Earlier: Five-Layer Protocol

* Five layers: Raw, Wiki, Policy, Execution, Audit.
* Wiki was the source of truth for financial state.
* MCP surface lived under `/execution/mcp`.
