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/integrations.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ <h3>x402 Paid Actions</h3>

<article class="integration-card">
<h3>Proof Flow Composer</h3>
<p>Compose simulated external adapter events with live runtime signing and live verification under one trace_id.</p>
<p>Compose a simulated Coinbase adapter event with live x402 paid-action signed receipts and live verification under one trace_id.</p>
<div class="integration-links"><a href="/proof-flow-composer.html">Open Proof Flow Composer demo</a></div>
</article>

Expand Down
117 changes: 87 additions & 30 deletions public/proof-flow-composer.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Proof Flow Composer | CommandLayer</title>
<meta name="description" content="Compose simulated adapter events with live CommandLayer runtime receipts and verification into a single trace-linked workflow." />
<meta name="description" content="Compose a simulated Coinbase adapter event with a live x402 signed paid-action receipt and live verification in one trace-linked workflow." />
<link rel="icon" href="/favicon.ico" />
<link rel="stylesheet" href="/css/site.css" />
<style>
Expand Down Expand Up @@ -38,15 +38,15 @@
</head>
<body>
<nav><div class="container nav-inner"><a href="/" class="brand"><img src="/commandlayer-logo.png" alt="CommandLayer" /><span>CommandLayer</span></a><ul class="nav-links"><li><a href="/">Home</a></li><li><a href="/protocol.html">Protocol</a></li><li><a href="/capabilities.html">Capabilities</a></li><li><a href="/verify.html">Verifier</a></li><li><a href="/sdk-records.html">SDK</a></li><li class="nav-drop"><a href="/docs.html" class="active">Docs ▾</a><div class="nav-drop-menu"><a href="/docs.html">Docs Home</a><a href="/stack-proof-demo.html">Production Proof</a><a href="/runtime.html">Runtime</a><a href="/api.html">API Reference</a><a href="/integrations.html">Integrations</a></div></li><li><a href="/claim.html">Claim</a></li><li><a href="https://github.com/commandlayer" target="_blank" rel="noopener">GitHub</a></li></ul></div></nav>
<section class="hero"><div class="container"><div class="hero-badge"><span class="badge-dot"></span>Demo</div><h1 class="hero-h1">Proof Flow Composer</h1><p class="hero-sub">Compose simulated adapter events with live runtime signing and live VerifyAgent validation in one trace-linked workflow.</p></div></section>
<section class="hero"><div class="container"><div class="hero-badge"><span class="badge-dot"></span>Demo</div><h1 class="hero-h1">Proof Flow Composer</h1><p class="hero-sub">Compose a simulated Coinbase adapter event with live x402 paid-action signing and live verifier validation in one trace-linked workflow.</p></div></section>
<main class="container doc-shell">
<section class="doc-card">
<h2>Workflow steps</h2>
<div class="steps">
<article class="step-card"><div class="k">Coinbase Webhook</div><h3>simulated verified event</h3><span class="mode sim">simulated adapter event</span></article>
<article class="step-card"><div class="k">x402 Payment</div><h3>simulated accepted payment</h3><span class="mode sim">simulated adapter event</span></article>
<article class="step-card"><div class="k">Runtime Action</div><h3>live signed receipt</h3><span class="mode live">live</span></article>
<article class="step-card"><div class="k">VerifyAgent</div><h3>live verification</h3><span class="mode live">live</span></article>
<article class="step-card"><div class="k">x402 Paid Action</div><h3>live signed endpoint</h3><span class="mode live">live signed endpoint</span></article>
<article class="step-card"><div class="k">Action</div><h3>executed by signed x402 endpoint</h3><span class="mode live">executed by signed x402 endpoint</span></article>
<article class="step-card"><div class="k">Verify</div><h3>live verifier</h3><span class="mode live">live verifier</span></article>
</div>
<div class="controls">
<button class="btn btn-primary" id="runBtn">Run proof flow</button>
Expand All @@ -60,7 +60,7 @@ <h2>Workflow steps</h2>
<div class="trace-pill" data-span="agent.action.executed">agent.action.executed</div>
<div class="trace-pill" data-span="verifyagent.receipt.verified">verifyagent.receipt.verified</div>
</div>
<div id="status" class="status">Ready. Coinbase/x402 are simulated in browser. Runtime and VerifyAgent are live network calls.</div>
<div id="status" class="status">Ready. Coinbase webhook is simulated in browser; x402 paid action and verifier are live network calls.</div>
</section>

