Demo Docs Pricing Compare Integrity Sign in Try it free

DarkMatter Documentation

DarkMatter records every AI agent action as a verifiable, independently auditable record. Every commit is hashed client-side, optionally signed with your own key, and stored outside your infrastructure. Works with any language, any model, any framework.

Commit  A sealed, timestamped record of one AI agent action, stored outside your system and independently verifiable.
Agent   A named entity you register in DarkMatter, with its own ID (dm_agent_...) and API key. Every commit is attributed to it.
Where to startNew to DarkMatter? Follow the Python quickstart. 2 minutes to your first record.
Integrating an existing agent? Jump to SDK wrappers for Anthropic, OpenAI, LangGraph, and more.
Need non-repudiation? Go directly to L3 setup to configure customer signing keys.

Overview

DarkMatter is the independent verification and audit layer for AI agent decisions. Every agent action becomes a commit: an immutable node chained to its parent via SHA-256 hash linkage. The chain is independently verifiable and can be replayed, forked, or exported as a proof bundle.

OperationWhat it doesEndpoint
CommitRecord an agent decision as an immutable, verifiable recordPOST /api/commit
VerifyProve the chain was never tampered withGET /api/verify/:id
ExportDownload a portable proof bundle for offline verificationGET /api/export/:id
ReplayWalk the full decision chain root to tipGET /api/replay/:id
ForkBranch from any checkpoint without touching the originalPOST /api/fork/:id
Base URLAll API calls go to https://darkmatterhub.ai. Get your API key at darkmatterhub.ai/signup.

Quickstart: Python

Install and make your first commit in under 2 minutes. Unfamiliar with terms like commit, trace ID, or fork? See Core concepts first.

pip install darkmatter-sdk
bash
export DARKMATTER_API_KEY=dm_sk_...
bash
import darkmatter as dm

dm.configure(
    api_key="dm_sk_..."
)

ctx = dm.commit(payload={
    "input":  "Approve refund #84721? $284.00, 18 days since purchase.",
    "output": "Approved. Customer within 30-day window."
})
print(ctx["verify_url"])
python

The payload is a free-form object. Add any fields that matter to your use case — model name, agent version, confidence score, order ID, or any domain-specific context. All fields are stored, verifiable, and included in the proof bundle.

Chain multiple commits

Pass parent_id to link commits into a verifiable sequence. The SDK auto-generates a shared trace_id for the chain. The Timeline tab on any proof page shows the full chain.

# First commit
ctx1 = dm.commit(payload={
    "input":  "Approve refund #84721?",
    "output": "Approved."
})

# Chain a second commit to the first
ctx2 = dm.commit(
    parent_id=ctx1["id"],
    payload={
        "input":  "Send confirmation email?",
        "output": "Email sent to customer."
    }
)

print(ctx2["verify_url"])
python
1
Install
pip install darkmatter-sdk, which installs the SDK and CLI.
2
Get your API key
Sign up at darkmatterhub.ai/signup. Open your dashboard and go to API Keys to create your first key. Copy it when shown: it is displayed once. The key looks like dm_sk_...
3
Commit
Call dm.commit() after each agent action. Pass parent_id to chain commits into a lineage.
4
Replay and verify
dm.replay(ctx_id) walks the chain root→tip. dm.verify(ctx_id) proves integrity. Share the verify URL. No account needed to view it.
How agent attribution worksIn DarkMatter, an agent is a named entity with its own API key. Every commit is attributed to it automatically — the server derives the agent identity from the API key, so you never need to pass an agent ID separately.

Chain multiple commits

parent_id = None
for step in pipeline_steps:
    result = run_step(step)
    ctx = dm.commit(
        payload   = {"input": step, "output": result},
        parent_id = parent_id,
    )
    parent_id = ctx["id"]

# Replay the full chain
replay = dm.replay(parent_id)
for s in replay["replay"]:
    print(s["step"], s["payload"]["output"])
python

curl (no SDK)

