Two ways developers use CommandLayer
You already have an agent and just want receipts. Use the SDK wrapper and let CommandLayer handle receipt structure plus canonical metadata.proof fields: metadata.proof.canonicalization, metadata.proof.hash.alg/value, metadata.proof.signature.alg/value/kid, and metadata.proof.signer_id.
wrap("summarize", async () => {
return { summary: "..." };
});
You want your agent to support a known capability like summarize, authorize, verify, attest, ship, or invoice. Follow that capability's schemas, examples, agent card, discovery record, and verifier expectations.
How the stack fits together
Capabilities are the menu of possible actions. Schemas are the contracts for each action. The SDK wraps an agent action and emits receipts. The verifier checks those receipts. Your agent only uses the capabilities it actually performs.
Should schemas be downloaded?
Not usually. The better model is to resolve, fetch, or pin schemas by capability and version.
capability: summarize
version: 1.0.0
schemas:
summarize.request.schema.json
summarize.receipt.schema.json
shared-proof.schema.json
Later, discovery can expose those through ENS records, agent cards, MCP, OpenAPI, manifests, and a capability registry.
Install
npm install @commandlayer/agent-sdk
Wrap an action
Wrap your function with a capability verb. The wrapped function returns normal output plus a signed receipt with metadata.proof using json.sorted_keys.v1 canonicalization, SHA-256 hash, and Ed25519 signatures that can be independently verified.
import { CommandLayer } from "@commandlayer/agent-sdk";
const cl = new CommandLayer({
agent: "runtime.commandlayer.eth",
privateKeyPem: process.env.CL_PRIVATE_KEY_PEM,
keyId: "vC4WbcNoq2znSCiQ",
verifierUrl: "https://runtime.commandlayer.org/verify"
});
const { output, receipt } = await cl.wrap("summarize", async () => {
return { summary: "hello world" };
});
console.log(output);
console.log(receipt);
Verify the receipt
Use the SDK in-app, or paste the receipt into the public verifier.
const check = await cl.verify(receipt);
console.log(check.ok);
console.log(check.status);
console.log(check.checks);
Browser verification: /verify.html
Tamper test
const tampered = structuredClone(receipt);
tampered.result.payload.summary = "changed";
const tamperedCheck = await cl.verify(tampered);
console.log(tamperedCheck.status); // INVALID
console.log(tamperedCheck.errors?.signature_error); // hash_mismatch
Trust boundary
Runtime signs.
MCP bridges.
Verifier validates.
Schema-valid alone is not verified.
Private keys never go through MCP.
What you get back
output: the result from your wrapped function.receipt: the signed proof payload for verification.check.ok/check.status: whether verification passed.check.checks.hash_matchesandcheck.checks.signature_valid: critical proof checks.