Build an Agent
This tutorial walks through building a CKP-conformant agent at each conformance level. You will start with a minimal L1 agent and progressively add tools, security gates, memory, swarm coordination, and optional predictive planning metadata.
Prerequisites
Section titled “Prerequisites”npm install @clawkernel/sdkYou will also need a claw.yaml manifest for each level. The SDK ships example manifests in sdk/examples/.
Step 1: L1 agent — Identity and Provider
Section titled “Step 1: L1 agent — Identity and Provider”An L1 agent only needs a name and version. The SDK handles initialization, status, shutdown, heartbeat, and all required error responses automatically.
import { createAgent } from "@clawkernel/sdk";
const agent = createAgent({ name: "my-agent", version: "1.0.0",});
agent.listen();That is the entire agent. It communicates over stdio using JSON-RPC 2.0 and passes all 13 L1 test vectors.
Manifest
Section titled “Manifest”The corresponding claw.yaml declares the agent’s identity and at least one provider:
claw: "0.3.0"kind: Clawmetadata: name: my-agent
spec: identity: inline: personality: "You are a helpful assistant." autonomy: supervised
providers: - inline: protocol: openai-compatible endpoint: http://localhost:11434/v1 model: llama3 auth: type: noneWhat this gives you
Section titled “What this gives you”claw.initialize/claw.initializedhandshakeclaw.statuswith lifecycle state trackingclaw.shutdownwith graceful drainclaw.heartbeatperiodic notifications- Proper JSON-RPC error handling (parse errors, invalid requests, unknown methods)
Step 2: L2 agent — Tools, Policy, and Sandbox
Section titled “Step 2: L2 agent — Tools, Policy, and Sandbox”L2 adds executable tools with a five-gate security pipeline. Every tool call passes through quota, policy, sandbox, existence check, and approval before execution.
import { createAgent } from "@clawkernel/sdk";
const agent = createAgent({ name: "my-agent", version: "1.0.0",
// Tools: register callable functions tools: { echo: { execute: async (args) => ({ content: [{ type: "text", text: args.text as string }], }), }, "slow-tool": { timeout_ms: 100, // Will timeout if execution exceeds 100ms execute: async () => { await new Promise((r) => setTimeout(r, 5000)); return { content: [{ type: "text", text: "done" }] }; }, }, },
// Policy gate: deny specific tools by name policy: { evaluate: (toolName) => { if (toolName === "destructive-tool") return { allowed: false, code: -32011 }; return { allowed: true }; }, },
// Sandbox gate: block dangerous arguments sandbox: { check: (_toolName, args) => { if ((args.url as string)?.includes("169.254")) return { allowed: false, code: -32010 }; return { allowed: true }; }, },
// Quota gate: reject expensive calls quota: { check: (toolName) => { if (toolName === "expensive-tool") return { allowed: false, code: -32021 }; return { allowed: true }; }, },
// Approval gate: require human approval for specific tools approval: { required: (toolName) => toolName === "deploy", timeout_ms: 30000, },});
agent.listen();Manifest
Section titled “Manifest”The L2 manifest adds channels, tools, sandbox, and policies:
claw: "0.3.0"kind: Clawmetadata: name: my-agent
spec: identity: inline: personality: "L2 agent with tools and security." autonomy: supervised
providers: - inline: protocol: openai-compatible endpoint: http://localhost:11434/v1 model: test-model auth: type: none
channels: - inline: type: cli transport: stdio auth: secret_ref: CLI_TOKEN
tools: - inline: name: echo description: "Echo input back" input_schema: type: object properties: text: type: string
sandbox: inline: level: process
policies: - inline: rules: - id: allow-all action: allow scope: allKey concepts at L2
Section titled “Key concepts at L2”Tool definition — Each tool has an execute function and an optional timeout_ms. The function receives parsed arguments and returns a content array.
Gate pipeline — The five gates run in order: quota -> policy -> sandbox -> exists -> approval -> execute. A tool denied by policy never reveals whether it exists.
Error codes — Each gate maps to a specific CKP error code: -32021 (quota), -32011 (policy), -32010 (sandbox), -32012 (approval timeout), -32013 (approval denied), -32014 (tool timeout).
Step 3: L3 agent — Memory and Swarm
Section titled “Step 3: L3 agent — Memory and Swarm”L3 adds persistent memory and multi-agent coordination. You implement four memory operations (store, query, compact) and four swarm operations (delegate, discover, report, broadcast).
import { createAgent } from "@clawkernel/sdk";import type { MemoryEntry, MemoryQuery, SwarmTask, SwarmContext,} from "@clawkernel/sdk";import { randomUUID } from "node:crypto";
// In-memory store (replace with your database in production)const memoryStore = new Map< string, { id: string; content: string | Record<string, unknown>; timestamp: string }[]>();
const agent = createAgent({ name: "my-agent", version: "1.0.0",
// L2 config (tools, policy, sandbox, etc.) ... tools: { /* ... same as Step 2 ... */ }, policy: { /* ... same as Step 2 ... */ }, sandbox: { check: () => ({ allowed: true }) },
// Memory: persistent state across sessions memory: { store: async (storeName: string, entries: MemoryEntry[]) => { const bucket = memoryStore.get(storeName) ?? []; const ids: string[] = []; for (const entry of entries) { const id = randomUUID(); ids.push(id); bucket.push({ id, content: entry.content, timestamp: new Date().toISOString(), }); } memoryStore.set(storeName, bucket); return { stored: entries.length, ids }; },
query: async (storeName: string, _query: MemoryQuery) => { const bucket = memoryStore.get(storeName) ?? []; return { entries: bucket.map((e) => ({ id: e.id, content: e.content, score: 1.0, timestamp: e.timestamp, })), }; },
compact: async (storeName: string) => { const bucket = memoryStore.get(storeName) ?? []; const before = bucket.length; const compacted = bucket.slice(-100); memoryStore.set(storeName, compacted); return { entries_before: before, entries_after: compacted.length }; }, },
// Swarm: multi-agent coordination swarm: { delegate: async ( _taskId: string, _task: SwarmTask, _context: SwarmContext ) => { return { acknowledged: true }; },
discover: async (_swarmName?: string) => { return { peers: [ { identity: "peer-1", uri: "claw://local/identity/peer-1", status: "ready" as const, }, ], }; },
report: async ( _taskId: string, _status: string, _result: Record<string, unknown> ) => { return { acknowledged: true }; },
broadcast: (_swarmName: string, _message: Record<string, unknown>) => { // Fire-and-forget notification, no response needed }, },});
agent.listen();Manifest
Section titled “Manifest”The L3 manifest includes all 9 core primitives (Telemetry optional at all levels):
claw: "0.3.0"kind: Clawmetadata: name: my-agent
spec: identity: inline: personality: "L3 agent with memory and swarm." autonomy: autonomous
providers: - inline: protocol: openai-compatible endpoint: http://localhost:11434/v1 model: test-model auth: type: none
channels: - inline: type: cli transport: stdio auth: secret_ref: CLI_TOKEN
tools: - inline: name: echo description: "Echo input back" input_schema: type: object properties: text: type: string
skills: - inline: name: echo-skill description: "Echo workflow" tools_required: - echo instruction: "Use echo tool to echo back user input."
memory: inline: stores: - name: context type: key-value backend: sqlite scope: global
sandbox: inline: level: process
policies: - inline: rules: - id: allow-all action: allow scope: all
swarm: inline: topology: peer-to-peer agents: - identity_ref: peer-1 role: peer coordination: message_passing: direct backend: in-process concurrency: max_parallel: 2 aggregation: strategy: mergeKey concepts at L3
Section titled “Key concepts at L3”Memory — Three operations map to JSON-RPC methods: claw.memory.store persists entries, claw.memory.query retrieves them (with optional semantic search), and claw.memory.compact runs garbage collection.
Swarm — Four operations: claw.swarm.delegate assigns tasks to peers, claw.swarm.discover finds available agents, claw.swarm.report returns task results, and claw.swarm.broadcast sends fire-and-forget notifications to all peers.
Optional Step 4: Add a WorldModel manifest
Section titled “Optional Step 4: Add a WorldModel manifest”CKP 0.3.0 introduces an optional WorldModel primitive for predictive planning. The SDK does not add new JSON-RPC methods for this; instead, Skills can reference a reusable world model declaration inside the manifest.
claw: "0.3.0"kind: Clawmetadata: name: my-agent
spec: memory: inline: stores: - name: planner-checkpoints type: checkpoint role: working backend: sqlite
world_models: - inline: name: route-simulator paradigm: hybrid backend: type: tool ref: scenario-simulator planning: horizon: adaptive uncertainty_mode: bounded fallback: conservative
skills: - inline: name: route-planning description: "Plan before acting." tools_required: ["scenario-simulator"] instruction: "Simulate outcomes before selecting a route." world_model_ref: route-simulatorThis keeps predictive planning declarative and reusable. Multiple skills can reference the same WorldModel without burying planning logic directly in prompt text.
Next steps
Section titled “Next steps”- SDK Reference — Full API documentation
- Manifest Format — Detailed manifest structure and validation rules
- Testing — Run the conformance harness against your agent