Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion public/ambient-verification.html
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ <h2>Trust checks</h2>
<ul>
<li>receipt structure</li>
<li>metadata.proof present</li>
<li>canonicalization = json.sorted_keys.v1</li>
<li>canonicalization = json.sorted_keys.v1 (standard canonical JSON path)</li><li>erc8211.merkle.v1 recognized at schema layer for interoperability</li><li>metadata.trace optional for correlation across multi-step workflows and batch execution</li>
<li>hash_alg = SHA-256</li>
<li>hash_matches</li>
<li>signature_alg = Ed25519</li>
Expand Down
6 changes: 3 additions & 3 deletions public/api.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ <h1 class="hero-h1">API surfaces for verifiable agent actions.</h1>
<a class="btn btn-primary btn-lg" href="/verify.html">Try Verifier</a>
<a class="btn btn-secondary btn-lg" href="/stack-proof-demo.html">View Production Proof</a>
</div>
<div class="proof-status"><strong>Production proof status:</strong> Runtime production is live and signs canonical Trust Verification receipts. MCP E2E against production runtime passes: STEP 1 SIGNED, STEP 2 VERIFIED, STEP 3 TAMPERED INVALID. Runtime signer is <code>runtime.commandlayer.eth</code> with <code>kid=vC4WbcNoq2znSCiQ</code>. Canonical proof is <code>metadata.proof.canonicalization=json.sorted_keys.v1</code>, <code>metadata.proof.hash.alg=SHA-256</code>, <code>metadata.proof.signature.alg=Ed25519</code>.</div>
<div class="proof-status"><strong>Production proof status:</strong> Runtime production is live and signs canonical Trust Verification receipts. MCP E2E against production runtime passes: STEP 1 SIGNED, STEP 2 VERIFIED, STEP 3 TAMPERED INVALID. Runtime signer is <code>runtime.commandlayer.eth</code> with <code>kid=vC4WbcNoq2znSCiQ</code>. Canonical proof uses <code>metadata.proof</code> with <code>json.sorted_keys.v1</code> as the standard receipt path; <code>erc8211.merkle.v1</code> is recognized at the schema layer for interoperability.</div>
</div>
</section>

Expand Down Expand Up @@ -169,8 +169,8 @@ <h3>Input for verifier endpoints</h3>
}</code></pre>
</div>
</div>
<h3 style="margin-top:14px">Canonical proof fields</h3>
<p><code>metadata.proof.canonicalization</code><br/><code>metadata.proof.hash.alg</code><br/><code>metadata.proof.hash.value</code><br/><code>metadata.proof.signature.alg</code><br/><code>metadata.proof.signature.value</code><br/><code>metadata.proof.signature.kid</code><br/><code>metadata.proof.signer_id</code></p>
<h3 style="margin-top:14px">Canonical proof fields</h3><p><code>metadata.proof</code> is required. <code>metadata.trace</code> is optional for multi-step workflow correlation (agents, spans, solver fills, and batch execution).</p><p><code>metadata.proof.signature</code> can be a single Ed25519 object or an array of role-based Ed25519 signature entries.</p><p>Allowed signature roles: <code>user</code>, <code>solver</code>, <code>relayer</code>, <code>agent</code>, <code>runtime</code>, <code>verifier</code>. Do not assume every signature in a multi-signature array is verified unless your verifier explicitly validates all of them.</p>
<p><code>metadata.proof.canonicalization</code><br/><code>metadata.proof.hash.alg</code><br/><code>metadata.proof.hash.value</code><br/><code>metadata.proof.signature</code> (single object or role-based array)<br/><code>metadata.proof.signer_id</code><br/><code>metadata.trace</code> (optional)</p>
</section>