curl -X POST https://darkmatterhub.ai/api/commit   -H "Authorization: Bearer dm_sk_..."   -H "Content-Type: application/json"   -d '{"toAgentId": "dm_agent_...", "payload": {"input": "Approve refund?", "output": "Approved"}}'
# Returns: {"id": "ctx_...", "verify_url": "https://darkmatterhub.ai/r/ctx_...", ...}
bash

Quickstart: Jupyter

Works in JupyterLab, Jupyter Notebook, Google Colab, and VS Code notebooks.

# Cell 1: install
%pip install darkmatter-sdk -q
python
# Cell 2: commit
import darkmatter as dm
import os

prompt = "Approve refund?"
result = "Approved."

ctx = dm.commit(
    payload = {
        "prompt":      prompt,
        "output":      result,
        "model":       "claude-sonnet-4-6",
        "temperature": 0.7,
    }
)
print(f"Committed: {ctx[’id’]}")
print(f"Verify: {ctx[’verify_url’]}")
python
# Cell 3: fork and compare two runs
result_b = "Rejected."

fork  = dm.fork(ctx["id"])
ctx_b = dm.commit(parent_id=fork["id"], payload={"output": result_b, "temperature": 1.0})
diff  = dm.diff(ctx["id"], ctx_b["id"])
python
Google Colab tipSet your API key as a Colab secret named DARKMATTER_API_KEY, then: from google.colab import userdata; os.environ["DARKMATTER_API_KEY"] = userdata.get("DARKMATTER_API_KEY")

TypeScript / Node.js SDK

Full TypeScript SDK with type definitions. Requires Node.js 18+ (uses native fetch).

npm install darkmatter-js
bash
// ES module (Node 18+ or wrap in async function)
const { commit, verify, replay, fork } = require('darkmatter-js');

// DARKMATTER_API_KEY and DARKMATTER_AGENT_ID read from process.env automatically
const ctx   = await commit("dm_agent_...", { input: "Summarise this", output: "Approved." });
const chain = await replay(ctx.id);
const proof = await verify(ctx.id);
javascript
Same primitives as Pythoncommit, verify, export, replay, fork: identical to the Python SDK. Source on GitHub.

Authentication

All API requests require a Bearer token. In the Python SDK, call dm.configure(api_key="dm_sk_...") to set credentials in code instead of environment variables.

Account deletionTo delete your account and all associated data permanently, go to Dashboard, Settings, and click "Delete account." You will be asked to type your email address to confirm. Deletion is automatic and immediate. This action cannot be undone.
Authorization: Bearer dm_sk_your_api_key_here
http
PropertyDetail
Formatdm_sk_ prefix followed by hex string
ScopeEach key belongs to one agent
Rate limit120 requests per minute per key
RotationRotate anytime from the dashboard without losing history

Core concepts

DarkMatter uses assurance levels (L1, L2, L3) to describe how strongly a record can be verified. Higher levels add stronger cryptographic guarantees and are additive. L3 includes all L2 and L1 guarantees.

Commit

An immutable node containing a structured payload, agent attribution, a parent reference, and an integrity hash. Once stored, it cannot be modified or deleted. Every commit gets a globally unique ctx_ ID and a verify_url that anyone can open.

Commits are permanent by design. The tamper-evident guarantee depends on every record remaining in the chain. There is no delete API. If you need to correct a record, submit a follow-up commit with redacts: "<ctx_id>" in the payload: the redaction commit becomes the authoritative note of correction while the original remains verifiable.

Parent linkage

Pass parent_id in each commit to link it to the previous step. This builds a lineage graph. Each node stores parent_hash which chains integrity hashes together. Tampering at any node breaks every downstream hash.

Trace ID

Use trace_id to group commits into one pipeline run. Pass the same trace ID across all agents in one execution to group them for compliance reports and replay.

Fork

Creates a new branch from any existing checkpoint without modifying the original chain. The fork node carries fork_of, fork_point, and lineage_root. Continue by committing with parent_id set to the fork ID.

SDK wrappers: Anthropic and OpenAI

