DCP-AI Quick Start Guide¶
This guide shows how to produce and verify DCP evidence with an SDK, and which tools are demos.
Choose a path¶
- Produce and verify evidence with an SDK. Install a published SDK. The examples of §3 TypeScript and §4 Python create signed bundles and verify them; Other SDKs gives the installation and references for Go, Rust and WebAssembly. Verification checks integrity and signatures; it does not establish principal trust, admission or authorization (see Admission).
- Look around with a demo. The playground and the starter projects of the zero-install shortcuts, and the CLI wizard of §1 and §2, show the concepts. Their limits differ (simulated PQ keys or signatures, placeholder keys, unsigned records, structure-only checks), and what they produce is not verification evidence.
- Run a verifier without installing an SDK. The optional Docker image of the reference verification server, in the same shortcuts and in Run the reference services, verifies bundles; it does not create them.
The current package versions are listed in Published versions.
Prerequisites¶
Depending on which SDK you use:
- Node.js 18+ — for the TypeScript SDK, CLI, WASM package, and the
@dcp-ai/*integrations; the current LangChain.js (v1) in QUICKSTART_LANGCHAIN.md needs Node.js 22+ - Python 3.10+ — for the Python SDK; the separate
agno-dcppackage in QUICKSTART_AGNO.md needs 3.11+ - Go 1.25+ — for the Go SDK
- Rust stable — for the Rust crate
You only need the language you plan to build with. All SDKs implement the same V2 wire format; the shared vectors and the interoperability matrix test signing and verification across SDKs, and each SDK README lists its remaining gaps.
Published packages and this guide¶
The TypeScript examples use published @dcp-ai/sdk 2.4.0, the npm CLI is @dcp-ai/cli 2.2.0, and Python is dcp-ai 2.11.0 on PyPI. See npm, Python and SECURITY.md. Go and Rust releases are separate. For source development, use:
git clone https://github.com/dcp-ai-protocol/dcp-ai.git
cd dcp-ai/sdks/typescript && npm install && npm run build # TypeScript SDK of main
cd ../../cli && npm install --no-save --package-lock=false --ignore-scripts --install-links ../sdks/typescript
pip install -e /path/to/dcp-ai/sdks/python # Python SDK of main
The registry commands in this guide install the published versions.
Zero-install shortcuts¶
These shortcuts use published packages and images, not main. The playground and the starters are demos and do not produce SDK verification evidence (limits below); the Docker image runs the reference verification server, which verifies bundles but does not create them:
- Interactive playground: https://docs.dcp-ai.org/playground/ — generate identities, build bundles, verify signatures in the browser.
- Scaffolded starter: run
npm create @dcp-ai/langchain my-app(or/crewai,/openai,/express) to generate a starter project. - Docker one-liner:
docker run -p 3000:3000 ghcr.io/dcp-ai-protocol/dcp-ai/verification:lateststarts the reference verification server without cloning anything.
The playground is a demo: its PQ signatures are simulated and its canonicalization and Merkle handling are simplified, so its bundles are not SDK verification evidence. The starter templates also have limits: LangChain, CrewAI and OpenAI use placeholder keys/signatures; Express checks structure only. Use the SDK examples below for verifiable bundles.
1. Install the CLI¶
The CLI wizard is a demo for looking around: its "ML-DSA-65" keys are simulated (random bytes), and the RPR and passport it writes are unsigned and do not match the V2 schemas. To create an identity and bundles that verify, skip to §3 or §4; the limits are listed in Agent creation.
The published version, installed or run directly:
From a checkout (above), run the repository's wizard in your project's directory:
node /path/to/dcp-ai/cli/bin/dcp-ai.js init.
2. Initialize Your Agent¶
This creates the following demo files in your project:
| File | Purpose |
|---|---|
.dcp/config.json |
Agent configuration and metadata |
.dcp/keys/ed25519_public.key, .dcp/keys/ed25519_secret.key |
Ed25519 keypair |
.dcp/keys/ml_dsa_65_public.key, .dcp/keys/ml_dsa_65_secret.key |
Simulated "ML-DSA-65" keypair (random bytes), when post-quantum keys are chosen |
.dcp/identity.json |
RPR-like record (unsigned, not schema-valid) |
.dcp/passport.json |
Passport-like record (unsigned, not schema-valid) |
The secret key files are written with default permissions (0644 with the usual umask 022): run
chmod 600 .dcp/keys/*_secret.key, and keep them out of version control by adding .dcp/keys/ to your
.gitignore.
3. TypeScript SDK¶
The TypeScript examples below work with npm SDK 2.4.0 or a development checkout (see Published packages and this guide).
Install one of the two:
- the SDK of
main, built from a checkout, for source development:
- or the published SDK 2.4.0, which includes these fixes and features:
Create and Sign a Bundle (V1 — Ed25519)¶
The RPR and the passport are each signed over the object without its signature field. verifySignedBundle
checks the bundle signature, its hashes and the chain; the inner signatures are checked apart.
import { BundleBuilder, generateKeypair, signBundle, signObject, verifyObject, verifySignedBundle } from '@dcp-ai/sdk';
import type { AgentPassport, ResponsiblePrincipalRecord } from '@dcp-ai/sdk';
const now = new Date().toISOString();
const principalKeys = generateKeypair();
const agentKeys = generateKeypair();
// Each artifact is signed over the object without its `signature` field.
const rprBody: Omit<ResponsiblePrincipalRecord, 'signature'> = {
dcp_version: '1.0', human_id: 'human:example-001', legal_name: 'Example Principal',
entity_type: 'natural_person', jurisdiction: 'ES', liability_mode: 'owner_responsible',
override_rights: true, issued_at: now, expires_at: null, contact: null,
};
const rpr: ResponsiblePrincipalRecord = { ...rprBody, signature: signObject(rprBody, principalKeys.secretKeyB64) };
const passportBody: Omit<AgentPassport, 'signature'> = {
dcp_version: '1.0', agent_id: 'agent:example-001', public_key: agentKeys.publicKeyB64,
principal_binding_reference: rpr.human_id, capabilities: ['browse', 'api_call'],
risk_tier: 'low', created_at: now, status: 'active',
};
const passport: AgentPassport = { ...passportBody, signature: signObject(passportBody, agentKeys.secretKeyB64) };
const bundle = new BundleBuilder()
.responsiblePrincipalRecord(rpr)
.agentPassport(passport)
.intent({
dcp_version: '1.0', intent_id: 'intent:example-001', agent_id: passport.agent_id, human_id: rpr.human_id,
timestamp: now, action_type: 'api_call', target: { channel: 'api', domain: 'api.example.com' },
data_classes: ['none'], estimated_impact: 'low', requires_consent: false,
})
.policyDecision({
dcp_version: '1.0', intent_id: 'intent:example-001', decision: 'approve', risk_score: 0.05,
reasons: ['low-impact call'], required_confirmation: null,
})
.createAuditEntry({
dcp_version: '1.0', audit_id: 'audit:example-001', timestamp: now, agent_id: passport.agent_id,
human_id: rpr.human_id, intent_id: 'intent:example-001', policy_decision: 'approved',
outcome: 'call_completed', evidence: { tool: 'http', result_ref: null },
})
.build();
const signed = signBundle(bundle, { secretKeyB64: principalKeys.secretKeyB64, signerType: 'human', signerId: rpr.human_id });
console.log(verifySignedBundle(signed, principalKeys.publicKeyB64)); // { verified: true }
// The inner signatures, over the same objects without `signature`
console.log(verifyObject(rprBody, rpr.signature, principalKeys.publicKeyB64)); // true
console.log(verifyObject(passportBody, passport.signature, agentKeys.publicKeyB64)); // true
Verify a Bundle¶
import { readFileSync } from 'node:fs';
import { getDefaultRegistry, registerDefaultProviders, verifySignedBundleV2 } from '@dcp-ai/sdk';
registerDefaultProviders();
const signedBundle = JSON.parse(readFileSync('bundle.signed.json', 'utf8'));
const result = await verifySignedBundleV2(signedBundle, getDefaultRegistry());
console.log(result.verified, result.errors);
V2 — Post-Quantum Hybrid Signatures¶
Every artifact is a SignedPayload signed under its domain-separation context with Ed25519 + ML-DSA-65; the
principal signs the RPR and the manifest, the agent the passport, intent and policy decision.
import {
AlgorithmRegistry, BundleBuilderV2, DCP_CONTEXTS, Ed25519Provider, MlDsa65Provider, compositeSign,
generateSessionNonce, preparePayload, sha256Hex, canonicalizeV2, signBundleV2, verifySignedBundleV2,
} from '@dcp-ai/sdk';
import type {
AgentPassportV2, AuditEventV2, CompositeKeyPair, DcpContext, IntentV2, KeyEntry, PolicyDecisionV2,
ResponsiblePrincipalRecordV2, SignedPayload,
} from '@dcp-ai/sdk';
const registry = new AlgorithmRegistry();
const ed25519 = new Ed25519Provider();
const mlDsa65 = new MlDsa65Provider();
registry.registerSigner(ed25519);
registry.registerSigner(mlDsa65);
async function hybridKeys(): Promise<CompositeKeyPair> {
const c = await ed25519.generateKeypair();
const p = await mlDsa65.generateKeypair();
return {
classical: { kid: c.kid, alg: 'ed25519', secretKeyB64: c.secretKeyB64, publicKeyB64: c.publicKeyB64 },
pq: { kid: p.kid, alg: 'ml-dsa-65', secretKeyB64: p.secretKeyB64, publicKeyB64: p.publicKeyB64 },
};
}
const keyEntries = (keys: CompositeKeyPair): KeyEntry[] => [keys.classical, keys.pq].map((k) => ({
kid: k.kid, alg: k.alg, public_key_b64: k.publicKeyB64, created_at: '2026-01-01T00:00:00Z', expires_at: null, status: 'active',
}));
const sha256Of = (value: unknown) => `sha256:${sha256Hex(new TextEncoder().encode(canonicalizeV2(value)))}`;
async function signed<T>(payload: T, context: DcpContext, keys: CompositeKeyPair): Promise<SignedPayload<T>> {
const { canonicalBytes, payloadHash } = preparePayload(payload);
return { payload, payload_hash: payloadHash, composite_sig: await compositeSign(registry, context, canonicalBytes, keys) };
}
const principal = await hybridKeys();
const agent = await hybridKeys();
const nonce = generateSessionNonce();
const now = new Date().toISOString();
const rpr: ResponsiblePrincipalRecordV2 = {
dcp_version: '2.0', human_id: 'human:example-001', session_nonce: nonce, legal_name: 'Example Principal',
entity_type: 'natural_person', jurisdiction: 'ES', liability_mode: 'owner_responsible', override_rights: true,
issued_at: now, expires_at: null, contact: null, binding_keys: keyEntries(principal),
};
const passport: AgentPassportV2 = {
dcp_version: '2.0', agent_id: 'agent:example-001', session_nonce: nonce, keys: keyEntries(agent),
principal_binding_reference: rpr.human_id, capabilities: ['browse', 'api_call'], risk_tier: 'low',
created_at: now, status: 'active',
};
const intent: IntentV2 = {
dcp_version: '2.0', intent_id: 'intent:example-001', session_nonce: nonce, agent_id: passport.agent_id,
human_id: rpr.human_id, timestamp: now, action_type: 'api_call', target: { channel: 'api', domain: 'api.example.com' },
data_classes: ['none'], estimated_impact: 'low', requires_consent: false,
};
const policy: PolicyDecisionV2 = {
dcp_version: '2.0', intent_id: intent.intent_id, session_nonce: nonce, decision: 'approve', risk_score: 50,
reasons: ['low-impact call'], required_confirmation: null, applied_policy_hash: sha256Of({ policy: 'default' }), timestamp: now,
};
const audit: AuditEventV2 = {
dcp_version: '2.0', audit_id: 'audit:example-001', session_nonce: nonce, prev_hash: 'GENESIS', hash_alg: 'sha256',
timestamp: now, agent_id: passport.agent_id, human_id: rpr.human_id, intent_id: intent.intent_id,
intent_hash: sha256Of(intent), policy_decision: 'approved', outcome: 'call_completed',
evidence: { tool: 'http', result_ref: null, evidence_hash: null }, pq_checkpoint_ref: null,
};
const bundle = new BundleBuilderV2(nonce)
.responsiblePrincipalRecord(await signed(rpr, DCP_CONTEXTS.ResponsiblePrincipal, principal))
.agentPassport(await signed(passport, DCP_CONTEXTS.AgentPassport, agent))
.intent(await signed(intent, DCP_CONTEXTS.Intent, agent))
.policyDecision(await signed(policy, DCP_CONTEXTS.PolicyDecision, agent))
.addAuditEntry(audit)
.build();
const signedBundle = await signBundleV2(bundle, { registry, signerType: 'human', signerId: rpr.human_id, keys: principal });
const result = await verifySignedBundleV2(signedBundle, registry);
console.log(result.verified, result.errors); // true []
4. Python SDK¶
Install one of the two:
- a checkout for SDK development:
- or the published version 2.11.0, including the fixes and APIs described here:
Create and Verify a Bundle¶
from datetime import datetime, timezone
from dcp_ai import (
AgentPassport,
AuditEvidence,
BundleBuilder,
Intent,
PolicyDecision,
ResponsiblePrincipalRecord,
generate_keypair,
sign_bundle,
sign_object,
verify_object,
verify_signed_bundle,
)
now = datetime.now(timezone.utc).isoformat()
principal_keys = generate_keypair()
agent_keys = generate_keypair()
# 1. The responsible principal, signed with the principal's key (the object without "signature")
rpr_body = {
"dcp_version": "1.0", "human_id": "human:example-001", "legal_name": "Example Principal",
"entity_type": "natural_person", "jurisdiction": "ES", "liability_mode": "owner_responsible",
"override_rights": True, "issued_at": now, "expires_at": None, "contact": None,
}
rpr = {**rpr_body, "signature": sign_object(rpr_body, principal_keys["secret_key_b64"])}
# 2. The agent passport, signed with the agent's key (the object without "signature")
passport_body = {
"dcp_version": "1.0", "agent_id": "agent:example-001", "public_key": agent_keys["public_key_b64"],
"principal_binding_reference": "human:example-001", "capabilities": ["browse", "api_call"],
"risk_tier": "low", "created_at": now, "status": "active",
}
passport = {**passport_body, "signature": sign_object(passport_body, agent_keys["secret_key_b64"])}
# 3. Intent, policy decision and one audit entry
intent = Intent(
intent_id="intent:example-001", agent_id="agent:example-001", human_id="human:example-001",
timestamp=now, action_type="api_call", target={"channel": "api", "domain": "api.example.com"},
data_classes=["none"], estimated_impact="low", requires_consent=False,
)
policy = PolicyDecision(
intent_id="intent:example-001", decision="approve", risk_score=0.05, reasons=["low-impact call"],
)
bundle = (
BundleBuilder()
.responsible_principal_record(ResponsiblePrincipalRecord(**rpr))
.agent_passport(AgentPassport(**passport))
.intent(intent)
.policy_decision(policy)
.create_audit_entry(
audit_id="audit:example-001", timestamp=now, agent_id="agent:example-001",
human_id="human:example-001", intent_id="intent:example-001", policy_decision="approved",
outcome="call_completed", evidence=AuditEvidence(tool="http", result_ref=None),
)
.build()
)
# 4. Sign with the principal's key and verify against the principal's public key
signed = sign_bundle(bundle, principal_keys["secret_key_b64"])
print(verify_signed_bundle(signed, principal_keys["public_key_b64"])) # {'verified': True}
# 5. The inner signatures, over the same objects without "signature"
print(verify_object(rpr_body, rpr["signature"], principal_keys["public_key_b64"])) # True
print(verify_object(passport_body, passport["signature"], agent_keys["public_key_b64"])) # True
For V2 bundles in Python, see V2 Bundles.
5. Security Tiers¶
DCP automatically selects a cryptographic security tier based on the intent's risk profile:
| Tier | Name | Verification Mode | PQ Checkpoint Interval | Trigger |
|---|---|---|---|---|
| 0 | Routine | Classical only (Ed25519) | Every 50 events | None of the triggers below |
| 1 | Standard | Hybrid preferred | Every 10 events | Risk score 200–499, estimated_impact: medium |
| 2 | Elevated | Hybrid required | Every event | Risk score 500–799, PII, financial or health data, payments, estimated_impact: high, unknown values |
| 3 | Maximum | Hybrid required | Every event | Risk score ≥ 800, credentials, children's data |
The risk score is the policy decision's risk_score (spec §14.2).
import { computeSecurityTier, tierToVerificationMode } from '@dcp-ai/sdk';
const tier = computeSecurityTier(intent, policyDecision);
const mode = tierToVerificationMode(tier);
// tier: 'elevated', mode: 'hybrid_required'
6. Telemetry & Observability¶
import { dcpTelemetry } from '@dcp-ai/sdk';
dcpTelemetry.init({
serviceName: 'my-agent',
enabled: true,
exporterType: 'console', // or 'otlp'
});
// Automatic span tracking
const spanId = dcpTelemetry.startSpan('sign_bundle', { tier: 'elevated' });
// ... perform operation ...
dcpTelemetry.endSpan(spanId);
// Record metrics
dcpTelemetry.recordSignLatency(12.5, 'ed25519');
// Get summary
const summary = dcpTelemetry.getMetricsSummary();
console.log(summary.sign.p95); // p95 sign latency in ms
7. Agent-to-Agent (A2A) Communication¶
import { createHello, createWelcome, createSession, encryptMessage } from '@dcp-ai/sdk';
// Agent A initiates
const hello = createHello(bundleA, kemPublicKeyB64, ['api_call'], 'standard');
// Agent B responds
const welcome = createWelcome(bundleB, kemPubB, kemCiphertextB64, 'standard');
// Establish encrypted session
const session = createSession(sessionId, sessionKey, 'agent-a', 'agent-b', 'standard');
// Send encrypted messages
const encrypted = encryptMessage(session, { action: 'transfer', amount: 100 });
Other SDKs¶
Go¶
import dcp "github.com/dcp-ai-protocol/dcp-ai/sdks/go/v2/dcp"
canonical, _ := dcp.Canonicalize(map[string]string{"b": "2", "a": "1"})
// produces {"a":"1","b":"2"}
Rust¶
Providers for ML-DSA-65, ML-KEM-768, SLH-DSA-192f, Ed25519 live under dcp_ai::providers::*. See the dcp-ai crate docs on docs.rs for the full surface.
WebAssembly (browser)¶
npm install @dcp-ai/wasm@^2.2.0 # the published version; for main, see the WASM SDK's Release status
Exposes the Rust SDK's primitives to browsers and Node.js. In Node.js, initDcp() needs the .wasm file as a data: URL: see Initialization.
Run the reference services¶
All four services the spec references (verification server, anchor, transparency log, revocation registry) ship as Docker images. From an empty directory:
docker run -d -p 3000:3000 ghcr.io/dcp-ai-protocol/dcp-ai/verification:latest
docker run -d -p 3001:3001 ghcr.io/dcp-ai-protocol/dcp-ai/anchor:latest
docker run -d -p 3002:3002 ghcr.io/dcp-ai-protocol/dcp-ai/transparency-log:latest
docker run -d -p 3003:3003 ghcr.io/dcp-ai-protocol/dcp-ai/revocation:latest
For managed hosting, see the Fly.io configs in deploy/fly/ and the deployment guide for Cloud Run / Railway / Compose alternatives.
Next Steps¶
- LangChain Integration — Add DCP to LangChain agents
- CrewAI Integration — Add DCP to CrewAI crews
- OpenAI Integration — Add DCP to OpenAI function calling
- Express Middleware — Verify DCP bundles in Express APIs
- API Reference — Complete SDK documentation
- Protocol Specification — Full DCP v2.0 specification
- Security Model — Threat model and security architecture
- Operator Guide — Running verification and anchoring services in production