<section class="api-card section">
Expand Down
6 changes: 4 additions & 2 deletions public/canonical-receipts.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@
"value": "..."
},
"signer_id": "runtime.commandlayer.eth"
}
},
"trace": { "trace_id": "trace_01", "span_id": "span_01" }
}
}</code></pre></section>
<section class="doc-card"><h2>Required proof fields</h2><ul><li><code>metadata.proof.canonicalization</code></li><li><code>metadata.proof.hash.alg</code></li><li><code>metadata.proof.hash.value</code></li><li><code>metadata.proof.signature.alg</code></li><li><code>metadata.proof.signature.kid</code></li><li><code>metadata.proof.signature.value</code></li><li><code>metadata.proof.signer_id</code></li></ul></section>
<section class="doc-card"><h2>Canonicalization and interoperability</h2><p><code>json.sorted_keys.v1</code> remains the standard canonical JSON receipt path.</p><p><code>erc8211.merkle.v1</code> is recognized at the schema layer and accepted for interoperability. Full local ERC-8211 Merkle cryptographic verification should only be claimed where implemented.</p><p><code>metadata.proof.signature</code> supports a single Ed25519 signature object or a multi-signature array with roles for solver/relayer/batch workflows.</p><p>Allowed roles: <code>user</code>, <code>solver</code>, <code>relayer</code>, <code>agent</code>, <code>runtime</code>, <code>verifier</code>.</p></section>
<section class="doc-card"><h2>Required proof fields</h2><ul><li><code>metadata.proof.canonicalization</code></li><li><code>metadata.proof.hash.alg</code></li><li><code>metadata.proof.hash.value</code></li><li><code>metadata.proof.signature</code> (single object or array)</li><li><code>metadata.proof.signer_id</code></li><li><code>metadata.trace</code> (optional)</li></ul></section>
<section class="doc-card"><h2>Verification lifecycle</h2><div class="flow-strip">receipt received → structure checked → canonical payload rebuilt → SHA-256 hash recomputed → hash compared → Ed25519 signature verified → signer identity/kid checked → VALID or INVALID</div></section>
<section class="doc-card"><h2>Valid vs tampered</h2><div class="grid-2"><div class="mini-card"><h3>Valid receipt</h3><p><code>verifier_status = VALID</code><br/><code>hash_matches = true</code><br/><code>signature_valid = true</code></p><p>Valid receipt accepted.</p></div><div class="mini-card"><h3>Tampered receipt</h3><p><code>verifier_status = INVALID</code><br/><code>hash_matches = false</code><br/><code>signature_valid = false</code></p><p>Tampered receipt rejected.</p></div></div></section>
<section class="doc-card"><h2>Schema validation vs proof verification</h2><div class="warning"><strong>Schema validation checks shape. Proof verification checks truth.</strong><br/>A schema-valid receipt can still be invalid if the hash or signature fails.</div></section>
Expand Down
11 changes: 5 additions & 6 deletions public/sdk-records.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
</div>
</nav>
<main>
<section class="sdk-hero"><div class="container"><div class="hero-badge"><span class="badge-dot"></span>SDK Records</div><h1 class="sdk-h1">Add verifiable receipts to agent actions.</h1><p class="sdk-sub">@commandlayer/agent-sdk wraps agent actions and emits canonical metadata.proof receipts that can be checked by CommandLayer verifiers.</p><div class="hero-actions"><a class="hero-btn primary" href="https://github.com/commandlayer/agent-sdk" target="_blank" rel="noopener">View SDK on GitHub</a><a class="hero-btn" href="/verify.html">Verify a receipt</a></div><div class="status"><strong>Wrap an agent action, emit a canonical receipt, and verify the proof.</strong><br/>Runtime production is live. Runtime signs canonical Trust Verification receipts. MCP E2E against production runtime passes: STEP 1 SIGNED, STEP 2 VERIFIED, STEP 3 TAMPERED INVALID. Runtime signer: <code>signer_id = runtime.commandlayer.eth</code>, <code>kid = vC4WbcNoq2znSCiQ</code>. Canonical proof: <code>metadata.proof.canonicalization = json.sorted_keys.v1</code>, <code>metadata.proof.hash.alg = SHA-256</code>, <code>metadata.proof.signature.alg = Ed25519</code>.</div></div></section>
<section class="sdk-hero"><div class="container"><div class="hero-badge"><span class="badge-dot"></span>SDK Records</div><h1 class="sdk-h1">Add verifiable receipts to agent actions.</h1><p class="sdk-sub">@commandlayer/agent-sdk wraps agent actions and emits canonical metadata.proof receipts that can be checked by CommandLayer verifiers.</p><div class="hero-actions"><a class="hero-btn primary" href="https://github.com/commandlayer/agent-sdk" target="_blank" rel="noopener">View SDK on GitHub</a><a class="hero-btn" href="/verify.html">Verify a receipt</a></div><div class="status"><strong>Wrap an agent action, emit a canonical receipt, and verify the proof.</strong><br/>Runtime production is live. Runtime signs canonical Trust Verification receipts. MCP E2E against production runtime passes: STEP 1 SIGNED, STEP 2 VERIFIED, STEP 3 TAMPERED INVALID. Runtime signer: <code>signer_id = runtime.commandlayer.eth</code>, <code>kid = vC4WbcNoq2znSCiQ</code>. Canonical proof keeps <code>json.sorted_keys.v1</code> as the standard receipt path, while <code>erc8211.merkle.v1</code> is accepted for interoperability at the schema layer. Signature shape supports single-signature and multi-signature proof entries for solver/relayer/batch workflows.</div></div></section>