Drop-in wrappers for the Anthropic and OpenAI Python SDKs. One import change instruments every API call automatically, with no per-call code changes required.

What gets committed automaticallyInput messages, output text, model, latency, token usage, stop reason, tool calls (as separate child records), and a scoped coverage assertion per observed API call.

Anthropic SDK wrapper

pip install "darkmatter-sdk[anthropic]"
bash
from darkmatter.integrations.anthropic import Anthropic

client = Anthropic(
    dm_api_key = "dm_sk_...",   # or set DARKMATTER_API_KEY
    api_key    = "sk-ant-...",  # standard Anthropic key
    # dm_agent_id = "dm_..."  # optional
)

# Identical to the standard Anthropic client:
response = client.messages.create(
    model     = "claude-sonnet-4-6",
    max_tokens= 1024,
    messages  = [{"role": "user", "content": "Approve this refund?"}],
)
# → Every call is automatically committed to DarkMatter
python

OpenAI SDK wrapper

pip install "darkmatter-sdk[openai]"
bash
from darkmatter.integrations.openai import OpenAI

client = OpenAI(
    dm_api_key = "dm_sk_...",   # or set DARKMATTER_API_KEY
    api_key    = "sk-...",       # standard OpenAI key
    # dm_agent_id = "dm_..."  # optional
)

response = client.chat.completions.create(
    model    = "gpt-4o",
    messages = [{"role": "user", "content": "Approve this refund?"}],
)
# → Every call is automatically committed to DarkMatter
python

With L3 signing

import darkmatter as dm
from darkmatter.integrations.anthropic import Anthropic

# Configure customer signing key once (see L3 setup)
dm.configure(
    customer_key_path = "./my-signing-key.customer.private.pem",
    customer_key_id   = "ck_...",
)

client = Anthropic(
    dm_api_key  = "dm_sk_...",
    api_key     = "sk-ant-...",
    dm_agent_id = "dm_agent_...",
)
python

Wrapper options

OptionDefaultDescription
dm_api_keyDARKMATTER_API_KEYDarkMatter API key
dm_agent_idDARKMATTER_AGENT_IDAgent ID, optional
dm_signingNoneReserved for L3 signing config (configure via dm.configure(customer_key_path=...))
dm_auto_commitTrueSet False to disable instrumentation
dm_commit_toolsTrueSet False to skip tool call child commits
dm_asyncTrueCommits sent in background thread (zero latency)
dm_debugFalsePrint full traceback on commit errors

MCP server (any MCP client)

The DarkMatter MCP server exposes Context Passport tools (darkmatter_commit, darkmatter_verify, darkmatter_replay, darkmatter_export, darkmatter_list_sessions) to any MCP-compatible AI tool. One server install reaches every MCP client at once: Claude Code, Cursor, Cline, Continue, Zed, ChatGPT Desktop, Goose, and the rest of the ecosystem.

When to use thisUse this when you want a Context Passport commit available as a tool the agent can call on demand. It captures whatever the agent explicitly invokes. For auto-capture of every event without invocation, also install the per-tool adapter (e.g., the Claude Code hook bundle below).

Install

In your MCP client's config (claude_desktop_config.json, Cursor's mcp.json, etc.):

{
  "mcpServers": {
    "darkmatter": {
      "command": "npx",
      "args": ["-y", "@darkmatterhub/mcp-server"]
    }
  }
}
json

Restart the client. The five DarkMatter tools become available to your agent.

What the agent gets

ToolPurpose
darkmatter_commitRecord an agent decision or action. Returns id and verify_url.
darkmatter_verifyCheck that the chain has not been tampered with.
darkmatter_replayWalk the full chain in chronological order.
darkmatter_exportProduce a portable JSON proof bundle.
darkmatter_list_sessionsList sessions with stored records.

Storage

Default is local-only. Passports stored at ~/.darkmatter/mcp/<session_id>/chain.jsonl. To also forward each passport to a DarkMatter receiving server, set DARKMATTER_API_KEY in the environment that launches the MCP server.

