Open source · Apache-2.0 Inspired by CycloneDX ML-BOM Runs in your boundary

Know what your AI agents are made of and prove what they did.

ABOM is the Agent Bill of Materials: every agent action becomes a signed, tamper-evident record an auditor can verify without trusting you — what the agent is, what it did, and proof nobody edited the story afterwards. Blocking is one flag away; the evidence is the product. Cryptographic, not reputational.

$pip install abom-cli && abom scan .

Composition is opaque

No one can say, in one signed document, which models, tools, prompts, data and policies an agent is built from — or prove the deployed agent matches what was approved.

Actions are unaccountable

When an agent makes a consequential decision, the evidence is scattered logs you must trust — not a tamper-evident record you can verify and hand to a regulator.

Nothing stops a bad action

A prompt-injected agent that calls a tool it was never authorized to use is, in most stacks, only logged after the fact — not blocked before it runs.

The /authorize API

Authorize every tool call — with zero agent code

Point your agent's MCP client at the ABOM broker instead of its MCP server. Every tools/call is authorized before it runs, and comes back ALLOW/DENY plus a signed, notarized receipt. You don't wrap tools or write integration code — the agent doesn't even know the API is there.

  • Nothing to instrument. The broker hooks the MCP loop at the tool-call step. A denied call never reaches the upstream server — structural, not cooperative.
  • A receipt, not just a log. Each verdict carries a Merkle inclusion proof + signed tree head — hand it to your buyer's security team.
  • Or evidence-first: the v0.2 gateway. abom gateway run records every call as a signed, fsync'd provenance record — inspect-only by default, --enforce to block. See it in the quickstart.
  • Or call it directly. Not on MCP? POST /authorize an action, get the same verdict + receipt.
  • Free to start. Self-host free forever; the neutral hosted endpoint is the paid tier, metered per key.
shell
# point the agent's MCP client at the broker —
# it authorizes every tools/call against your API
$ abom broker abom.json \
    --authorize-url https://api.abom.ai/authorize \
    --api-key abom_…

# a prompt-injected tool call the agent was never
# granted comes back:
{
  "verdict": "deny",
  "rule": "tool_not_in_manifest",
  "receipt": { "inclusion_proof": {…},  # notarized
               "head_signature": {…} }  # signed
}
# the upstream never saw it. and you can prove it.
What ABOM is

Three questions every agent should answer

For a non-technical reader: think of a nutrition label (what's inside), a permission slip (what it's allowed to do), and a flight recorder (what it actually did) — for AI agents, all signed so they can't be faked.

01

What is it made of?

→ Composition Manifest

A signed inventory of every model (with weight hashes), tool, prompt, data source, framework and policy. Generated by abom scan.

02

What is it allowed to do?

→ The inline gate

Deny-by-default enforcement against the signed manifest, before the action executes. A guardrail, not a log.

03

What did it actually do?

→ Provenance + Notary

A hash-chained, Merkle-notarized record of every decision, with proofs anyone can verify — without trusting the operator.

The inline gate

Block the action — don't just log it

A SIEM tells you an agent wired money to an attacker yesterday. ABOM's gate stops the call before it executes because the tool isn't in the agent's signed manifest. This is the difference between a guardrail and an audit trail.

  • Deny-by-default. A tool not in the signed manifest is blocked, not logged-and-allowed.
  • Signature-pinned. Pin the authorized signer and the gate refuses to enforce a manifest that was tampered or re-signed by anyone else — "signed" authenticates who, not just integrity.
  • Framework-agnostic. A decorator, a wrapper, or a direct check — no LangChain / MCP lock-in.
  • Three decidable rules: undeclared tool, endpoint not on allowlist, confidential data egress.
  • Every decision is notarized — allowed and denied alike.
agent.py
# pin the signer: a re-signed manifest is refused
from abom import Gate, Action, ActionDenied

gate = Gate(signed_manifest,
            trusted_keys={"9a72f7ef…"})  # pinned
# forged manifest, attacker's key → refused

@gate.gated()              # wrap any tool
def wire_transfer(amount, to):
    ...                    # never runs if
                           # undeclared

# a prompt injection makes the agent try this:
try:
    wire_transfer(1_000_000, to="attacker")
except ActionDenied as e:
    e.decision.rule   # → "tool_not_in_manifest"
    # the money never moved. denial notarized.
The MCP broker

Move the gate out of the agent's process

A decorator trusts the agent to route calls through it. A prompt-injected agent can just… not. The broker relocates the gate to a choke point the agent doesn't control: it sits between the agent and its MCP server, and every tools/call transits the gate before it's forwarded. Deny-by-default becomes structural, not cooperative.

  • Nothing to instrument. Point the agent's MCP client at the broker; the manifest auto-builds from tools/list. New tool at runtime → auto-denied.
  • Denied calls never reach the server. A blocked tools/call is answered with a notarized JSON-RPC error — the upstream tool is never invoked.
  • Every decision lands in the durable transparency log — allowed and denied alike, surviving restart.
  • Honest scope. Structural for brokered tools; pair with egress containment to stop out-of-band calls the agent makes without transiting the broker.
