{"_id":"@blockbrainlabs/decision-core","name":"@blockbrainlabs/decision-core","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@blockbrainlabs/decision-core","version":"0.1.0","description":"Portable, replayable policy decision governor for AI agents","type":"module","main":"dist/src/index.js","types":"dist/src/index.d.ts","scripts":{"build":"tsc","postbuild":"chmod +x dist/src/surfaces/cli/bin.js","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","smoke:tarball":"node scripts/tarball-smoke.mjs","prepack":"npm run build","lint":"oxlint ."},"dependencies":{"@modelcontextprotocol/sdk":"^1.29.0","pino":"^9.6.0","yaml":"^2.8.4","zod":"^3.24.0"},"devDependencies":{"@types/better-sqlite3":"^7.6.13","@types/node":"^22.0.0","oxlint":"^0.16.0","typescript":"^5.7.0","vitest":"^4.1.9"},"overrides":{"hono":"^4.12.27","qs":"^6.15.2"},"engines":{"node":">=20.0.0"},"license":"Apache-2.0","publishConfig":{"access":"public"},"bin":{"decision-core":"dist/src/surfaces/cli/bin.js"},"exports":{".":{"types":"./dist/src/index.d.ts","import":"./dist/src/index.js"}},"optionalDependencies":{"better-sqlite3":"^12.9.0"},"directories":{"doc":"docs","test":"test"},"repository":{"type":"git","url":"git+https://github.com/blockbrain-ai/decision-core.git"},"keywords":["ai-agents","policy","governance","decision-core","mcp"],"bugs":{"url":"https://github.com/blockbrain-ai/decision-core/issues"},"homepage":"https://github.com/blockbrain-ai/decision-core#readme","author":{"name":"Blockbrain Labs","email":"admin@blockbrain.au"},"contributors":[{"name":"Chris Walker","email":"admin@blockbrain.au"},{"name":"Dustin Henning"}],"_id":"@blockbrainlabs/decision-core@0.1.0","gitHead":"46017a14e1ed32d575888d068f79766ae177cad7","_nodeVersion":"24.8.0","_npmVersion":"11.6.0","dist":{"integrity":"sha512-wCBAkfC5YmbYy3p9Vkw2pLIpjYs6WsZCFiFZNAYQfIcSZFN5I9VauHd3B8YtU4/fylqOKNBvUA595PiXPDNTWQ==","shasum":"f8d48aeeee2c0e2d2ce6af8ba75b9105786a2122","tarball":"https://registry.npmjs.org/@blockbrainlabs/decision-core/-/decision-core-0.1.0.tgz","fileCount":1240,"unpackedSize":3054430,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC4vSxf1ESoq7TfiisSmVCXSYVqPPeyySbAlpaexne4+QIgHkeaHHhQsHuInYs+0BTwdwqKsS7Y8OOtcnoUMtLrojI="}]},"_npmUser":{"name":"chrispaulwalker","email":"admin@blockbrain.au"},"maintainers":[{"name":"chrispaulwalker","email":"admin@blockbrain.au"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/decision-core_0.1.0_1782620239711_0.437178985049419"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-28T04:17:19.521Z","0.1.0":"2026-06-28T04:17:19.909Z","modified":"2026-06-28T04:17:20.114Z"},"maintainers":[{"name":"chrispaulwalker","email":"admin@blockbrain.au"}],"description":"Portable, replayable policy decision governor for AI agents","homepage":"https://github.com/blockbrain-ai/decision-core#readme","keywords":["ai-agents","policy","governance","decision-core","mcp"],"repository":{"type":"git","url":"git+https://github.com/blockbrain-ai/decision-core.git"},"contributors":[{"name":"Chris Walker","email":"admin@blockbrain.au"},{"name":"Dustin Henning"}],"author":{"name":"Blockbrain Labs","email":"admin@blockbrain.au"},"bugs":{"url":"https://github.com/blockbrain-ai/decision-core/issues"},"license":"Apache-2.0","readme":"<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/blockbrain-ai/decision-core/main/docs/images/hero.png\" alt=\"Decision Core — the deterministic safety layer for AI agents: allow, approve, or deny every action with a tamper-evident audit trail\" width=\"100%\">\n</p>\n\n<p align=\"center\">\n  <img src=\"https://img.shields.io/badge/status-pre--release%20v0.1-f0a35e?style=flat-square&labelColor=0d1117\" alt=\"status: pre-release v0.1\">\n  <img src=\"https://img.shields.io/badge/license-Apache--2.0-3fb950?style=flat-square&labelColor=0d1117\" alt=\"license: Apache-2.0\">\n  <img src=\"https://img.shields.io/badge/built%20with-TypeScript-3178c6?style=flat-square&labelColor=0d1117\" alt=\"built with TypeScript\">\n  <img src=\"https://img.shields.io/badge/node-%E2%89%A520-339933?style=flat-square&labelColor=0d1117\" alt=\"node >= 20\">\n  <img src=\"https://img.shields.io/badge/local--first-no%20DB,%20no%20LLM,%20no%20network-39c5bb?style=flat-square&labelColor=0d1117\" alt=\"local-first: no DB, no LLM, no network\">\n  <img src=\"https://img.shields.io/badge/MCP-server%20built--in-8957e5?style=flat-square&labelColor=0d1117\" alt=\"MCP server built-in\">\n</p>\n\n<p align=\"center\"><b>Govern what your AI agent can do — <i>before</i> it acts — and keep a tamper-evident record of every decision.</b></p>\n\n---\n\nYour agent can delete data, move money, deploy, or leak secrets. Most setups have **no brakes and no record**.\n\n**Decision Core** sits between your agent and its tools and enforces policy on every action — returning\n**`allow`**, **`approve_required`**, or **`deny`** — then writes a **SHA-256 hash-linked audit record** you can\nverify later. It's deterministic: **no database, no LLM, and no network are required.** The whole engine runs\nin-process from four small libraries, or as an MCP server, over HTTP, or from the CLI.\n\nThe scary part of dropping a policy engine in front of a live agent is *what if it blocks the wrong thing?*\nSo adoption is **observe-first**: install in watch mode, see exactly what enforcement *would* have blocked,\nthen flip on real blocking with one command.\n\n```bash\nnpm install @blockbrainlabs/decision-core\n```\n\n```console\n$ decision-core init --profile team\n  Created decision-core.yaml + .decision-core/policy-pack.yaml\n  Unknown actions will be denied by default.\n\n$ decision-core doctor\n  [OK] config        decision-core.yaml found and valid\n  [OK] pack          5 rules (0 deny, 1 approval)\n  [OK] deny-unknown  unknown actions will be denied\n  [OK] mode          ENFORCE — denied actions are blocked\n\n$ decision-core evaluate --action read_file           → allow             (matched allow-read)\n$ decision-core evaluate --action delete_user         → approve_required  (matched approve-destructive)\n$ decision-core evaluate --action exfiltrate_secrets  → deny              (matched deny-unknown-default)\n\n  + every decision → SHA-256 hash-linked, tamper-evident audit record\n```\n<p align=\"center\"><sub>Real CLI output. <code>read_file</code> → allow · <code>delete_user</code> → approve · unknown tool → deny. Every decision is logged and hash-linked.</sub></p>\n\n## Why it exists\n\nContent guardrails check *what the model says*. Decision Core governs *what the agent does* — and proves it.\n\n- **A real gate, not a logger.** Deny-wins arbitration: if any rule says deny, the action is denied — no ambiguity, no model in the loop.\n- **Adopt without breaking anything.** Observe mode records what it *would* block while blocking nothing, so you onboard a running agent with zero risk.\n- **Tamper-evident by construction.** Every step of a decision is a hash-linked evidence record; change one byte and `verify()` pinpoints the break.\n- **Boringly portable.** In-memory by default. No infra to stand up, nothing to page you at 3am. Drop it into one process or run it as a service.\n\n## Features\n\n| | |\n|---|---|\n| **Deny-wins policy engine** | A deterministic PDP/PEP: glob-matched rules resolve to `allow` / `approve_required` / `deny`, and any deny wins. No LLM, no flakiness. |\n| **Observe-first onboarding** | `setup → observations → enforce`. Watch what *would* be blocked (redacted — no tool args), review impact, then promote to enforcement with a backed-up, validated config. |\n| **Tamper-evident evidence chains** | Each decision emits SHA-256 hash-linked records (`auditHash = hash(sequence ‖ previousHash ‖ payloadHash ‖ op)`). `verifyChain()` detects and locates tampering. |\n| **Approval workflows** | Risky actions escalate to `approve_required` (human review) instead of hard-failing, with separation-of-duties on resolution. |\n| **Policy packs** | Pre-built YAML rule sets — `personal`, `team`, `fintech`, `healthcare`, `saas` — loadable and customizable; a linter and conflict analyzer catch contradictions before they ship. |\n| **Four surfaces, one engine** | The same core runs as an **SDK**, a **CLI**, an **MCP server** (for IDEs/agents), and an **HTTP** service. |\n| **Tenant isolation** | Every record and rule is partitioned by `tenantId`; the HTTP server (org mode) binds each request to the authenticated token's tenant, never the request body. |\n| **Zero mandatory infra** | Runs entirely in memory. Optional SQLite for durable logs degrades gracefully if the native binding isn't present. |\n\n## How it works\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/blockbrain-ai/decision-core/main/docs/images/pipeline.svg\" alt=\"Architecture: an agent tool call flows through the Decision Runner (quality gate → deny-wins policy → trust routing → clause enforcement → execute) to an allow/approve/deny verdict, recording a hash-linked evidence chain at every step\" width=\"100%\">\n</p>\n\nA tool call enters the **Decision Runner**, which evaluates it through a deterministic pipeline and records an\nevidence entry at every step. The default path is the **deny-wins policy engine + evidence chain**; trust routing\nand clause enforcement engage when you configure them.\n\n## Quickstart\n\n### Option A — the SDK (60 seconds)\n\n```bash\nnpm install @blockbrainlabs/decision-core\n```\n\n```typescript\nimport { quickStart, ActionApprovalDecision } from '@blockbrainlabs/decision-core';\n\n// Declare the tools your agent may use. Anything unlisted is denied by default.\nconst dc = await quickStart({ tools: ['read_*', 'write_*', 'search_*'] });\n\nconst result = await dc.evaluate(\n  new ActionApprovalDecision('delete_file').withInputProvider(() => ({\n    actionName: 'delete_file',\n    actionParams: { path: '/data/report.csv' },\n    requestedBy: 'agent-1',\n    riskIndicators: ['destructive'],\n  })),\n);\n\nconsole.log(result.verdict);                   // → 'blocked'  (no allow rule matched → deny-unknown)\nconsole.log(result.evidenceChain.recordCount); // → 4\nconsole.log(result.evidenceChain.headHash);    // → '11e917d5…'  (SHA-256 head of the chain)\n\nconst why = await dc.explain(result.correlationId);\nconsole.log(why.summary);          // → \"Decision denied by policy rule(s): deny-unknown-default.\"\nconsole.log(why.evidenceSummary);  // → \"4 evidence record(s) in chain; … head hash: 11e917d5…\"\n```\n\n> The output above is copied from a real run. Need a one-liner gate without the full pipeline?\n> `await evaluate({ action: 'delete_file', surface: 'api' }, { denyUnknownDefault: true })` returns `{ decision: 'deny' }`.\n\n### Option B — the CLI (observe-first)\n\n```bash\nnpm install @blockbrainlabs/decision-core\n\nnpx decision-core init --profile team   # writes config + policy pack, deny-unknown ON\nnpx decision-core doctor                 # health check + tells you observe vs enforce\nnpx decision-core evaluate --action delete_user   # → approve_required\nnpx decision-core evaluate --action read_file     # → allow\n```\n\nTo onboard a **live** agent safely, install in observe mode and review before enforcing:\n\n```bash\nnpx decision-core setup            # detects your tools, installs in OBSERVE mode (blocks nothing)\n# ... run your agent normally ...\nnpx decision-core observations --recommend   # see what enforcement WOULD have blocked\nnpx decision-core enforce          # turn on real blocking (backs up + validates the config)\n```\n\n### Option C — MCP server\n\n```bash\nnpx decision-core serve --mcp\n```\n\nExposes read-only policy tools (`evaluate`, `query_policy`, `explain_decision`, `audit_trail`, `dc_observations`, …)\nto any MCP client. Policy-**mutating** tools are off by default and require explicit opt-in.\n\n## The part you'll actually brag about: verifiable audit\n\nEvery decision produces a hash-linked chain. Tampering with any record breaks every record after it, and\nverification tells you exactly where:\n\n```typescript\nconst result = await dc.evaluate(decision);\n\nresult.evidenceChain.recordCount; // 4\nresult.evidenceChain.headHash;    // 'a1b2c3…'  SHA-256 head of the chain\nresult.auditHash;                 // SHA-256 of the decision payload\nresult.correlationId;             // trace id linking every evidence record\n\n// Each record: auditHash = SHA-256(sequence ‖ previousHash ‖ payloadHash ‖ operationType)\n// EvidenceChainService.verify() walks the chain and reports the first broken record.\n```\n\nThis is the difference between \"we log decisions\" and \"we can prove decisions weren't altered.\" See the\n[Evidence Chain Guide](docs/EVIDENCE-CHAIN-GUIDE.md).\n\n## Decision Core vs. content guardrails\n\nDecision Core is **complementary** to validation libraries — it governs *actions*, they validate *text*. Use both.\n\n| | **Decision Core** | Guardrails AI / NeMo Guardrails |\n|---|---|---|\n| **Scope** | Should this **action** run at all? | Is this model **input/output** safe? |\n| **Engine** | Deny-wins PDP/PEP, deterministic | Validators / dialog rails |\n| **Policy as data** | Hot-reloadable YAML packs | Python validators / Colang |\n| **Approval workflows** | Built-in escalation to humans | Not built-in |\n| **Audit** | Hash-linked, tamper-evident chains | Logging only |\n| **Historical replay** | Replay with point-in-time policy | — |\n| **LLM required** | No — core is fully deterministic | Often yes |\n| **Database required** | No — in-memory default | Varies |\n| **MCP server** | Built-in | — |\n\n**What Decision Core deliberately does *not* do:** content filtering, prompt engineering, agent orchestration,\nor secret storage. Pair it with a content-guardrails library for input/output safety.\n\n## Status & honesty\n\nThis project keeps a single source of truth — [`docs/STATUS-LEDGER.md`](docs/STATUS-LEDGER.md) — that **wins over\nany marketing language, including this page.** The short version:\n\n- **Proven & tested today:** SDK · CLI · MCP · HTTP surfaces · deny-wins policy engine · observe→enforce\n  onboarding · tamper-evident evidence chains · tenant isolation · the **Hermes** Python-runtime integration\n  (verified end-to-end through Hermes's real tool-dispatch path).\n- **Optional / runs when configured:** SQLite persistence, trust routing & model-assisted decision patterns,\n  G-Brain evidence sink.\n- **Experimental:** the **OpenClaw** TypeScript-runtime adapter (not yet proven through a full agent loop — run it `failMode: 'closed'`).\n- **Not shipped:** any Postgres/managed-persistence tier.\n\n> **Default posture, stated plainly:** with no policy pack loaded and `denyUnknownDefault` unset, an unmatched\n> action is **allowed** — deny-unknown is opt-in (the quick starts above enable it). Load a pack or set the flag\n> before relying on deny-wins for unknown actions.\n\nThe library is **pre-1.0 (v0.1)** and not yet published to npm; the public release is a deliberate, separate step.\n\n## Docs\n\n| | |\n|---|---|\n| [Full usage guide](docs/USAGE.md) | Personal / Team / Enterprise setups, full CLI reference, org mode |\n| [Architecture](docs/ARCHITECTURE.md) | The pipeline, surfaces, and persistence in depth |\n| [Policy authoring](docs/POLICY-AUTHORING-GUIDE.md) | Writing rules, packs, and structured clauses |\n| [Evidence chains](docs/EVIDENCE-CHAIN-GUIDE.md) | How hash-linking and verification work |\n| [Trust routing](docs/TRUST-ROUTING-GUIDE.md) | Surfaces, tiers, and decision patterns |\n| [Hermes integration](docs/INTEGRATION-GUIDES/hermes.md) | The proven end-to-end drop-in |\n| [Status ledger](docs/STATUS-LEDGER.md) | What's proven vs. experimental — the source of truth |\n\n## Requirements\n\n- **Node.js ≥ 20**\n- Runtime libraries: `zod`, `pino`, `yaml`, `@modelcontextprotocol/sdk` — **no database, no LLM, no network.**\n- Optional: `better-sqlite3` for durable logs (degrades gracefully if absent).\n\n## Contributing\n\n```bash\nnpm install\nnpm test          # vitest\nnpm run typecheck\nnpm run lint\n```\n\nTests live next to source (`foo.ts` → `foo.test.ts`). Every repository method takes `tenantId` first; every\nevidence record carries `correlationId`, `timestamp`, `tenantId`, and `auditHash`. Sign off your commits\n(`git commit -s`) — contributions are accepted under the [DCO](https://developercertificate.org/). See\n[CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Maintainers\n\nBuilt and maintained by **Blockbrain Labs**.\n\n- **Chris Walker** — <admin@blockbrain.au>\n- **Dustin Henning**\n\nFollow [**@blockbrain_labs**](https://x.com/blockbrain_labs) on X. Questions: <admin@blockbrain.au>. For\nsecurity issues, see [SECURITY.md](SECURITY.md) — please don't open a public issue.\n\n## License\n\n[Apache-2.0](LICENSE) © Blockbrain Labs — see [LICENSE](LICENSE) and [NOTICE](NOTICE).\n","readmeFilename":"README.md","_rev":"1-6fa8bf0704bfd3ce22a38de01f127ab7"}