Source: github.com/darkmatter-hub/mcp. Apache-2.0. Implements Context Passport for MCP.

Claude Code (auto-capture via hooks)

The MCP server above captures what the agent explicitly invokes. For Claude Code specifically, the darkmatter-claude-code package adds auto-capture of every event (user prompt, tool use, tool result, assistant turn) using Claude Code's native hooks. Zero code change in your project, one config file edit handled by the install command.

When to use thisUse this when you want every single Claude Code action recorded as a Context Passport without the agent having to remember to call a commit tool. Pairs cleanly with the MCP server above; install both for full coverage.

Install

pip install "darkmatter-claude-code[signing]"
cd path/to/your/project
darkmatter-claude-code install
bash

The install command:

  1. Adds four hook entries to .claude/settings.json in the current project (creates it if needed)
  2. Generates an Ed25519 signing key at ~/.darkmatter/claude-code/key.pem
  3. Prints the public key so anyone can verify your records without contacting you

Restart Claude Code. Every session from this point forward auto-captures.

What gets captured

Claude Code eventHookContext Passport event.typePayload
User submits a promptUserPromptSubmitcommitThe prompt text
Claude is about to use a toolPreToolUsecommitTool name and arguments
Tool returns a resultPostToolUsecommitTool name and result
Assistant finishes the turnStopcheckpointStop reason or final summary

Every record is signed with your Ed25519 key, hash-chained to the previous record in the session, and stored at ~/.darkmatter/claude-code/sessions/<session_id>/chain.jsonl.

Verify your chain

darkmatter-claude-code verify <session_id>
bash

Or independently with the open-source Python reference verifier (no DarkMatter dependency):

pip install context-passport
python -c "
import json
from context_passport import verify_chain
chain = [json.loads(line) for line in open('$HOME/.darkmatter/claude-code/sessions/default/chain.jsonl')]
print('chain intact:', verify_chain(chain))
"
bash

Optional: forward to DarkMatter

By default everything stays on the developer's machine. To also push each passport to a DarkMatter account (cross-machine access, Witness Log anchoring, dashboard view), set DARKMATTER_API_KEY. Forwarding is best-effort and never blocks the hook; local records remain the source of truth.

Source: github.com/darkmatter-hub/claude-code. Apache-2.0.

Integration: LangGraph

LangGraph handles internal graph checkpointing. DarkMatter adds cross-framework lineage and an independent record outside your infrastructure. They’re complementary.

from darkmatter.integrations.langgraph import DarkMatterTracer

app = workflow.compile()
app = DarkMatterTracer(app, agent_id="MY_AGENT_ID")

# Use exactly as before; every node auto-commits
result = app.invoke({"input": "Write a report"})
python
LangGraph note: LangGraph’s own checkpointing persists internal graph state. DarkMatter captures what was passed between agents and produces a cryptographically verifiable chain. Use both.

Manual pattern

import os, requests, uuid
from langgraph.graph import StateGraph, END
from typing import TypedDict, Optional

DM_URL = "https://darkmatterhub.ai"
DM_KEY = os.environ["DARKMATTER_API_KEY"]

class AgentState(TypedDict):
    input:       str
    output:      Optional[str]
    dm_ctx_id:   Optional[str]
    dm_trace_id: Optional[str]

def dm_commit(payload, parent_id=None, trace_id=None, role=None):
    body = {"payload": payload}
    if parent_id: body["parentId"] = parent_id
    if trace_id:  body["traceId"]  = trace_id
    if role:      body["agent"] = {"role": role}
    return requests.post(f"{DM_URL}/api/commit",
        headers={"Authorization": f"Bearer {DM_KEY}"},
        json=body, timeout=5).json()["id"]
python

Integration: LangChain

Use a callback handler to automatically commit context after any LangChain chain or LLM call without modifying your chain logic.

from langchain_core.callbacks.base import BaseCallbackHandler
from langchain_core.outputs import LLMResult

