BrainstormRouter is a personal research project by Justin Jilg. It is not a commercial product, has no SLA and is not intended for production use.

Governance

Memory audit trails, compliance scanning, and executive dashboards.

Endpoints

MethodPathAuthDescription
GET/v1/governance/memory/auditAPI KeyMemory change history
GET/v1/governance/memory/statsAPI KeyOperation counts by type
GET/v1/governance/memory/complianceAPI KeyPII and policy scan
GET/v1/governance/sleep-time/reportAPI KeySleep-time refinement history
GET/v1/governance/summaryAPI KeyExecutive dashboard
POST/v1/governance/policy/dry-runAPI KeyPolicy dry-run evaluation
GET/v1/governance/lineage/{request_id}API KeyThe WHY answer for one request
GET/v1/governance/lineageAPI KeyTrace/request reconstruction
GET/v1/governance/audit/chain/verifyAPI KeyHash-chain + provenance verify

Policy dry-run

Evaluate a policy context against the tenant's current ruleset without enforcement. Useful for testing policies before activating them.

curl -X POST "https://api.brainstormrouter.com/v1/governance/policy/dry-run" \
  -H "Authorization: Bearer br_live_..." \
  -H "Content-Type: application/json" \
  -d '{"action": "POST:/v1/chat/completions", "agentId": "agent-007", "modelName": "gpt-4"}'

Request body

FieldTypeRequiredDescription
actionstringYesAction string
actorobjectNo{ type, id } actor identity
targetstringNoTarget resource path
categorystringNoCategory (e.g., routing)
agentIdstringNoAgent identifier
toolNamestringNoTool name
modelNamestringNoModel name

Response

{
  "decision": "deny",
  "matchedRule": {
    "id": "deny-gpt4",
    "description": "Block GPT-4 usage",
    "action": "deny"
  },
  "ruleCount": 3,
  "mode": "active"
}

Returns decision: "allow" with matchedRule: null when no rules match or no ruleset is configured.

Memory audit

Query the full change history for memory operations.

curl "https://api.brainstormrouter.com/v1/governance/memory/audit?limit=50&operation=append" \
  -H "Authorization: Bearer br_live_..."

Query parameters

ParamTypeDefaultDescription
memory_keystringtenant IDMemory scope
limitnumber100 (max 500)Results to return
sincenumber—Unix timestamp (ms)
operationstring—Filter: append, replace, delete, pin, evict

Response

{
  "entries": [
    {
      "id": "audit-uuid",
      "timestamp": "2025-02-20T10:30:00.000Z",
      "operation": "append",
      "block": "human",
      "entry_id": "entry-uuid",
      "fact_after": "User prefers dark mode",
      "actor": "agent",
      "reason": "Extracted from conversation"
    }
  ],
  "count": 1
}

Compliance scan

curl https://api.brainstormrouter.com/v1/governance/memory/compliance \
  -H "Authorization: Bearer br_live_..."
{
  "total_entries": 42,
  "violations_found": 1,
  "compliant": false,
  "violations": [
    {
      "entry_id": "entry-uuid",
      "block": "general",
      "fact_preview": "Contact email is john@example...",
      "issues": ["possible_email"]
    }
  ]
}

Executive summary

curl https://api.brainstormrouter.com/v1/governance/summary \
  -H "Authorization: Bearer br_live_..."
{
  "memory": {
    "total_entries": 42,
    "pinned_entries": 5,
    "blocks": [
      { "block": "human", "entries": 12, "limit": 50, "utilization": 24 },
      { "block": "project", "entries": 18, "limit": 50, "utilization": 36 }
    ],
    "pii_violations": 1,
    "compliant": false
  },
  "activity_24h": { "append": 8, "replace": 2, "delete": 1 }
}

Sleep-time report

curl "https://api.brainstormrouter.com/v1/governance/sleep-time/report?since=1708387200000" \
  -H "Authorization: Bearer br_live_..."