<section class="section section-alt"><div class="container"><div class="section-eyebrow">Install</div><h2 class="section-h2">Install the SDK package.</h2><div class="copy-code-box"><button class="copy-code-button" type="button">Copy</button><pre class="code">npm install @commandlayer/agent-sdk

Expand All @@ -80,13 +80,12 @@

const verified = await cl.verify(receipt);</pre></div></div></section>

<section class="section section-alt"><div class="container"><div class="section-eyebrow">Receipt shape</div><h2 class="section-h2">Canonical metadata.proof fields.</h2><div class="copy-code-box"><button class="copy-code-button" type="button">Copy</button><pre class="code">metadata.proof.canonicalization = "json.sorted_keys.v1"
<section class="section section-alt"><div class="container"><div class="section-eyebrow">Receipt shape</div><h2 class="section-h2">Canonical metadata.proof and metadata.trace fields.</h2><div class="copy-code-box"><button class="copy-code-button" type="button">Copy</button><pre class="code">metadata.proof.canonicalization = "json.sorted_keys.v1"
metadata.proof.hash.alg = "SHA-256"
metadata.proof.hash.value = "..."
metadata.proof.signature.alg = "Ed25519"
metadata.proof.signature.kid = "vC4WbcNoq2znSCiQ"
metadata.proof.signature.value = "..."
metadata.proof.signer_id = "runtime.commandlayer.eth"</pre></div></div></section>
metadata.proof.signature = { alg: "Ed25519", kid: "vC4WbcNoq2znSCiQ", value: "..." } // single-signature proof
metadata.proof.signer_id = "runtime.commandlayer.eth"
metadata.trace = { trace_id: "trace_..." } // optional correlation metadata</pre></div></div></section>

<section class="section"><div class="container"><div class="section-eyebrow">What the SDK does</div><div class="cards"><article class="card">Wraps agent actions into consistent execution envelopes.</article><article class="card">Emits canonical receipts for each wrapped action.</article><article class="card">Normalizes canonical proof shape under metadata.proof.</article><article class="card">Calls verifier endpoints to confirm receipt validity.</article><article class="card">Helps developers integrate without rebuilding proof plumbing.</article></div></div></section>