broker
# the agent gets its tools FROM the broker
$ abom broker abom.json \
    --upstream https://mcp.internal/rpc \
    --trusted-key 9a72f7ef… --log gate.mlog

# agent (prompt-injected) tries a tool it
# was never granted:
tools/call  wire_transfer   # → DENIED (-32001)
# the upstream server never saw the call.
tools/call  lookup_customer # → forwarded
The Notary

Tamper-evidence you can verify yourself

A plain hash chain proves internal consistency, but an operator who controls the store can rebuild it from scratch. ABOM uses an append-only Merkle transparency log (the same RFC 6962 construction behind Certificate Transparency) — inclusion and consistency proofs anyone can check. Paired with the witness and anchor below, the record becomes verifiable without trusting whoever produced it.

  • Inclusion proof — "this decision is in the log, under this signed root."
  • Consistency proof — "nothing already published was edited or deleted."
  • Keys in KMS / HSM — the private key never leaves hardware; verification is backend-independent.
  • An auditor, insurer or regulator relies on the proof, not on our word.
auditor.py
# anyone verifies — no trust in the operator
decision = gate.check(action)

# it IS in the signed log:
verify_inclusion(entry, proof)    # → True
# signed tree head (KMS key):
verify_payload(head, head_sig)    # → True

# attacker tries to backdate the record:
verify_inclusion(forged, proof)   # → False
# the proof no longer matches.
The witness & the anchor

Proof the operator can't quietly rewrite

A Merkle log is tamper-evident to outsiders — but the operator holds the store and the key, so on its own it can still be rebuilt from scratch. Two independent things close that gap and make the record something a third party can actually rely on.

  • A witness cosigns the log with its own key and refuses unless a consistency proof shows the log only grew. Rewrite or truncate history, and the witness won't sign the forged head.
  • An RFC 3161 timestamp anchors the root to an independent authority the operator doesn't control. Under eIDAS Art. 41, a qualified timestamp carries a legal presumption of time and integrity — evidence regulated buyers already recognize.
  • Honest about scope. A self-hosted witness is defense-in-depth; genuine non-equivocation comes from an independent one. The timestamp is the third-party proof that stands today.

The lineage. This is the same construction as Certificate Transparency and Sigstore. ABOM's Merkle log is Rekor-shaped; the witness is the independent cosigner role Sigstore is now baking into Rekor. Run it yourself for defense-in-depth today; the neutral, multi-party witness network is the natural next step.

notary
# a second party cosigns — with a different key
witness.cosign(head, consistency=proof)

# operator rewrites history, asks again:
witness.cosign(forged_head, consistency=bad)
# → WitnessRejected: not append-only

# anchor the root to an RFC 3161 authority
anchor_head(head, tsa_url="https://tsa…")
# → signed proof it existed by time T 
The registry

Consult every event — across agents, over time

Every manifest, gate decision, model call and approval lands in the Notary as a queryable record. Ask it questions the way an auditor or a risk team actually would — by agent, by time window, by data classification — and get an answer you can verify, not just read.

By time period

Every event an agent emitted last quarter, last week, or between any two dates.

Tokens & cost

Prompt and completion tokens, model spend, and per-agent totals — rolled up for any window.

Decisions & denials

Every ALLOW/DENY, the rule that fired, top blocked tools, and gate latency.

Data & approvals

Which actions touched confidential data, what egressed, and who approved what.

query the registry
# every event for an agent, last quarter
abom registry events \
 --agent loan-doc-agent \
 --from 2026-04-01 --to 2026-06-30

# token + cost rollup, same window
abom registry usage \
  --agent loan-doc-agent --period Q2

# or over HTTP — filter by decision
GET /v1/registry/events
  ?agent=loan-doc-agent
  &from=2026-04-01&to=2026-06-30
  &verdict=deny
  &classification=confidential
loan-doc-agent · Q2 2026
04-12 09:14model_callqwen2.5-coder · 812 tok
04-12 09:14allowhttp_fetch → internal-kyc.bank
05-03 16:41denywire_transfer — not in manifest
05-28 11:02denyconfidential data → egress blocked
06-19 14:30allowsubmit memo · approved by operator
3,184
events
1.46M
tokens
17
denials
€38
model cost
Result carries a Merkle inclusion proof — the auditor verifies it wasn't doctored.

This is what makes the registry more than a dashboard: a query result over any time window comes with a cryptographic proof, so a regulator can trust the answer without trusting us. Cross-agent, time-windowed registry queries are in construction.