Decision lineage

Durable, tamper-evident decision lineage bound to the audit chain. See Committed Lineage for the model and Decision Provenance — Chain Payload v2 for the normative commitment + test vectors. All three routes require governance.read.

The WHY answer

GET /v1/governance/lineage/{request_id} returns the committed audit row's verified block (chain hashes + a provenance recompute), the principal block (who acted and who is accountable — see _Owner binding_ below), the synchronous policy_context deny reason, the Inc 3 grant_context pointer, the durable lineage row + its causal neighbors, the coverage enum, and any anomalies. The response echoes the request's traceparent and x-br-request-id headers.

curl "https://api.brainstormrouter.com/v1/governance/lineage/req_01HXXXXXX" \
  -H "Authorization: Bearer br_live_..."
{
  "request_id": "req_01HXXXXXX",
  "coverage": "captured",
  "verified": {
    "outcome": "denied",
    "event_hash": "…",
    "chain_schema_version": 2,
    "provenance_check": "ok",
    "provenance_digest": "b96591a0…",
    "trace_id": "0af7651916cd43dd8448eb211c80319c",
    "edge_provenance": "caller_asserted",
    "trace_inbound_trusted": false
  },
  "principal": {
    "id": "agent-jwt:sales-assistant",
    "auth_method": "jwt",
    "spiffe_id": "spiffe://brainstorm.internal/agent/…/sales-assistant",
    "owner_id": "alice@example.com"
  },
  "policy_context": { "reason_code": "scope_denied", "deny_rule": "no-gpt4" },
  "grant_context": null,
  "lineage": { "binding": "bound", "edge_label": "verified", "...": "..." },
  "causal_neighbors": [],
  "anomalies": ["authority_without_causation"]
}

coverage ∈ captured | sampled_out | dropped | aggregated | pre_rollout | expired_by_retention. provenance_check ∈ ok | redacted | missing_lineage | expired_by_retention | sampled_out | failed.

Owner binding — accountability on the governance artifact

GET /v1/governance/artifacts/{request_id} projects the accountable human behind the decision into a signed accountability block, and maps it to EU AI Act Art. 14 (human oversight). The block is omitted entirely — never null — when no owner is known, so artifacts minted before owner binding re-derive to byte-identical signed bodies.

"accountability": {
  "agentId": "sales-assistant",
  "ownerId": "alice@example.com",
  "ownerSource": "agent_profile",
  "evidence": "committed"
}

evidence says how well the claim is evidenced: committed means the owner sits inside the bound lineage row's decision (covered by lineage_digest → provenanceDigest → the chain, so a post-hoc edit is chain-detectable); recorded means it comes only from the non-hashed audit column. ownerSource ∈ agent_profile | api_key_user: an agent caller's owner is its profile owner_id; an API-key caller's owner is the key's user. The same resolver stamps br_principal.owner_id into the signed trust envelope, so the envelope, the audit row, and the artifact never disagree.

Agent inventory — the shadow-agent view

GET /v1/governance/agents/inventory?period=day|week|month (governance.read) classifies every caller BrainstormRouter routed for in the window against the two identity registries. No scanning of cloud accounts or repos: this is the traffic the router already observes, joined to the agent profiles and mesh identities it already keeps.

ClassMeaning
registeredthe agent id has a profile; ownerless: true when no accountable owner is bound
unregisteredan agent id seen in traffic with no profile (deleted, never enrolled, or forged)
untagged keyAPI-key traffic carrying no agent identity at all — where scripts and un-enrolled agents hide
assertedan X-BR-Agent-Id header the policy plane accepted for scoping, with agent_registered

summary.shadow_ratio is (unregistered + untagged) requests / total requests — the number that falls as callers are enrolled — and is null, never 0, for an empty window. Idle registered agents are still listed (idle: true). Header assertions are verified against the profile registry on every request and stamped on the response as X-BR-Agent-Assertion: registered | unregistered; the answer is chain-committed inside the lineage row's decision.accountability (asserted_agent_id, agent_registered), which is the source the inventory reads. The asserted block is null (and notes says why) when the lineage store cannot be read — never silently empty.