class DarkMatterCallbackHandler(BaseCallbackHandler):
    def __init__(self, trace_id=None, role=None):
        self.trace_id    = trace_id
        self.role        = role
        self.last_input  = None
        self.last_ctx_id = None

    def on_llm_start(self, serialized, prompts, **kwargs):
        self.last_input = prompts[0] if prompts else None

    def on_llm_end(self, response: LLMResult, **kwargs):
        import darkmatter as dm
        ctx = dm.commit(
            payload   = {"input": self.last_input, "output": response.generations[0][0].text},
            parent_id = self.last_ctx_id,
            trace_id  = self.trace_id,
        )
        self.last_ctx_id = ctx["id"]
python
handler = DarkMatterCallbackHandler(trace_id="trc_001")
llm = ChatOpenAI(callbacks=[handler])
result = llm.invoke("Approve refund?")
python

Integration: CrewAI

Add DarkMatterObserver once before crew.kickoff(). Every task commits automatically, with no changes to your agents, tasks, or crew definition.

One-line setup

from darkmatter.integrations.crewai import observe_crew
import darkmatter as dm

dm.configure(api_key="dm_sk_...", agent_id="dm_agent_...")
observer = observe_crew(to_agent_id="dm_agent_...", trace_id="trc_001")

crew = Crew(agents=[researcher, writer], tasks=[task1, task2])
crew.kickoff()

print(observer.last_ctx_id)  # ctx_...
python

After each TaskCompletedEvent: task description as input, task output as output, agent role and model captured automatically. Parent/child chain built across tasks.

Requires: pip install 'crewai>=0.60.0' darkmatter-sdk

Integration: AWS Bedrock

Wrap the Bedrock runtime client once. Every invoke_model() call auto-commits. Works with Claude, Titan, Llama, Mistral, and Bedrock Agents.

One-line setup

from darkmatter.integrations.bedrock import DarkMatterBedrockClient
import darkmatter as dm

dm.configure(api_key="dm_sk_...", agent_id="dm_agent_...")

bedrock = DarkMatterBedrockClient(
    region="us-east-1", to_agent_id="dm_agent_...", trace_id="trc_001"
)
result = bedrock.invoke_model(
    model_id="anthropic.claude-opus-4-6-v1:0",
    prompt="Analyze this contract for risk clauses",
)
print(bedrock.last_ctx_id)  # ctx_...
python

Bedrock agents

output = bedrock.invoke_agent(
    agent_id="ABCDEF1234", agent_alias="TSTALIASID",
    session_id="session_001", prompt="Summarize the Q1 report",
)  # Full Bedrock Agent invocation recorded
python
Requires: pip install boto3 darkmatter-sdk. AWS credentials via environment or IAM role.

Integration: Google ADK

Subclass DarkMatterADKAgent instead of LlmAgent. Every final response auto-commits. Use DarkMatterADKRunner for multi-turn session lineage.

Single agent

import asyncio
from darkmatter.integrations.google_adk import DarkMatterADKAgent
from google.adk import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
import darkmatter as dm

dm.configure(api_key="dm_sk_...", agent_id="dm_agent_...")
agent = DarkMatterADKAgent(
    name="research_agent", model="gemini-2.0-flash",
    instruction="You are a research assistant.",
    to_agent_id="dm_agent_...", trace_id="trc_adk_001",
)

session_svc = InMemorySessionService()
runner = Runner(agent=agent, app_name="my_app", session_service=session_svc)

async def main():
    session = await session_svc.create_session(app_name="my_app", user_id="u1")
    msg = types.Content(role="user", parts=[types.Part(text="Summarize AI trends")])
    async for event in runner.run_async(user_id="u1", session_id=session.id, new_message=msg):
        if getattr(event, "is_final_response", False):
            print(event.content.parts[0].text)
    print(agent.last_ctx_id)  # ctx_... (populated after the run completes)

asyncio.run(main())
python

Multi-turn sessions

from darkmatter.integrations.google_adk import DarkMatterADKRunner
from google.adk import Runner