Expand Down
6 changes: 3 additions & 3 deletions public/verify-badge-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,16 @@ <h3>What gets checked through the verifier</h3>
<ul>
<li>receipt structure</li>
<li><code>metadata.proof</code> present</li>
<li><code>json.sorted_keys.v1</code> canonicalization</li>
<li><code>json.sorted_keys.v1</code> canonicalization (standard JSON receipt path)</li><li><code>erc8211.merkle.v1</code> canonicalization recognized at schema layer for interoperability</li>
<li>SHA-256 hash match</li>
<li>Ed25519 signature validity</li>
<li><code>signature.kid</code> (<code>vC4WbcNoq2znSCiQ</code>)</li>
<li><code>signer_id</code> (<code>runtime.commandlayer.eth</code>)</li>
<li>supported capability verb</li>
<li>tamper invalidation</li>
</ul>
<p>The canonical proof model is:</p>
<p><code>metadata.proof.canonicalization = json.sorted_keys.v1</code><br /><code>metadata.proof.hash.alg = SHA-256</code><br /><code>metadata.proof.hash.value</code><br /><code>metadata.proof.signature.alg = Ed25519</code><br /><code>metadata.proof.signature.kid = vC4WbcNoq2znSCiQ</code><br /><code>metadata.proof.signature.value</code><br /><code>metadata.proof.signer_id = runtime.commandlayer.eth</code></p>
<p>Canonical proof model (single-signature example):</p>
<p><code>metadata.proof.canonicalization = json.sorted_keys.v1</code><br /><code>metadata.proof.hash.alg = SHA-256</code><br /><code>metadata.proof.hash.value</code><br /><code>metadata.proof.signature = { alg, kid, value }</code><br /><code>metadata.proof.signer_id = runtime.commandlayer.eth</code><br /><code>metadata.trace = { trace_id, span_id? }</code> (optional)</p><p>Multi-signature shape is also supported for solver/relayer/batch workflows via <code>metadata.proof.signature[]</code> entries with <code>role</code> values of <code>user</code>, <code>solver</code>, <code>relayer</code>, <code>agent</code>, <code>runtime</code>, or <code>verifier</code>.</p>
<p>Runtime endpoint: <code>https://runtime.commandlayer.org</code>.</p>
</article>
</div>
Expand Down
39 changes: 37 additions & 2 deletions tests/verifyReceipt-runtime.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@ async function makeRuntimeReceipt() {
return { receipt, rawPub };
}


function isSingleProofSignature(signature) {
return Boolean(signature) && !Array.isArray(signature) && typeof signature === 'object';
}

function isMultiProofSignature(signature) {
return Array.isArray(signature);
}

function getPrimaryProofSignature(proof) {
const signature = proof?.signature;
if (isSingleProofSignature(signature)) return signature;
if (isMultiProofSignature(signature)) return signature[0] || null;
return null;
}

function makeTextResolver(pub) {
return async (_ens, key) => ({
'cl.sig.pub': `ed25519:${pub}`,
Expand Down Expand Up @@ -92,14 +108,33 @@ test('wrong canonicalization rejects', async () => {

test('wrong kid rejects', async () => {
const { receipt, rawPub } = await makeRuntimeReceipt();
receipt.metadata.proof.signature.kid = 'wrong';
const primarySignature = getPrimaryProofSignature(receipt.metadata.proof);
assert.ok(primarySignature);
primarySignature.kid = 'wrong';
const out = await verifyReceipt(receipt, { ens: { textResolver: makeTextResolver(rawPub) } });
assert.equal(out.status, 'INVALID');
});

test('legacy top-level proof does not verify', async () => {
const { receipt, rawPub } = await makeRuntimeReceipt();
receipt.signature = { kid: 'vC4WbcNoq2znSCiQ', sig: receipt.metadata.proof.signature.value };
const primarySignature = getPrimaryProofSignature(receipt.metadata.proof);
assert.ok(primarySignature);
receipt.signature = { kid: 'vC4WbcNoq2znSCiQ', sig: primarySignature.value };
const out = await verifyReceipt(receipt, { ens: { textResolver: makeTextResolver(rawPub) } });
assert.equal(out.status, 'INVALID');
});


test('multi-signature proof shape does not crash runtime verifier', async () => {
const { receipt, rawPub } = await makeRuntimeReceipt();
const original = receipt.metadata.proof.signature;
receipt.metadata.proof.signature = [
{ role: 'runtime', ...original },
{ role: 'relayer', alg: 'Ed25519', kid: 'other', value: original.value },
];
assert.equal(isMultiProofSignature(receipt.metadata.proof.signature), true);
const primarySignature = getPrimaryProofSignature(receipt.metadata.proof);
assert.ok(primarySignature);
const out = await verifyReceipt(receipt, { ens: { textResolver: makeTextResolver(rawPub) } });
assert.equal(out.status, 'INVALID');
});
Loading