{
  "window": { "period": "week", "since": "…", "until": "…" },
  "summary": {
    "total_requests": 1240,
    "registered_agents": 4,
    "ownerless_agents": 1,
    "unregistered_agents": 1,
    "untagged_keys": 2,
    "mesh_identities": 3,
    "shadow_ratio": 0.18,
    "shadow_requests": 223
  },
  "agents": [
    { "agent_id": "ghost-7", "classification": "unregistered", "request_count": 91, "…": "…" }
  ],
  "untagged_keys": [
    {
      "api_key_id": "…",
      "request_count": 132,
      "hint": "Traffic on this key carries no agent identity. …"
    }
  ],
  "asserted": [{ "asserted_agent_id": "ghost-7", "agent_registered": false, "request_count": 91 }],
  "mesh": [
    { "spiffe_id": "spiffe://brainstorm.internal/agent/…", "hostname": "reviewer", "online": true }
  ],
  "notes": []
}

Also available as the MCP tool br_agent_inventory and via governance.agentInventory() (TypeScript) / governance.agent_inventory() (Python).

Human approval — one queue for every require_approval

A policy-pack rule (or an agent-manifest tool policy) whose action is require_approval now means the same thing on every enforcement point — the MCP governor, the tool-call firewall, and the streaming tool-call interceptor all use the same durable queue that GET /v1/approvals/pending reads. Before this, the firewall silently mapped it to a block and the interceptor severed the stream with nothing for a human to review.

For a completion tool call the client executes, the semantics are:

  1. The call is withheld and a tool_call review record is queued. The response is

403 approval_required with the approval_id, a recovery block, and an X-BR-Approval-Id header (on streams the header is set and the denial chunk names the id). Retrying before approval dedupes onto the same record.

  1. A reviewer with approvals.write calls POST /v1/approvals/{id}/approve. The record

becomes a one-shot allowance. scope: "exact" (default) means the retry must carry the same argument hash the reviewer saw; scope: "tool" widens it to any arguments for that tool, once. The widening is recorded on the record.

  1. The caller retries the same request. The enforcement point finds the allowance,

consumes it (consumedAt, consumedByRequestId), and the call passes. An allowance lapses 15 minutes after approval and can never be spent twice.

Reviewers see the tool name, the enforcement surface, the requesting agent and its accountable owner, and the argument keys — never the argument values. High-risk tools (shell, SQL, exec) require a review note. The EU AI Act policy pack's Art. 14 rules use this path, so "human oversight" on a completion is now a real review, not a denial.

{
  "error": {
    "type": "approval_required",
    "approval_id": "2f1c…",
    "tool_name": "execute_sql",
    "surface": "firewall",
    "rule": "euaia-oversight-restricted-tool"
  },
  "recovery": {
    "action": "escalate",
    "endpoint": "POST /v1/approvals/2f1c…/approve",
    "message": "A reviewer with approvals.write must approve this request … then retry the same tool call."
  }
}

Trace / request reconstruction

GET /v1/governance/lineage?trace_id=… (or ?request_id=…) reconstructs a causal episode ordered by span parentage. Every record carries an edge_label (verified | claimed | unverified) derived from the row's committed fields — one wire shape in all modes. Add ?live=true to read the recent in-memory ring buffer through the same mapper.

curl "https://api.brainstormrouter.com/v1/governance/lineage?trace_id=0af7651916cd43dd8448eb211c80319c" \
  -H "Authorization: Bearer br_live_..."

Chain + provenance verify

GET /v1/governance/audit/chain/verify verifies the hash chain and adds per-row provenanceChecks[] recomputing provenanceDigest from the stored columns + the bound lineage bytes. The provenance recompute is best-effort and never flips the chain result.