dm_runner = DarkMatterADKRunner(
    runner=Runner(agent=agent, app_name="my_app", session_service=session_svc),
    to_agent_id="dm_agent_...", trace_id="trc_session_001",
)
async for event in dm_runner.run_async(user_id="u1", session_id="s1", new_message=msg):
    pass  # each turn committed, full chain built
python
Requires: pip install google-adk darkmatter-sdk. Requires google-adk >= 0.4.0.

Integration: OpenTelemetry

Use the DarkMatter span exporter to record any OpenTelemetry-instrumented LLM call, including spans generated by third-party libraries.

from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
import darkmatter as dm

class DarkMatterSpanExporter(SpanExporter):
    def export(self, spans):
        for span in spans:
            attrs  = dict(span.attributes or {})
            inp    = attrs.get("llm.input") or attrs.get("gen_ai.prompt")
            output = attrs.get("llm.output") or attrs.get("gen_ai.completion")
            if inp or output:
                dm.commit(payload={"input": inp, "output": output}, event_type=span.name)
        return SpanExportResult.SUCCESS
python

L3 setup: customer signing keys

L3 means every commit is signed with a key only you hold, before it reaches DarkMatter's servers. DarkMatter cannot forge a record. Verification requires only your public key.

One-time setup: dm.commit() is unchangedConfigure signing once. After that, every commit is automatically L3. No per-commit code changes required.

Step 1: generate a keypair

import darkmatter as dm

keys = dm.generate_customer_keypair('my-signing-key')
# Creates my-signing-key.customer.private.pem (chmod 600, never share)
# and my-signing-key.customer.public.pem (safe to share)
# Prints the key_id: ck_...
python

Step 2: register the public key

curl -X POST https://darkmatterhub.ai/api/agents/keys   -H "Authorization: Bearer dm_sk_..."   -H "Content-Type: application/json"   -d "{\"keyId\": \"ck_...\", \"publicKey\": \"$(cat my-signing-key.customer.public.pem)\"}"
# Or register from the dashboard under Settings > Signing Keys
bash

Step 3: configure signing

# Option A: env vars (.env file)
DARKMATTER_CUSTOMER_KEY_PATH=./my-signing-key.customer.private.pem
DARKMATTER_CUSTOMER_KEY_ID=ck_...
bash
# Option B: inline in code
dm.configure(
    api_key           = "dm_sk_...",
    customer_key_path = "./my-signing-key.customer.private.pem",
    customer_key_id   = "ck_...",
)
python

Step 4: commit (unchanged)

ctx = dm.commit(payload={"input": "approve refund?", "output": "approved"})
print(ctx["assurance_level"])   # "L3"
print(ctx["verify_url"])        # shows L3 NON-REPUDIATION badge on /r/ page
python
Seeing L1 instead of L3?Check that DARKMATTER_CUSTOMER_KEY_PATH points to a valid .pem file and that the key ID returned by dm.generate_customer_keypair() is registered via /api/agents/keys. Both must be set before the first commit.

Key management

# List registered keys
curl https://darkmatterhub.ai/api/agents/keys -H "Authorization: Bearer dm_sk_..."

# Revoke a key
curl -X POST https://darkmatterhub.ai/api/agents/keys/revoke   -H "Authorization: Bearer dm_sk_..."   -H "Content-Type: application/json"   -d '{"keyId": "ck_..."}'
bash
Key rotationGenerate a new keypair with a new key-id, register it, update your config. Old L3 records keep their original signature. Rotation never breaks existing verification.

What L3 proves

The canonical sentence: DarkMatter received this record already signed. It cannot forge your signature. Verification requires only your public key.

For full protocol details see ENVELOPE_SPEC_V1.md and the integrity model. Example repo with offline verifier: github.com/darkmatter-hub/darkmatter-l3-example.

Coverage assertion (completeness_claim)

Set completeness_claim=True on a commit to assert that no steps were omitted. This claim is included in the signed envelope: it cannot be added, removed, or altered after signing.

