Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <title>ControlSpec — Before an agent acts</title> | |
| <meta name="description" content="Explore seven recorded ControlSpec examples: spending limits, approval requirements, self-approval rejection and changed intent binding."> | |
| <style> | |
| :root{color-scheme:light;--ink:#18382e;--muted:#607268;--line:#d7e1d8;--paper:#f5f7ef;--green:#246346;--white:#fff;--amber:#8d590a;--red:#ab3838}*{box-sizing:border-box}body{margin:0;background:var(--paper);color:var(--ink);font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;line-height:1.55}a{color:inherit;text-underline-offset:3px}button{font:inherit;cursor:pointer}button:focus-visible,a:focus-visible,summary:focus-visible{outline:3px solid #297aab;outline-offset:4px}header{display:flex;justify-content:space-between;align-items:center;padding:22px 0;border-bottom:1px solid var(--line);gap:20px}.brand{font-weight:800;font-size:21px;letter-spacing:-.6px}.brand span{display:inline-grid;place-items:center;background:var(--ink);color:white;width:30px;height:30px;border-radius:7px;margin-right:9px;font-size:18px}nav{display:flex;gap:24px;font-size:14px}main,header,footer{max-width:1120px;margin:auto}main{padding:42px 0}.eyebrow{text-transform:uppercase;letter-spacing:1.8px;font-size:11px;font-weight:800;color:var(--green);margin:0 0 10px}h1{font-size:clamp(30px,4vw,47px);letter-spacing:-1.8px;line-height:1.15;margin:0 0 15px;max-width:830px}h2,h3,p{margin-top:0}.intro{max-width:700px;color:var(--muted);font-size:17px;margin-bottom:18px}.notice{font-size:13px;border-left:3px solid #93b598;padding:8px 12px;max-width:790px;margin-bottom:30px}.workbench{display:grid;grid-template-columns:340px 1fr;gap:20px}.panel{background:var(--white);border:1px solid var(--line);border-radius:14px;padding:25px}.tabs{display:flex;border-bottom:1px solid var(--line);gap:8px;padding-bottom:16px;margin-bottom:20px}.tab{border:0;border-radius:7px;padding:8px 14px;background:transparent;color:var(--muted);font-weight:650}.tab[aria-pressed=true]{background:var(--ink);color:white}.section-label{font-size:12px;color:var(--muted);margin-bottom:12px}.choices{display:flex;flex-direction:column;gap:10px}.choice{border:1px solid var(--line);border-radius:9px;background:white;text-align:left;color:var(--ink);padding:14px 15px;transition:border-color .12s}.choice:hover{border-color:var(--green)}.choice[aria-pressed=true]{border-color:var(--green);box-shadow:inset 3px 0 var(--green);background:#f1f7f1}.choice strong{display:block;font-size:15px}.choice small{display:block;color:var(--muted);margin-top:3px;font-size:12px}.pack{font-size:12px;overflow-wrap:anywhere;color:var(--muted);padding-top:22px}.pack code{display:block;margin-top:6px;font-size:11px}.result-head{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-bottom:21px}.result-head .section-label{margin:0}.badge{font-size:11px;letter-spacing:1px;text-transform:uppercase;font-weight:750;border-radius:30px;padding:6px 12px;background:#e5f1e7;color:var(--green)}.badge.approval,.badge.conditions{background:#fff0d6;color:var(--amber)}.badge.block{background:#ffe9e6;color:var(--red)}.decision{font-size:32px;letter-spacing:-1px;margin:0 0 12px}.explanation{color:var(--muted);max-width:620px;min-height:49px}.steps{display:grid;gap:0;margin-top:25px}.step{display:grid;grid-template-columns:32px 1fr;gap:10px;border-top:1px solid var(--line);padding:17px 0}.num{color:var(--muted);font-size:12px;padding-top:3px}.step h3{font-size:14px;margin:0 0 4px}.step p{font-size:13px;color:var(--muted);margin:0}.step code{font-size:12px;overflow-wrap:anywhere}.toggle{margin-top:12px;border:1px solid var(--line);background:#f5f7f4;color:var(--ink);border-radius:7px;padding:8px 12px;font-size:12px}.toggle[aria-pressed=true]{background:#ffe9e6;border-color:#d6aaa4}.binding-error{color:var(--red)!important;font-weight:650}.bottom{display:flex;gap:24px;justify-content:space-between;padding-top:28px;color:var(--muted);font-size:13px}.bottom p{max-width:610px}details{margin-top:20px;border:1px solid var(--line);border-radius:10px;padding:15px 18px;background:#fff}summary{cursor:pointer;font-size:13px;font-weight:650}pre{font-size:11px;white-space:pre-wrap;overflow-wrap:anywhere;max-height:300px;overflow:auto;background:#f5f7f4;padding:14px;border-radius:6px}footer{border-top:1px solid var(--line);padding:20px 0 30px;color:var(--muted);font-size:12px;display:flex;justify-content:space-between;gap:20px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}[hidden]{display:none!important}@media(max-width:1180px){header,main,footer{margin-left:24px;margin-right:24px}}@media(max-width:760px){main{padding-top:28px}.workbench{grid-template-columns:1fr}.panel{padding:20px}.choices{display:grid;grid-template-columns:1fr 1fr}.choice{padding:12px}.pack{padding-top:15px}.bottom,footer{flex-direction:column;gap:8px}.result-head{align-items:flex-start}.decision{font-size:28px}nav{gap:14px}header{padding:17px 0}.intro{font-size:15px}}@media(prefers-reduced-motion:reduce){*{transition:none!important}} | |
| </style> | |
| </head> | |
| <body> | |
| <header><a class="brand" href="https://github.com/claytonsamples/controlspec" target="_blank" rel="noopener noreferrer"><span aria-hidden="true">C</span>ControlSpec</a><nav aria-label="Project"><a href="https://github.com/claytonsamples/controlspec#try-it-locally" target="_blank" rel="noopener noreferrer">Run locally ↗</a><a href="https://github.com/claytonsamples/controlspec" target="_blank" rel="noopener noreferrer">GitHub ↗</a></nav></header> | |
| <main><p class="eyebrow">An open-source experiment in agent controls</p><h1>Before an agent acts,<br>what should it be allowed to do?</h1><p class="intro">Explore how a proposed action meets a specific set of controls. Change the scenario. Inspect the decision, its binding, and what the outcome actually proves.</p><p class="notice"><strong>Recorded reference examples.</strong> These outputs come from the real Python evaluator. This static page does not evaluate new policies or execute actions. An “allow” result here is not production permission.</p> | |
| <div class="workbench"> | |
| <section class="panel" aria-label="Choose an agent scenario"><div class="tabs" role="group" aria-label="Example domain"><button class="tab" id="personal-tab" aria-pressed="true">Personal spending</button><button class="tab" id="smb-tab" aria-pressed="false">Sales</button></div><p class="section-label">Choose a proposed action</p><div class="choices" id="choices"></div><p class="pack">Selected immutable example pack<code id="pack"></code></p></section> | |
| <section class="panel" aria-label="Recorded reference result"><div class="result-head"><p class="section-label">ControlSpec reference result</p><span class="badge" id="badge"></span></div><div aria-live="polite" aria-atomic="true"><h2 class="decision" id="decision"></h2><p class="explanation" id="explanation"></p></div><div class="steps"><div class="step"><span class="num">01</span><div><h3>Decision and route</h3><p id="route"></p></div></div><div class="step"><span class="num">02</span><div><h3>Recheck the exact action</h3><p id="binding" aria-live="polite"></p><button class="toggle" id="mutate" aria-pressed="false" hidden>Change the purchase after the decision</button></div></div><div class="step"><span class="num">03</span><div><h3>Assess the outcome</h3><p id="receipt"></p></div></div></div></section> | |
| </div> | |
| <details><summary>Inspect the recorded data and provenance</summary><p class="section-label" id="provenance"></p><pre id="raw"></pre><a href="observations.json" download>Download all seven observations</a></details> | |
| <div class="bottom"><p><strong>Building an agent?</strong> Try one of your controls against the Python reference. We want integration attempts, uncomfortable edge cases, and feedback on the contract.</p><a href="https://github.com/claytonsamples/controlspec/issues/new" target="_blank" rel="noopener noreferrer">Share an integration idea ↗</a></div> | |
| </main><footer><span>ControlSpec · Apache-2.0 · Experimental community preview</span><span>Human-owned controls. Exact action binding. Evidence after action.</span></footer> | |
| <script id="observations" type="application/json">{"mode":"recorded_reference_outputs","source_commit":"77178798ffe7fed1e6608b7d4037e67c1c8cd113","reference_time":"2026-08-20T12:00:00.000000Z","external_actions_executed":false,"domains":[{"domain":"personal","release_id":"v0.1.1","catalog_digest":"sha256:07e00e11176752146d402c31269d3c89dbe1f8ae200c98a91f7e4f34f7888322","scenarios":[{"scenario_id":"groceries-42","intent_digest":"sha256:eae71621e734dcf7b654a778562900935637da3b62384ac8a06802ede2d1c16d","pack_catalog_id":"personal.agent.spending:spending-baseline@0.1.0","verdict":"allow","route_kind":"continue","route_id":"continue","recheck_valid":true,"changed_recheck_valid":false,"receipt_status":"incomplete","missing_evidence_count":1,"verified_evidence_count":0,"assessment_basis":"caller_report_only","stored":false,"durable":false,"route_substitution_rejected":true},{"scenario_id":"groceries-142","intent_digest":"sha256:5b0a007d31cec073c4a6c8731e192c15cc7de7e0a0c4d96b64d4b23210afd1c0","pack_catalog_id":"personal.agent.spending:spending-baseline@0.1.0","verdict":"require_approval","route_kind":"ask_user","route_id":"ask-before-purchase","recheck_valid":true,"changed_recheck_valid":null,"receipt_status":"failed","missing_evidence_count":0,"verified_evidence_count":0,"assessment_basis":"caller_report_only","stored":false,"durable":false,"route_substitution_rejected":true},{"scenario_id":"recurring-999","intent_digest":"sha256:bc82299648aa586ad4cb8da960d413c5cfbeaca046e58912a359714b7d0ec801","pack_catalog_id":"personal.agent.spending:spending-baseline@0.1.0","verdict":"require_approval","route_kind":"ask_user","route_id":"ask-before-recurring-purchase","recheck_valid":true,"changed_recheck_valid":null,"receipt_status":"failed","missing_evidence_count":0,"verified_evidence_count":0,"assessment_basis":"caller_report_only","stored":false,"durable":false,"route_substitution_rejected":true}],"machine_summary":{"status":"ok","scope":"local_reference_examples","domain":"personal","release_id":"v0.1.1","catalog_digest":"sha256:07e00e11176752146d402c31269d3c89dbe1f8ae200c98a91f7e4f34f7888322","observed":[{"id":"groceries-42","verdict":"allow","recheck_valid":true,"receipt_status":"incomplete","non_authoritative":true,"deterministic_repeat":true,"route_substitution_rejected":true},{"id":"groceries-142","verdict":"require_approval","recheck_valid":true,"receipt_status":"failed","non_authoritative":true,"deterministic_repeat":true,"route_substitution_rejected":true},{"id":"recurring-999","verdict":"require_approval","recheck_valid":true,"receipt_status":"failed","non_authoritative":true,"deterministic_repeat":true,"route_substitution_rejected":true}],"scenario_count":3,"probe_count":0,"operations":["GET packs","GET packs/{id}","GET controls","GET controls/{id}","POST decide","POST recheck","POST receipts"],"external_actions_executed":false,"receipts_stored":false}},{"domain":"smb","release_id":"v0.1.1","catalog_digest":"sha256:07e00e11176752146d402c31269d3c89dbe1f8ae200c98a91f7e4f34f7888322","scenarios":[{"scenario_id":"draft","intent_digest":"sha256:c97b00a3ce7f1e71a27f90bab783f4490f1fe09286f137abaa5cf2cf2882b64d","pack_catalog_id":"smb.sales.controls:sales-baseline@0.1.0","verdict":"allow","route_kind":"continue","route_id":"continue-draft","recheck_valid":true,"changed_recheck_valid":null,"receipt_status":"failed","missing_evidence_count":0,"verified_evidence_count":0,"assessment_basis":"caller_report_only","stored":false,"durable":false,"route_substitution_rejected":true},{"scenario_id":"discount-8","intent_digest":"sha256:be0d497159b6110a72d0a6bea0c2db21f82202f40e6217ef586ae1f51bbac7d0","pack_catalog_id":"smb.sales.controls:sales-baseline@0.1.0","verdict":"allow_with_conditions","route_kind":"continue","route_id":"continue-within-limit","recheck_valid":true,"changed_recheck_valid":null,"receipt_status":"failed","missing_evidence_count":0,"verified_evidence_count":0,"assessment_basis":"caller_report_only","stored":false,"durable":false,"route_substitution_rejected":true},{"scenario_id":"discount-15","intent_digest":"sha256:ec4f4dee20b67ee8dd0b264dcbf60f185eda92d48fa48bbf2ed54f0ff090e5d4","pack_catalog_id":"smb.sales.controls:sales-baseline@0.1.0","verdict":"require_approval","route_kind":"continue","route_id":"continue","recheck_valid":true,"changed_recheck_valid":null,"receipt_status":"failed","missing_evidence_count":0,"verified_evidence_count":0,"assessment_basis":"caller_report_only","stored":false,"durable":false,"route_substitution_rejected":true},{"scenario_id":"smb-discount-15-direct-self-approval","intent_digest":"sha256:c28c5920136a243b8256f8baaa59709217a8f7043e95dcec06013aaee3d1bf1a","pack_catalog_id":"smb.sales.controls:sales-baseline@0.1.0","verdict":"block","route_kind":"block","route_id":"fail-closed-block","recheck_valid":true,"changed_recheck_valid":null,"receipt_status":"failed","missing_evidence_count":0,"verified_evidence_count":0,"assessment_basis":"caller_report_only","stored":false,"durable":false,"route_substitution_rejected":true}],"machine_summary":{"status":"ok","scope":"local_reference_examples","domain":"smb","release_id":"v0.1.1","catalog_digest":"sha256:07e00e11176752146d402c31269d3c89dbe1f8ae200c98a91f7e4f34f7888322","observed":[{"id":"draft","verdict":"allow","recheck_valid":true,"receipt_status":"failed","non_authoritative":true,"deterministic_repeat":true,"route_substitution_rejected":true},{"id":"discount-8","verdict":"allow_with_conditions","recheck_valid":true,"receipt_status":"failed","non_authoritative":true,"deterministic_repeat":true,"route_substitution_rejected":true},{"id":"discount-15","verdict":"require_approval","recheck_valid":true,"receipt_status":"failed","non_authoritative":true,"deterministic_repeat":true,"route_substitution_rejected":true},{"id":"smb-discount-15-direct-self-approval","verdict":"block","recheck_valid":true,"receipt_status":"failed","non_authoritative":true,"deterministic_repeat":true,"route_substitution_rejected":true}],"scenario_count":4,"probe_count":0,"operations":["GET packs","GET packs/{id}","GET controls","GET controls/{id}","POST decide","POST recheck","POST receipts"],"external_actions_executed":false,"receipts_stored":false}}]}</script> | |
| <script> | |
| ; | |
| const data=JSON.parse(document.getElementById('observations').textContent); | |
| const labels={ | |
| 'groceries-42':['$42 grocery purchase','Within the $75 example limit','The selected control permits this one-time purchase below $75. The reference decision is allow.'], | |
| 'groceries-142':['$142 grocery purchase','Above the example limit','The amount exceeds the example’s $75 boundary. The reference requires human approval.'], | |
| 'recurring-999':['$9.99 subscription','A recurring commitment','A small amount can still create a recurring commitment. The example requires human approval for recurring purchases.'], | |
| 'draft':['Draft a customer email','No message is sent','The example permits preparing a draft. A draft decision does not establish that a message was sent or its outcome verified.'], | |
| 'discount-8':['Offer an 8% discount','Within the example discount limit','The reference returns allow with conditions. Those conditions still need to be followed and supported by evidence.'], | |
| 'discount-15':['Offer a 15% discount','Above the example discount limit','This discount requires approval. A continue route by itself does not override an approval-required verdict.'], | |
| 'smb-discount-15-direct-self-approval':['Approve my own 15% discount','The same actor tries to approve','The approval fails the example’s independence check. The reference blocks this proposed action.']}; | |
| const verdicts={allow:['Allow','Within this example’s controls',''],require_approval:['Approval required','A human decision is needed','approval'],allow_with_conditions:['Allow with conditions','Conditions remain to be met','conditions'],block:['Blocked','The proposed action cannot proceed','block']}; | |
| let domain='personal', selected='groceries-42', changed=false; | |
| const el=id=>document.getElementById(id); | |
| function current(){return data.domains.find(d=>d.domain===domain).scenarios.find(s=>s.scenario_id===selected)} | |
| function renderChoices(){el('choices').replaceChildren();for(const row of data.domains.find(d=>d.domain===domain).scenarios){const b=document.createElement('button');b.className='choice';b.setAttribute('aria-pressed',String(row.scenario_id===selected));const title=document.createElement('strong');title.textContent=labels[row.scenario_id][0];const subtitle=document.createElement('small');subtitle.textContent=labels[row.scenario_id][1];b.append(title,subtitle);b.addEventListener('click',()=>{selected=row.scenario_id;changed=false;renderChoices();renderResult()});el('choices').append(b)}} | |
| function renderResult(){const row=current(),v=verdicts[row.verdict];el('decision').textContent=v[0];el('badge').textContent=row.verdict.replaceAll('_',' ');el('badge').className='badge '+v[2];el('explanation').textContent=labels[selected][2];el('pack').textContent=row.pack_catalog_id;el('route').textContent='Verdict: '+row.verdict+'. Route: '+row.route_kind+' / '+row.route_id+'.';el('binding').textContent=changed?'Binding rejected. The recorded changed intent no longer matches the prior decision. Evaluate the new intent again.':'Binding matches. The recorded actor, action, resource, context and policy selection are unchanged. This also holds for restrictive verdicts; a valid binding is not permission.';el('binding').className=changed?'binding-error':'';el('mutate').hidden=row.changed_recheck_valid===null;el('mutate').setAttribute('aria-pressed',String(changed));el('mutate').textContent=changed?'Restore the original purchase':'Change the purchase after the decision';el('receipt').textContent='Assessment: '+row.receipt_status+'. The caller reported success, but no action ran and no execution was verified. '+row.missing_evidence_count+' required evidence item(s) missing. Nothing is stored.';el('raw').textContent=JSON.stringify({...row,displaying_changed_intent:changed},null,2);el('provenance').textContent='Source commit '+data.source_commit.slice(0,12)+' · Fixed reference time '+data.reference_time+' · '+data.mode+'.'} | |
| function chooseDomain(next){domain=next;selected=data.domains.find(d=>d.domain===domain).scenarios[0].scenario_id;changed=false;el('personal-tab').setAttribute('aria-pressed',String(domain==='personal'));el('smb-tab').setAttribute('aria-pressed',String(domain==='smb'));renderChoices();renderResult()} | |
| el('personal-tab').addEventListener('click',()=>chooseDomain('personal'));el('smb-tab').addEventListener('click',()=>chooseDomain('smb'));el('mutate').addEventListener('click',()=>{if(current().changed_recheck_valid===false){changed=!changed;renderResult()}}); | |
| renderChoices();renderResult(); | |
| </script> | |
| </body></html> | |