<section class="doc-card split">
Expand All @@ -74,7 +74,7 @@ <h2>Workflow steps</h2>
<div id="receipt" class="panel active"><pre id="receiptOut">{}</pre><button class="btn btn-secondary copy" data-copy="receiptOut">Copy</button></div>
<div id="trace" class="panel"><pre id="traceOut">{}</pre><button class="btn btn-secondary copy" data-copy="traceOut">Copy</button></div>
<div id="verification" class="panel"><pre id="verifyOut">{}</pre><button class="btn btn-secondary copy" data-copy="verifyOut">Copy</button></div>
<div id="boundary" class="panel"><pre id="boundaryOut">Coinbase and x402 shown here are simulated adapter events for demo UX. They do not prove webhook authenticity or payment settlement. Live trust starts when CommandLayer runtime signs the action receipt; verification checks that signed receipt.</pre><button class="btn btn-secondary copy" data-copy="boundaryOut">Copy</button></div>
<div id="boundary" class="panel"><pre id="boundaryOut">Coinbase webhook remains a simulated adapter event for demo UX and does not prove webhook authenticity. The x402 paid action receipt is generated by a live server-side signed endpoint, and verification is performed by the live verifier.</pre><button class="btn btn-secondary copy" data-copy="boundaryOut">Copy</button></div>
</div>
<aside>
<h3>Links</h3>
Expand All @@ -91,45 +91,102 @@ <h3>Verify cURL</h3>
<footer><div class="container footer-grid"><div><h4>Product</h4><a href="/protocol.html">Protocol</a><a href="/capabilities.html">Capabilities</a><a href="/verify.html">Verifier</a></div><div><h4>Developers</h4><a href="/docs.html">Docs</a><a href="/sdk-records.html">SDK</a><a href="/api.html">API</a></div><div><h4>Proof</h4><a href="/stack-proof-demo.html">Production Proof</a><a href="/verifyagent.html">VerifyAgent</a><a href="/canonical-receipts.html">Canonical Receipts</a></div></div></footer>
<script>
const state={traceId:null,receipt:null,verification:null,spans:[]};
const runtimeUrl='https://runtime.commandlayer.org/summarize/v1.1.0';
const verifyUrls=['/api/verify','/api/agents/verifyagent'];
const x402Url='/api/examples/x402-paid-action';
const verifyUrl='/api/verify';
const setStatus=(m,ok)=>{const el=document.getElementById('status');el.textContent=m;el.className='status '+(ok?'ok':'err')};
const writeJson=(id,v)=>{document.getElementById(id).textContent=typeof v==='string'?v:pretty(v);};
const clearStatus=(m)=>{const el=document.getElementById('status');el.textContent=m;el.className='status'};
const mark=(name)=>{const el=[...document.querySelectorAll('.trace-pill')].find(x=>x.dataset.span===name); if(el)el.classList.add('done');};
const reset=()=>{state.traceId=null;state.receipt=null;state.verification=null;state.spans=[];document.getElementById('traceLabel').textContent='trace_id: not started';document.querySelectorAll('.trace-pill').forEach(p=>p.classList.remove('done'));['receiptOut','traceOut','verifyOut'].forEach(id=>writeJson(id,{}));document.getElementById('curlOut').textContent='Run flow to generate cURL.';clearStatus('Ready. Coinbase/x402 are simulated in browser. Runtime and VerifyAgent are live network calls.');};
const reset=()=>{state.traceId=null;state.receipt=null;state.verification=null;state.spans=[];document.getElementById('traceLabel').textContent='trace_id: not started';document.querySelectorAll('.trace-pill').forEach(p=>p.classList.remove('done'));['receiptOut','traceOut','verifyOut'].forEach(id=>writeJson(id,{}));document.getElementById('curlOut').textContent='Run flow to generate cURL.';clearStatus('Ready. Coinbase webhook is simulated in browser; x402 paid action and verifier are live network calls.');};
const pretty=(v)=>JSON.stringify(v,null,2);
const doRun=async()=>{
reset();
state.traceId=`trace_${Date.now()}_${Math.random().toString(16).slice(2,8)}`;
document.getElementById('traceLabel').textContent=`trace_id: ${state.traceId}`;
const coinbase={span:'coinbase.webhook.verified',mode:'simulated adapter event',provider:'coinbase-cdp-webhook',verified:true,trace_id:state.traceId,timestamp:new Date().toISOString()};
const x402={span:'x402.payment.accepted',mode:'simulated adapter event',provider:'x402',accepted:true,asset:'USD',trace_id:state.traceId,timestamp:new Date().toISOString()};
state.spans.push(coinbase,x402); mark(coinbase.span); mark(x402.span);
clearStatus('Simulated adapter events generated. Executing live runtime action…');
let runtimeRes;
state.spans.push(coinbase);
mark(coinbase.span);

clearStatus('Simulated Coinbase webhook created. Calling live x402 paid-action endpoint…');
const x402Request={
request_id:`req_${Date.now()}_${Math.random().toString(16).slice(2,8)}`,
action:'summarize.text',
input:{text:'Summarize this trace-linked demo action in one deterministic sentence.'},
payment:{
payment_id:`pay_${Date.now()}_${Math.random().toString(16).slice(2,8)}`,
protocol:'x402',
status:'accepted',
asset:'USDC',
amount:'0.01',
network:'base'
},
metadata:{trace_id:state.traceId}
};

let x402Res;
try{
runtimeRes=await fetch(runtimeUrl,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({input:'Summarize this trace-linked demo action in one sentence.',metadata:{trace_id:state.traceId,trace:{trace_id:state.traceId}}})});
}catch(e){ writeJson('receiptOut',{error:'runtime_unreachable',detail:String(e)}); setStatus('Runtime unreachable. Live step failed before receipt signing.',false); throw e; }
if(!runtimeRes.ok){ writeJson('receiptOut',{error:'runtime_http_error',status:runtimeRes.status}); setStatus(`Runtime error ${runtimeRes.status}. Live receipt unavailable.`,false); throw new Error('runtime http error'); }
state.receipt=await runtimeRes.json();
state.spans.push({span:'agent.action.executed',mode:'live',trace_id:state.traceId}); mark('agent.action.executed');
x402Res=await fetch(x402Url,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(x402Request)});
}catch(e){
writeJson('receiptOut',{error:'network_error',detail:String(e)});
setStatus('Network error calling live x402 endpoint.',false);
throw e;
}

