|
| 1 | +<!DOCTYPE html> |
| 2 | +<html lang="en"> |
| 3 | +<head> |
| 4 | +<meta charset="UTF-8"> |
| 5 | +<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 6 | +<title>Model Weight Protection and Agent Governance Demos | AgenTrust</title> |
| 7 | +<meta name="description" content="Nine runnable demos for securing AI model weights and governing agents. Attestation-gated key release, tamper refusal before load, derivative lineage for fine-tunes, and 2-of-3 sovereign threshold custody. Run them on your laptop in ten minutes, no confidential-computing hardware required."> |
| 8 | +<link rel="canonical" href="https://agentrust-io.com/demos/"> |
| 9 | +<meta name="robots" content="index, follow"> |
| 10 | + |
| 11 | +<!-- Open Graph --> |
| 12 | +<meta property="og:type" content="article"> |
| 13 | +<meta property="og:site_name" content="AgenTrust"> |
| 14 | +<meta property="og:title" content="Model Weight Protection and Agent Governance Demos"> |
| 15 | +<meta property="og:description" content="Nine runnable demos: attestation-gated key release for model weights, tamper refusal before load, derivative lineage for fine-tunes, 2-of-3 sovereign threshold custody. Ten minutes on your laptop, no special hardware."> |
| 16 | +<meta property="og:url" content="https://agentrust-io.com/demos/"> |
| 17 | +<meta property="og:locale" content="en_US"> |
| 18 | +<meta property="og:image" content="https://agentrust-io.com/og.png"> |
| 19 | +<meta property="og:image:width" content="1200"> |
| 20 | +<meta property="og:image:height" content="630"> |
| 21 | +<meta property="og:image:alt" content="AgenTrust: open standards for AI agent governance"> |
| 22 | + |
| 23 | +<!-- Twitter --> |
| 24 | +<meta name="twitter:card" content="summary_large_image"> |
| 25 | +<meta name="twitter:title" content="Model Weight Protection and Agent Governance Demos"> |
| 26 | +<meta name="twitter:description" content="Attestation-gated key release, tamper refusal before load, derivative lineage, 2-of-3 sovereign threshold. Nine runnable demos, ten minutes, no special hardware."> |
| 27 | +<meta name="twitter:image" content="https://agentrust-io.com/og.png"> |
| 28 | + |
| 29 | +<!-- Icons --> |
| 30 | +<link rel="icon" href="/favicon.ico" sizes="any"> |
| 31 | +<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> |
| 32 | +<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> |
| 33 | +<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> |
| 34 | + |
| 35 | +<style> |
| 36 | + :root { |
| 37 | + --bg: #F2F4F7; |
| 38 | + --surface: #FFFFFF; |
| 39 | + --border: #D0D9E3; |
| 40 | + --navy: #15294B; |
| 41 | + --body: #2E4057; |
| 42 | + --muted: #6B7F94; |
| 43 | + --red: #B91C1C; |
| 44 | + --blue: #1B5EA0; |
| 45 | + --green: #1B7A4A; |
| 46 | + --amber: #C17817; |
| 47 | + --purple: #6D28D9; |
| 48 | + } |
| 49 | + * { box-sizing: border-box; } |
| 50 | + body { |
| 51 | + margin: 0; |
| 52 | + background: var(--bg); |
| 53 | + color: var(--body); |
| 54 | + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; |
| 55 | + line-height: 1.7; |
| 56 | + -webkit-font-smoothing: antialiased; |
| 57 | + } |
| 58 | + header.top { |
| 59 | + background: var(--navy); |
| 60 | + border-bottom: 3px solid var(--red); |
| 61 | + padding: 1rem 2rem; |
| 62 | + } |
| 63 | + header.top a.wordmark { |
| 64 | + color: #fff; |
| 65 | + text-decoration: none; |
| 66 | + font-weight: 700; |
| 67 | + letter-spacing: -0.01em; |
| 68 | + } |
| 69 | + header.top a.wordmark span { color: rgba(255,255,255,0.5); font-weight: 400; } |
| 70 | + |
| 71 | + .hero { background: var(--navy); color: #fff; padding: 3.25rem 2rem 3rem; } |
| 72 | + .hero-inner { max-width: 900px; margin: 0 auto; } |
| 73 | + .eyebrow { |
| 74 | + font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em; |
| 75 | + text-transform: uppercase; color: rgba(255,255,255,0.55); margin: 0 0 0.6rem; |
| 76 | + } |
| 77 | + .hero h1 { |
| 78 | + font-size: 2.125rem; line-height: 1.2; letter-spacing: -0.025em; |
| 79 | + margin: 0 0 1rem; color: #fff; |
| 80 | + } |
| 81 | + .hero p { color: rgba(255,255,255,0.85); margin: 0 0 1rem; max-width: 700px; } |
| 82 | + .hero code { |
| 83 | + background: rgba(255,255,255,0.12); color: #fff; |
| 84 | + padding: 0.1em 0.35em; border-radius: 3px; |
| 85 | + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.9em; |
| 86 | + } |
| 87 | + |
| 88 | + main { max-width: 900px; margin: 0 auto; padding: 3rem 2rem 4rem; } |
| 89 | + .section-label { |
| 90 | + font-size: 0.7rem; font-weight: 700; letter-spacing: 0.1em; |
| 91 | + text-transform: uppercase; color: var(--muted); margin: 0 0 0.4rem; |
| 92 | + } |
| 93 | + h2 { color: var(--navy); font-size: 1.5rem; letter-spacing: -0.02em; margin: 0 0 0.75rem; } |
| 94 | + h3 { color: var(--navy); font-size: 1.0625rem; margin: 0 0 0.4rem; letter-spacing: -0.01em; } |
| 95 | + p { margin: 0 0 1rem; } |
| 96 | + a { color: var(--red); } |
| 97 | + .lead { max-width: 720px; } |
| 98 | + |
| 99 | + .demo { |
| 100 | + background: var(--surface); |
| 101 | + border: 1px solid var(--border); |
| 102 | + border-radius: 8px; |
| 103 | + padding: 1.25rem 1.375rem; |
| 104 | + margin: 0 0 1rem; |
| 105 | + } |
| 106 | + .demo-head { |
| 107 | + display: flex; flex-wrap: wrap; align-items: baseline; |
| 108 | + gap: 0.5rem 0.75rem; margin-bottom: 0.5rem; |
| 109 | + } |
| 110 | + .demo-num { |
| 111 | + font-size: 0.68rem; font-weight: 700; letter-spacing: 0.06em; |
| 112 | + text-transform: uppercase; color: #fff; background: var(--navy); |
| 113 | + padding: 0.15rem 0.45rem; border-radius: 3px; white-space: nowrap; |
| 114 | + } |
| 115 | + .demo-time { font-size: 0.8rem; color: var(--muted); } |
| 116 | + .demo p { font-size: 0.9375rem; margin: 0 0 0.75rem; } |
| 117 | + .demo ul { font-size: 0.9375rem; margin: 0 0 0.875rem; padding-left: 1.25rem; } |
| 118 | + .demo li { margin-bottom: 0.3rem; } |
| 119 | + .demo pre { |
| 120 | + background: var(--navy); color: #E6EDF6; margin: 0; |
| 121 | + padding: 0.7rem 0.9rem; border-radius: 6px; overflow-x: auto; |
| 122 | + font-size: 0.85rem; line-height: 1.5; |
| 123 | + } |
| 124 | + pre { overflow-x: auto; } |
| 125 | + code { |
| 126 | + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; |
| 127 | + font-size: 0.9em; background: #E3E9F0; padding: 0.1em 0.35em; border-radius: 3px; |
| 128 | + } |
| 129 | + pre code { background: none; padding: 0; color: inherit; font-size: inherit; } |
| 130 | + |
| 131 | + .callout { |
| 132 | + background: var(--surface); border: 1px solid var(--border); |
| 133 | + border-left: 3px solid var(--amber); border-radius: 6px; |
| 134 | + padding: 1rem 1.125rem; font-size: 0.9375rem; margin: 0 0 2rem; |
| 135 | + } |
| 136 | + .callout strong { color: var(--navy); } |
| 137 | + .quickstart { |
| 138 | + background: var(--surface); border: 1px solid var(--border); |
| 139 | + border-radius: 8px; padding: 1.25rem 1.375rem; margin: 0 0 2.5rem; |
| 140 | + } |
| 141 | + .quickstart pre { background: var(--navy); color: #E6EDF6; padding: 0.85rem 1rem; border-radius: 6px; font-size: 0.85rem; } |
| 142 | + hr.divider { border: none; border-top: 1px solid var(--border); margin: 2.5rem 0; } |
| 143 | + |
| 144 | + footer { |
| 145 | + border-top: 1px solid var(--border); padding: 1.5rem 2rem; |
| 146 | + font-size: 0.875rem; color: var(--muted); text-align: center; |
| 147 | + } |
| 148 | + footer a { color: var(--body); } |
| 149 | + |
| 150 | + @media (max-width: 640px) { |
| 151 | + .hero { padding: 2.25rem 1.25rem 2rem; } |
| 152 | + .hero h1 { font-size: 1.625rem; } |
| 153 | + main { padding: 2rem 1.25rem 3rem; } |
| 154 | + header.top { padding: 0.875rem 1.25rem; } |
| 155 | + } |
| 156 | +</style> |
| 157 | +</head> |
| 158 | +<body> |
| 159 | + |
| 160 | +<header class="top"> |
| 161 | + <a class="wordmark" href="/">agentrust<span>.io</span></a> |
| 162 | +</header> |
| 163 | + |
| 164 | +<div class="hero"> |
| 165 | + <div class="hero-inner"> |
| 166 | + <p class="eyebrow">Runnable Demos</p> |
| 167 | + <h1>Don't take the spec on trust.<br>Run it.</h1> |
| 168 | + <p>Nine demos, about ten minutes end to end. Four cover custody of model weights: binding a checkpoint's hash, gating the decryption key behind attestation, tracking a fine-tune's lineage, and splitting the key so no single party can release it. Five cover governing what an agent does at the tool boundary.</p> |
| 169 | + <p>Everything runs in software mode with <code>CMCP_DEV_MODE=1</code>. No confidential-computing hardware, no cloud account, no signup.</p> |
| 170 | + </div> |
| 171 | +</div> |
| 172 | + |
| 173 | +<main> |
| 174 | + |
| 175 | + <div class="quickstart"> |
| 176 | + <h3>Quick start</h3> |
| 177 | + <pre><code>pip install cmcp-runtime weight-custody-manifest |
| 178 | +git clone https://github.com/agentrust-io/demos && cd demos |
| 179 | +export CMCP_BEARER_TOKEN=demo-token |
| 180 | +python demo.py # all nine, pausing before each |
| 181 | +python demo.py 6 # just demo 6</code></pre> |
| 182 | + <p style="font-size:0.875rem;color:var(--muted);margin:0.875rem 0 0;">Demos 1 to 5 are driven by <code>cmcp-runtime</code>. Demos 6 to 9 need only <code>weight-custody-manifest</code>, with no server and no gateway. Source: <a href="https://github.com/agentrust-io/demos">github.com/agentrust-io/demos</a>.</p> |
| 183 | + </div> |
| 184 | + |
| 185 | + <p class="section-label">Model Weights</p> |
| 186 | + <h2>Securing model weights</h2> |
| 187 | + <p class="lead">A fine-tune trained on your own data is IP that never existed publicly, and the weights are where it lives. These four demos treat the weights as the asset: bind the exact checkpoint, release the decryption key only into a serving stack that proves what it is, and keep the lineage of every derivative verifiable back to its base.</p> |
| 188 | + |
| 189 | + <div class="callout"> |
| 190 | + <strong>The honest limit, stated up front.</strong> Against an adversary who physically owns the silicon, no current confidential-computing platform is custody-grade. <a href="https://tee.fail/">TEE.fail</a> and BadRAM are the reason. What these demos give you is accountability-grade custody under an operator-trust model, plus a threshold scheme (demo 9) for when one operator's word is not enough. Anyone selling you weight protection "without operator trust assumptions" is overstating what the hardware does. |
| 191 | + </div> |
| 192 | + |
| 193 | + <div class="demo"> |
| 194 | + <div class="demo-head"><span class="demo-num">Demo 6</span><strong>Weight custody</strong><span class="demo-time">~60 seconds</span></div> |
| 195 | + <p>A Weight Custody Manifest binds the checkpoint's exact <code>weights_hash</code>, gates the decryption key behind attestation, and carries the fine-tune's lineage.</p> |
| 196 | + <ul> |
| 197 | + <li>a manifest jointly signed by builder and custodian binds the exact <code>weights_hash</code>, and the signature verifies</li> |
| 198 | + <li>the attestation gate releases the key only for the certified serving stack: genuine nonce, approved platform, signed image measurement</li> |
| 199 | + <li>a tampered checkpoint's hash does not match, so it is <strong>refused before it ever loads</strong></li> |
| 200 | + <li>a fine-tune verifies as a derivative back to the signed base</li> |
| 201 | + </ul> |
| 202 | + <pre><code>python demo-06-weight-custody/run.py</code></pre> |
| 203 | + </div> |
| 204 | + |
| 205 | + <div class="demo"> |
| 206 | + <div class="demo-head"><span class="demo-num">Demo 7</span><strong>Closed-weight custody</strong><span class="demo-time">~60 seconds</span></div> |
| 207 | + <p>The mirror of demo 6. Here the base model is closed, a frontier lab shipping weights into a customer's or a sovereign's own enclave, so the weights themselves are the secret and the job is keeping the key off the operator.</p> |
| 208 | + <ul> |
| 209 | + <li>a manifest with <code>base_confidentiality: confidential</code>, jointly signed by lab and customer</li> |
| 210 | + <li>the key releases only into the attested, lab-signed serving stack</li> |
| 211 | + <li>an unapproved stack, one that could export plaintext weights, is refused the key</li> |
| 212 | + <li>same protocol as demo 6, different job</li> |
| 213 | + </ul> |
| 214 | + <pre><code>python demo-07-closed-weight/run.py</code></pre> |
| 215 | + </div> |
| 216 | + |
| 217 | + <div class="demo"> |
| 218 | + <div class="demo-head"><span class="demo-num">Demo 8</span><strong>Derivative lineage</strong><span class="demo-time">~60 seconds</span></div> |
| 219 | + <p>Fine-tune inside the enclave on private data and the result is novel IP. It gets its own signed manifest with a <code>derived_from</code> pointer and a <code>rights_holder</code> split.</p> |
| 220 | + <ul> |
| 221 | + <li>a base permitting <code>fine-tune-only</code>, and a derivative permitting <code>none</code></li> |
| 222 | + <li><code>verify_lineage</code> resolves the derivative back to the base: chain, depth, root</li> |
| 223 | + <li>the <code>rights_holder</code> records the base and derivative IP split</li> |
| 224 | + <li>rights are monotone, so a fork of the no-derivatives derivative is <strong>rejected</strong></li> |
| 225 | + </ul> |
| 226 | + <pre><code>python demo-08-derivative-lineage/run.py</code></pre> |
| 227 | + </div> |
| 228 | + |
| 229 | + <div class="demo"> |
| 230 | + <div class="demo-head"><span class="demo-num">Demo 9</span><strong>Sovereign threshold</strong><span class="demo-time">~90 seconds</span></div> |
| 231 | + <p>This is the answer to the limit in the callout above. If a hardware owner who forges one attestation could release a key, then never let one release be enough.</p> |
| 232 | + <ul> |
| 233 | + <li>the model key is split <strong>2-of-3</strong> across the lab, the sovereign authority, and the customer</li> |
| 234 | + <li>a single share reconstructs nothing, so one forged attestation sits below threshold</li> |
| 235 | + <li>two independent shareholders each attest and release their share</li> |
| 236 | + <li>forging now means forging attestation to a quorum of independent roots, not one</li> |
| 237 | + </ul> |
| 238 | + <pre><code>python demo-09-sovereign-threshold/run.py</code></pre> |
| 239 | + </div> |
| 240 | + |
| 241 | + <hr class="divider"> |
| 242 | + |
| 243 | + <p class="section-label">Agent Governance</p> |
| 244 | + <h2>Governing what an agent does</h2> |
| 245 | + <p class="lead">Demos 6 to 9 protect the weights. These five govern the tool boundary: what the agent is allowed to call, under which workflow, with what compliance attributes, and what evidence survives afterwards. Cedar policy is enforced on every call and each session closes with a signed TRACE claim.</p> |
| 246 | + |
| 247 | + <div class="demo"> |
| 248 | + <div class="demo-head"><span class="demo-num">Demo 1</span><strong>cMCP in action</strong><span class="demo-time">~90 seconds</span></div> |
| 249 | + <p>An agent calls three tools through the cMCP gateway. Cedar is enforced on every call, and the session closes with a signed TRACE claim carrying the policy bundle hash.</p> |
| 250 | + <ul> |
| 251 | + <li><code>write_file</code> and <code>read_file</code> allowed, real files written to <code>workspace/</code></li> |
| 252 | + <li><code>list_dir</code> <strong>denied by policy</strong>: HTTP 403, <code>POLICY_DENY</code></li> |
| 253 | + <li>the claim carries <code>runtime.platform</code>, <code>runtime.measurement</code>, <code>policy.bundle_hash</code></li> |
| 254 | + <li>on real Intel TDX the bundle hash flows into RTMR[2] at startup</li> |
| 255 | + </ul> |
| 256 | + <pre><code>python demo-01-cmcp-in-action/run.py</code></pre> |
| 257 | + </div> |
| 258 | + |
| 259 | + <div class="demo"> |
| 260 | + <div class="demo-head"><span class="demo-num">Demo 2</span><strong>Policy swap is an attestation failure</strong><span class="demo-time">~90 seconds</span></div> |
| 261 | + <p>The operator quietly loads a different policy bundle. The claim's hash changes, and a verifier pinned to the old hash rejects it.</p> |
| 262 | + <ul> |
| 263 | + <li>v1 and v2 bundle hashes printed, visibly different</li> |
| 264 | + <li><code>write_file</code> now denied under v2</li> |
| 265 | + <li>verifying a v2 claim against the pinned v1 hash fails with <code>POLICY_HASH_MISMATCH</code></li> |
| 266 | + <li>on real TDX the measurement itself changes, not just a field</li> |
| 267 | + </ul> |
| 268 | + <pre><code>python demo-02-policy-swap/run.py</code></pre> |
| 269 | + </div> |
| 270 | + |
| 271 | + <div class="demo"> |
| 272 | + <div class="demo-head"><span class="demo-num">Demo 3</span><strong>Offline TRACE verification</strong><span class="demo-time">~60 seconds</span></div> |
| 273 | + <p>Verify the signed claim with no gateway, no server, and no network call at all.</p> |
| 274 | + <ul> |
| 275 | + <li>schema, signature, policy hash, catalog hash and audit chain all check out</li> |
| 276 | + <li><code>hardware_attestation</code> stays in <code>unverified_fields</code> in software mode, so the status reads <code>partially_verified</code></li> |
| 277 | + <li>on real TDX that field verifies too and the status becomes <code>verified</code></li> |
| 278 | + <li>no connection is made to anything</li> |
| 279 | + </ul> |
| 280 | + <pre><code>python demo-03-offline-trace/run.py</code></pre> |
| 281 | + </div> |
| 282 | + |
| 283 | + <div class="demo"> |
| 284 | + <div class="demo-head"><span class="demo-num">Demo 4</span><strong>Context-aware enforcement</strong><span class="demo-time">~90 seconds</span></div> |
| 285 | + <p>The same tool, the same arguments, allowed in one workflow and denied in another. Authorization tracks the declared call context, not the tool's name and not the model's stated intent.</p> |
| 286 | + <ul> |
| 287 | + <li><code>write_file</code> under <code>workflow_id="invoice-run"</code>: allowed</li> |
| 288 | + <li>the identical call under <code>workflow_id="chat-freeform"</code>: <strong>denied</strong>, default-deny holds</li> |
| 289 | + <li><code>read_file</code> still allowed in both, so only the write capability is scoped</li> |
| 290 | + <li>both the allow and the deny land in the signed audit chain</li> |
| 291 | + </ul> |
| 292 | + <pre><code>python demo-04-context-enforcement/run.py</code></pre> |
| 293 | + </div> |
| 294 | + |
| 295 | + <div class="demo"> |
| 296 | + <div class="demo-head"><span class="demo-num">Demo 5</span><strong>Attribute-based enforcement</strong><span class="demo-time">~90 seconds</span></div> |
| 297 | + <p>Deny on the tool's compliance attributes rather than its name. A tool that is not BAA-covered is refused by one guardrail rule, whatever it is called.</p> |
| 298 | + <ul> |
| 299 | + <li>tools tagged <code>compliance_domain=clinical</code>, <code>baa_covered=true</code>: allowed</li> |
| 300 | + <li>a tool tagged <code>baa_covered=false</code>: <strong>denied</strong></li> |
| 301 | + <li>the deny comes from <code>forbid ... when { context.baa_covered == false }</code>, overriding the baseline permit</li> |
| 302 | + <li>one rule covers every non-covered tool in the catalog, present and future</li> |
| 303 | + </ul> |
| 304 | + <pre><code>python demo-05-compliance-domain/run.py</code></pre> |
| 305 | + </div> |
| 306 | + |
| 307 | + <hr class="divider"> |
| 308 | + |
| 309 | + <h2>Where to go next</h2> |
| 310 | + <ul> |
| 311 | + <li><a href="https://github.com/agentrust-io/demos">Demo source on GitHub</a>, including a web console and a plain JSON-RPC test server</li> |
| 312 | + <li><a href="https://pypi.org/project/weight-custody-manifest/">weight-custody-manifest on PyPI</a>, the reference SDK behind demos 6 to 9</li> |
| 313 | + <li><a href="https://github.com/agentrust-io/examples/tree/main/weight-custody-manifest">Worked WCM examples</a></li> |
| 314 | + <li><a href="https://cmcp.agentrust-io.com">cMCP</a> and <a href="https://trace.agentrust-io.com">TRACE</a> specifications</li> |
| 315 | + <li><a href="/quickstart/">The ten-minute cMCP quickstart</a> if you would rather write the policy yourself</li> |
| 316 | + </ul> |
| 317 | + |
| 318 | +</main> |
| 319 | + |
| 320 | +<footer> |
| 321 | + <a href="/">AgenTrust</a> · <a href="/quickstart/">Quickstart</a> · <a href="https://github.com/agentrust-io">GitHub</a> |
| 322 | +</footer> |
| 323 | + |
| 324 | +</body> |
| 325 | +</html> |
0 commit comments