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.
dm_agent_...) and API key. Every commit is attributed to it.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.
| Operation | What it does | Endpoint |
|---|---|---|
| Commit | Record an agent decision as an immutable, verifiable record | POST /api/commit |
| Verify | Prove the chain was never tampered with | GET /api/verify/:id |
| Export | Download a portable proof bundle for offline verification | GET /api/export/:id |
| Replay | Walk the full decision chain root to tip | GET /api/replay/:id |
| Fork | Branch from any checkpoint without touching the original | POST /api/fork/:id |
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-sdkbash
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
pip install darkmatter-sdk, which installs the SDK and CLI.dm_sk_...dm.commit() after each agent action. Pass parent_id to chain commits into a lineage.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.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 -qpython
# 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
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-jsbash
// 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
commit, 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.
Authorization: Bearer dm_sk_your_api_key_herehttp
| Property | Detail |
|---|---|
| Format | dm_sk_ prefix followed by hex string |
| Scope | Each key belongs to one agent |
| Rate limit | 120 requests per minute per key |
| Rotation | Rotate 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.
- L1. Hash chain integrity. The record was not altered after it was committed.
- L2. OpenTimestamps anchor. The record's existence is anchored via OpenTimestamps, an open standard for timestamp proofs that operates independently of DarkMatter's infrastructure.
- L3. Customer signing key. Signed by a key only you hold, before reaching DarkMatter's servers. DarkMatter cannot forge or alter it.
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.
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 DarkMatterpython
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 DarkMatterpython
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
| Option | Default | Description |
|---|---|---|
dm_api_key | DARKMATTER_API_KEY | DarkMatter API key |
dm_agent_id | DARKMATTER_AGENT_ID | Agent ID, optional |
dm_signing | None | Reserved for L3 signing config (configure via dm.configure(customer_key_path=...)) |
dm_auto_commit | True | Set False to disable instrumentation |
dm_commit_tools | True | Set False to skip tool call child commits |
dm_async | True | Commits sent in background thread (zero latency) |
dm_debug | False | Print 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.
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
| Tool | Purpose |
|---|---|
darkmatter_commit | Record an agent decision or action. Returns id and verify_url. |
darkmatter_verify | Check that the chain has not been tampered with. |
darkmatter_replay | Walk the full chain in chronological order. |
darkmatter_export | Produce a portable JSON proof bundle. |
darkmatter_list_sessions | List 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.
Install
pip install "darkmatter-claude-code[signing]"
cd path/to/your/project
darkmatter-claude-code installbash
The install command:
- Adds four hook entries to
.claude/settings.jsonin the current project (creates it if needed) - Generates an Ed25519 signing key at
~/.darkmatter/claude-code/key.pem - 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 event | Hook | Context Passport event.type | Payload |
|---|---|---|---|
| User submits a prompt | UserPromptSubmit | commit | The prompt text |
| Claude is about to use a tool | PreToolUse | commit | Tool name and arguments |
| Tool returns a result | PostToolUse | commit | Tool name and result |
| Assistant finishes the turn | Stop | checkpoint | Stop 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
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.
pip install 'crewai>=0.60.0' darkmatter-sdkIntegration: 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 recordedpython
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 builtpython
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.SUCCESSpython
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.
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 Keysbash
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/ pagepython
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
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).”
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.
POST /api/commit
| Field | Type | Required | Description |
|---|---|---|---|
toAgentId | string | required | Recipient agent ID (dm_agent_...). Defaults to DARKMATTER_AGENT_ID env var if set. |
payload.input | string/object | optional | What the agent received |
payload.output | string/object | optional | What the agent produced |
parentId | string | optional | Parent ctx ID: chains commits into lineage |
traceId | string | optional | Groups commits into a run |
completeness_claim | boolean | optional | Signed coverage assertion, available on any commit |
client_attestation | object | optional | Ed25519 envelope for L3 signing |
eventType | string | optional | Defaults to commit |
agent.role | string | optional | researcher, writer, reviewer, etc. |
agent.model | string | optional | Model name |
Maximum payload size: 10 MB per commit. Requests exceeding this limit return 413.
GET /api/pull
Returns all verified contexts addressed to the authenticated agent, newest first.
GET /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
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
| Field | Description |
|---|---|
chain_intact | Boolean, true if all hashes verify |
assurance_level | L1, L2, or L3 |
length | Number of commits in chain |
broken_at | ctx ID where chain first breaks, or null |
fork_points | Array of ctx IDs where forks occurred |
GET /api/export/:ctxId
Downloads a portable JSON proof artifact. Verifiable offline with no DarkMatter dependency.
GET /api/lineage/:ctxId
Returns ancestor chain metadata (no payloads) from tip to root. Faster than replay for visualization.
GET /api/me
Returns the identity of the authenticated agent.
POST /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.
| Level | Name | What it proves | How |
|---|---|---|---|
L1 | Verifiable record | Payload wasn’t altered after commit | SHA-256 hash chain. Default with every commit. |
L2 | Independent verification | Record predates any dispute | OpenTimestamps anchor. Automatic. |
L3 | Non-repudiation | DarkMatter cannot forge this record | Customer 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.