let x402Body={};
try{x402Body=await x402Res.json();}catch(_e){}
if(!x402Res.ok){
const err=x402Body?.error||'x402_endpoint_unavailable';
writeJson('receiptOut',{error:err,status:x402Res.status,body:x402Body});
if(err==='signing_unavailable'){
setStatus('Live x402 endpoint responded signing_unavailable.',false);
}else{
setStatus('x402 endpoint unavailable or returned an error.',false);
}
throw new Error(err);
}

state.receipt=x402Body;
state.spans.push({span:'x402.payment.accepted',mode:'live signed endpoint',trace_id:state.traceId});
state.spans.push({span:'agent.action.executed',mode:'executed by signed x402 endpoint',trace_id:state.traceId});
mark('x402.payment.accepted');
mark('agent.action.executed');
writeJson('receiptOut',state.receipt);

let verifyData=null;
for(const url of verifyUrls){
try{
const vr=await fetch(url,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({receipt:state.receipt})});
if(vr.ok){ verifyData=await vr.json(); break; }
}catch(_err){}
try{
const vr=await fetch(verifyUrl,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({receipt:state.receipt})});
const vb=await vr.json().catch(()=>({}));
if(!vr.ok){
writeJson('verifyOut',{error:'verifier_error',status:vr.status,body:vb});
setStatus('Verifier returned invalid/error response.',false);
throw new Error('verifier_error');
}
verifyData=vb;
}catch(e){
if(!document.getElementById('verifyOut').textContent || document.getElementById('verifyOut').textContent==='{}'){
writeJson('verifyOut',{error:'verifier_invalid_or_network_error',detail:String(e)});
}
setStatus('Verifier invalid/error or network error.',false);
throw e;
}
if(!verifyData){ writeJson('verifyOut',{error:'verify_unreachable',tried:verifyUrls}); setStatus('Verifier unreachable on /api/verify and /api/agents/verifyagent.',false); throw new Error('verify unavailable'); }

state.verification=verifyData;
state.spans.push({span:'verifyagent.receipt.verified',mode:'live',trace_id:state.traceId}); mark('verifyagent.receipt.verified');
writeJson('verifyOut',state.verification);
writeJson('traceOut',{trace_id:state.traceId,spans:state.spans,labels:{simulated:['coinbase.webhook.verified','x402.payment.accepted'],live:['agent.action.executed','verifyagent.receipt.verified']}});
document.getElementById('curlOut').textContent=`curl -X POST /api/verify -H 'content-type: application/json' -d '${JSON.stringify({receipt:state.receipt}).replace(/'/g,"'\\''")}'`;
setStatus('Flow complete. Simulated adapter events + live runtime receipt + live verification captured.',true);
state.spans.push({span:'verifyagent.receipt.verified',mode:'live verifier',trace_id:state.traceId});
mark('verifyagent.receipt.verified');

const summary={
trace_id:state.traceId,
receipt_id:state.receipt?.receipt_id??state.receipt?.id??null,
hash_matches:state.verification?.hash_matches??null,
signature_valid:state.verification?.signature_valid??null,
signer:state.verification?.signer??null,
key_id:state.verification?.key_id??null
};

writeJson('verifyOut',{...state.verification,summary});
writeJson('traceOut',{trace_id:state.traceId,request:x402Request,spans:state.spans,labels:{simulated:['coinbase.webhook.verified'],live:['x402.payment.accepted','agent.action.executed','verifyagent.receipt.verified']}});
document.getElementById('curlOut').textContent=`curl -X POST /api/verify -H 'content-type: application/json' -d '${JSON.stringify({receipt:state.receipt}).replace(/'/g,"'\''")}'`;
setStatus('Flow complete. Simulated Coinbase event + live x402 signed receipt + live verification captured.',true);
};
document.getElementById('runBtn').addEventListener('click',()=>doRun().catch(()=>{}));
document.getElementById('resetBtn').addEventListener('click',reset);
Expand Down
Loading