ctx = dm.commit(
    payload            = {...},
    completeness_claim = True   # agent asserts nothing was omitted
)
python

The claim appears in the commit drawer and on the /r/:traceId verify page as: “Agent asserted this record is complete (nothing omitted).”

Signed assertion, not enforced coverageThis is a signed statement by the agent, not a guarantee. DarkMatter records and preserves the claim, but cannot verify that all steps actually occurred. The value is accountability: if a claim of completeness is made and steps are missing, the signed false assertion surfaces who made it. SDK wrappers set this automatically when they can observe the full call scope.

Payload privacy

If your payloads contain sensitive content, encrypt them client-side before calling /api/commit. DarkMatter stores whatever you send. If you send ciphertext, only you can read it.

For end-to-end non-repudiation with client-controlled keys, use L3 signing. L3 is the correct place for BYOK: your signing key never leaves your infrastructure, and the signature is verified by DarkMatter on every commit.

Why no server-side BYOK endpoint?Sending an encryption key to the server and asking it to encrypt on your behalf defeats the non-repudiation guarantee. DarkMatter would briefly hold your key in memory and could in principle alter the payload before encrypting. L3 client-side signing removes that trust requirement entirely.

POST /api/commit

POST https://darkmatterhub.ai/api/commit
FieldTypeRequiredDescription
toAgentIdstringrequiredRecipient agent ID (dm_agent_...). Defaults to DARKMATTER_AGENT_ID env var if set.
payload.inputstring/objectoptionalWhat the agent received
payload.outputstring/objectoptionalWhat the agent produced
parentIdstringoptionalParent ctx ID: chains commits into lineage
traceIdstringoptionalGroups commits into a run
completeness_claimbooleanoptionalSigned coverage assertion, available on any commit
client_attestationobjectoptionalEd25519 envelope for L3 signing
eventTypestringoptionalDefaults to commit
agent.rolestringoptionalresearcher, writer, reviewer, etc.
agent.modelstringoptionalModel name

Maximum payload size: 10 MB per commit. Requests exceeding this limit return 413.

GET /api/pull

GET https://darkmatterhub.ai/api/pull

Returns all verified contexts addressed to the authenticated agent, newest first.

GET /api/replay/:ctxId

GET https://darkmatterhub.ai/api/replay/:ctxId

Walks the parent chain from ctxId back to root, reverses to chronological order, returns each step with full payload and integrity verification. Add ?mode=summary for metadata only.

POST /api/fork/:ctxId

POST https://darkmatterhub.ai/api/fork/:ctxId

Branch from any checkpoint. Returns new ctx ID with fork_of, fork_point, lineage_root. Original chain never modified.

curl -X POST https://darkmatterhub.ai/api/fork/ctx_...   -H "Authorization: Bearer YOUR_KEY"   -d '{"branchKey": "experiment-1"}'
bash

GET /api/verify/:ctxId

GET https://darkmatterhub.ai/api/verify/:ctxId
FieldDescription
chain_intactBoolean, true if all hashes verify
assurance_levelL1, L2, or L3
lengthNumber of commits in chain
broken_atctx ID where chain first breaks, or null
fork_pointsArray of ctx IDs where forks occurred

GET /api/export/:ctxId

GET https://darkmatterhub.ai/api/export/:ctxId

Downloads a portable JSON proof artifact. Verifiable offline with no DarkMatter dependency.

Share links are on-demandClicking Share or Verify → in the dashboard generates a signed URL valid for 30 days. Records are not publicly accessible until you explicitly share them.

GET /api/lineage/:ctxId

GET https://darkmatterhub.ai/api/lineage/:ctxId

Returns ancestor chain metadata (no payloads) from tip to root. Faster than replay for visualization.

GET /api/me

GET https://darkmatterhub.ai/api/me

Returns the identity of the authenticated agent.

POST /api/agents/register

POST https://darkmatterhub.ai/api/agents/register

Programmatically spawn a new agent without a dashboard login. Useful for pipelines that create agents dynamically. Cap: 10 new agents per account per day.