How it fits together

Scan · Gate · Notarize

Three steps, all inside your own infrastructure — air-gap capable. Nothing leaves without explicit, logged policy.

1
abom scan

Scan

Detect every component an agent is built from and emit a signed Composition Manifest — fingerprinted by composition_sha256.

2
the gateway

Attest

Route tool calls through the gateway: every call becomes a signed record before executionwould_deny as evidence by default, hard ALLOW/DENY with --enforce.

3
the Notary

Notarize

Append every decision to a Merkle transparency log with a signed tree head — independently verifiable proof of what happened.

🔒  Customer trust boundary — keys in KMS/HSM · ed25519 · trust is in the keys + proofs, not our word
The architecture

One chain of custody, CI to auditor

Every plane of the system, live below — click any node for what it does and why it's there; watch the evidence flow 1 → 5 from the build pipeline through the gateway and local chain to the verifiers outside the operator's control.

The interactive architecture needs a wider screen — open it full-page →
For the technical reader

The two artifacts

Both extend CycloneDX ML-BOM and are linked by hash, so a swapped model or tool at runtime is detectable as drift.

The composition manifest (what the agent is) linked by composition hash to action provenance records (what the agent did) composition manifest what the agent is models · tools · prompts signed at build composition_sha256 action provenance what the agent did one record per tool call signed · hash-chained
What the agent is

Composition Manifest

The ingredients label · generated at build/deploy

A signed inventory: models (with weight hashes), tools (with egress allowlists), prompts (hashed), data sources (classified), policies, frameworks and MCP servers — plus declared controls (egress, HITL, residency) and an EU AI Act risk class. Identified by composition_sha256 and ed25519-signed.

What the agent did

Action Provenance Record

The flight recorder · per consequential action

One hash-chained record per action — and in v0.2, every record is individually ed25519-signed: the decision (allow / deny / would_deny), policy and floor hashes, guardrail verdicts (detectors[]), salted-HMAC argument commitments instead of payloads, and a linked outcome record per forwarded call. Any edit, insertion, deletion or reorder breaks the chain at a known point; even degradations and refused policies enter the chain as signed events.

Standard-first

Inspired by CycloneDX — not a fork of it

ABOM borrows the component model of the dominant, ECMA-standardized SBOM format rather than competing with it. CycloneDX answers "what is it made of." ABOM extends the idea into the agent runtime, adding the enforcement and provenance layer CycloneDX doesn't model.

CycloneDX (incl. ML-BOM)

  • What is it made of?
  • Software & ML components
  • One BOM document
  • Schema validation by the consumer
  • Integrity via external signing

ABOM (the additions)

  • Made of + allowed to do + what it did
  • Full agentic system + per-action runtime
  • Manifest + gate + notarized provenance
  • Deny-by-default enforcement, inline
  • Merkle transparency log — verifiable proofs

ABOM's component model is aligned with CycloneDX naming today; native CycloneDX import/export is on the roadmap. ABOM does not claim CycloneDX conformance.

Honest status

What's real vs. roadmap

ABOM is draft v0.1, pre-1.0. Honesty about maturity is a feature for a trust project — here's exactly what ships today.

CapabilityStatus
abom scan → signed Composition ManifestBuilt
Hash-chained Action Provenance + verificationBuilt
ed25519 signingBuilt
Inline gate — deny-by-default enforcementBuilt
Merkle transparency log — inclusion + consistency proofsBuilt
Decidable policy checks (abom verify)Built
KMS/HSM-backed signing (provider wiring)In construction
OPA/Rego policy engine · hardened Notary registry · SDK hooksIn construction
Native CycloneDX / SIEM export · eBPF egress · air-gap bundlePlanned
Why now

The timing

Agents started acting

In 2025–26 agents began taking consequential, real-world actions faster than anyone built the controls to bound them.

The precedent is proven

SBOM went from optional to mandated in ~3 years. Agent accountability is on the same arc — and the muscle memory exists.

The rail exists

CycloneDX shipped ML-BOM. ABOM is the natural extension to full agents + runtime provenance — extend the winner, don't fork.

Regulation is the upside

EU AI Act Art. 12 & DORA point at accountability for AI. Deferred to ~2027 — so ABOM sells present-tense control now, with the mandate as upside.

What ABOM stands for

Standard · Signed · Neutral · Yours

Standard

Inspired by CycloneDX, open. Define the format, become infrastructure.

Signed

Tamper-evident, regulator-grade. Cryptographic, not reputational.

Neutral

Any model, any framework — we sell neither. Only an independent can be the bill-of-materials layer.

Yours

Runs inside your boundary; nothing leaves. Air-gap capable, sovereign by default.

Make every agent answerable.

What is it made of, what is it allowed to do, and what did it do? — answered in a signed, standard, portable artifact you can hand to an auditor.