curl -X POST https://darkmatterhub.ai/api/agents/register   -H "Authorization: Bearer EXISTING_AGENT_KEY"   -d '{"agentName": "summarizer-v2", "role": "summarizer"}'
# Returns: { agentId, agentName, apiKey, spawnedBy, createdAt }
bash

Context Passport schema

Every DarkMatter commit response is a Context Passport v2.0 record. Context Passport is an open standard (CC0) for structured, verifiable records of AI agent events; v2.0 adopts RFC 8785 (JCS) canonicalization, so records are byte-equivalent across the Python and TypeScript reference SDKs. DarkMatter is a reference implementation; the canonical specification, JSON Schema, and conformance tests are maintained at github.com/contextpassport/spec.

Every commit response includes "$schema": "https://contextpassport.com/schema/v2.json" and "schema_version": "2.0" so any parser or downstream tool can detect the format programmatically. v1.x records produced by older clients remain verifiable via the compat.v1 shim shipped in both reference SDKs.

{
  "$schema":        "https://contextpassport.com/schema/v2.json",
  "schema_version": "2.0",
  "id":             "ctx_{unix_ms}_{6_hex_bytes}",
  "parent_id":      "ctx_... | null",
  "trace_id":       "trc_... | null",
  "branch_key":     "main",

  "created_by": {
    "agent_id":   "dm_...",
    "agent_name": "string",
    "role":       "researcher | writer | reviewer | ...",
    "provider":   "anthropic | openai | google | mistral | local | custom",
    "model":      "claude-opus-4-6"
  },

  "event": {
    "type":        "commit | fork | checkpoint | spawn | audit | ...",
    "to_agent_id": "dm_... | null",
    "timestamp":   "ISO 8601"
  },

  "payload": {
    "input":     "string | object | null",
    "output":    "string | object | null",
    "memory":    "object | null",
    "variables": "object | null"
  },

  "integrity": {
    "payload_hash":        "sha256:hex",
    "parent_hash":         "sha256:hex | null",
    "integrity_hash":      "sha256:hex",
    "verification_status": "valid | broken | unverified"
  },

  "lineage": {
    "fork_of":      "ctx_... | null",
    "fork_point":   "ctx_... | null",
    "lineage_root": "ctx_... | null"
  },

  "signature": {
    "algorithm":  "ed25519",
    "key_id":     "string",
    "public_key": "base64",
    "signature":  "base64"
  },

  "created_at": "ISO 8601"
}
json

The signature block is optional in the spec but is emitted automatically by DarkMatter when a customer-held signing key is configured (see L3 below). The integrity_hash is computed per SPEC.md ยง3.4 using RFC 8785 (JCS) canonicalization and MUST NOT be set manually.

For the full specification including all event types, integrity computation rules, signature canonicalization, and the extension model, see contextpassport/spec. The conformance test suite that validates implementations is at contextpassport/conformance-tests.

Integrity model

Every commit starts at L1. L2 is applied automatically via OpenTimestamps anchoring on checkpoints. L3 requires a customer-held signing key.

LevelNameWhat it provesHow
L1Verifiable recordPayload wasn’t altered after commitSHA-256 hash chain. Default with every commit.
L2Independent verificationRecord predates any disputeOpenTimestamps anchor. Automatic.
L3Non-repudiationDarkMatter cannot forge this recordCustomer Ed25519 key signs envelope before transmission.

See the integrity model page for the full trust boundary documentation.

Hooks and policies

Policies are rules that evaluate incoming commits before they are stored. Register them via API to enforce commit structure, flag patterns, or trigger webhooks.

curl -X POST https://darkmatterhub.ai/api/policies   -H "Authorization: Bearer YOUR_API_KEY"   -d '{"name": "require-model", "condition": "!payload.model", "action": "reject"}'
bash

The condition field is a JavaScript-style expression evaluated against the incoming commit. Use dot notation to access fields: payload.model, payload.input, agent.role. A truthy result triggers the action.