{"version":2,"width":92,"height":40,"timestamp":1786028726,"title":"Wovyr — the trust layer for AI-generated interfaces","env":{"SHELL":"/bin/sh","TERM":"xterm-256color"}}
[0.011,"o","\r\n"]
[0.082,"o","\u001b[1m  Wovyr — the trust layer for AI-generated interfaces\u001b[0m\r\n"]
[0.145,"o","\u001b[90m  A procurement agent reorders lab supplies. Two takes.\u001b[0m\r\n"]
[0.207,"o","\r\n"]
[0.271,"o","  \u001b[90mbinary   .\\target\\debug\\wovyr.exe\u001b[0m\r\n"]
[0.333,"o","  \u001b[90mpolicy   examples/policies/default-ui-policy.yaml\u001b[0m\r\n"]
[0.395,"o","  \u001b[90mstate    C:\\Users\\Punar\\AppData\\Local\\Temp\\wovyr-demo-vLt1Sh\u001b[0m\r\n"]
[0.458,"o","  \u001b[90m         \u001b[2ma scratch HOME — the real ~/.wovyr is never touched\u001b[0m\u001b[0m\r\n"]
[2.066,"o","  \u001b[32m✓\u001b[0m server up — pid 42824, healthz {\"status\":\"ok\",\"version\":\"0.4.1\"}\r\n"]
[5.642,"o","\r\n"]
[5.704,"o","\u001b[1m\u001b[35m──────────────────────────────────────────────────────────────────────────\u001b[0m\r\n"]
[5.765,"o","\u001b[1m\u001b[35m ACT 1\u001b[0m\u001b[1m  The agent is poisoned. It asks for a card number.\u001b[0m\r\n"]
[5.828,"o","\u001b[1m\u001b[35m──────────────────────────────────────────────────────────────────────────\u001b[0m\r\n"]
[5.891,"o","\u001b[36m▸\u001b[0m A compromised vendor page steers the model into composing this frame:\r\n"]
[5.954,"o","  \u001b[90m│\u001b[0m \u001b[33mtext_input\u001b[0m  name: \u001b[31mcard_number\u001b[0m   label: \"Card number\"\r\n"]
[6.015,"o","  \u001b[90m│\u001b[0m \u001b[33mbutton\u001b[0m      action: pay        label: \"Continue\"\r\n"]
[11.555,"o","  \u001b[2m\u001b[34mPOST /api/v1/workflows   (examples/workflows/ui-checkout-block.yaml)\u001b[0m\r\n"]
[14.426,"o","  \u001b[31m✗\u001b[0m execution \u001b[1mfailed\u001b[0m — the trust layer refused the frame\r\n"]
[18.005,"o","\u001b[36m▸\u001b[0m Was it ever visible to a human? Ask the only route a renderer can pull from:\r\n"]
[18.067,"o","  \u001b[2m\u001b[34mGET /api/v1/ui/frames\u001b[0m\r\n"]
[18.14,"o","  \u001b[32m✓\u001b[0m 0 frames. It was blocked \u001b[1mbefore\u001b[0m becoming visible — not filtered after.\r\n"]
[18.208,"o","  \u001b[90mThere is no raw-HTML node and no credential-input component in the protocol\u001b[0m\r\n"]
[18.271,"o","  \u001b[90mat all, so this is a structural guarantee, not a blocklist that can be evaded.\u001b[0m\r\n"]
[24.191,"o","\u001b[36m▸\u001b[0m The refusal is not just a log line. It's in the tamper-evident chain:\r\n"]
[24.266,"o","  \u001b[31m│\u001b[0m action   \u001b[1mui.frame.block\u001b[0m\r\n"]
[24.33,"o","  \u001b[31m│\u001b[0m outcome  denied\r\n"]
[24.393,"o","  \u001b[31m│\u001b[0m \u001b[31mreason   policy `default@v1` rule `sensitive_input`: input `card_number` is\u001b[0m\r\n"]
[24.456,"o","  \u001b[31m│\u001b[0m \u001b[31m         named/labelled like a credential or PII prompt (matched token `card`);\u001b[0m\r\n"]
[24.519,"o","  \u001b[31m│\u001b[0m \u001b[31m         generated frames must never collect credentials (policy `default@v1`)\u001b[0m\r\n"]
[24.583,"o","  \u001b[31m│\u001b[0m actor    wovyr-ui\r\n"]
[24.647,"o","  \u001b[31m│\u001b[0m seq 1   hash cdaa4ea8d12e…   prev e3af956634c7…\r\n"]
[24.708,"o","  \u001b[32m✓\u001b[0m the rule that fired is named in the record — an auditor can reconstruct why\r\n"]
[32.585,"o","\r\n"]
[32.647,"o","\u001b[1m\u001b[35m──────────────────────────────────────────────────────────────────────────\u001b[0m\r\n"]
[32.71,"o","\u001b[1m\u001b[35m ACT 2\u001b[0m\u001b[1m  Take two: the safe frame. It presents, with a content hash.\u001b[0m\r\n"]
[32.774,"o","\u001b[1m\u001b[35m──────────────────────────────────────────────────────────────────────────\u001b[0m\r\n"]
[32.837,"o","  \u001b[2m\u001b[34mPOST /api/v1/workflows   (examples/workflows/ui-checkout-approve.yaml)\u001b[0m\r\n"]
[33.096,"o","  \u001b[32m✓\u001b[0m frame presented — activity \u001b[1mconfirm\u001b[0m\r\n"]
[33.163,"o","  \u001b[32m│\u001b[0m frame_id    \u001b[1muif-312ea719291448d8\u001b[0m\r\n"]
[33.225,"o","  \u001b[32m│\u001b[0m frame_hash  \u001b[1m9caabdbdab09fb7035a662b04feadf519e94095c9288ffbc35c39ef99e173786\u001b[0m\r\n"]
[36.818,"o","\u001b[36m▸\u001b[0m What the human will actually see (a constrained vocabulary, nothing else):\r\n"]
[36.874,"o","  \u001b[32m│\u001b[0m \u001b[1mConfirm order\u001b[0m\r\n"]
[36.937,"o","  \u001b[32m│\u001b[0m Reorder 3 boxes of pipette tips from LabSupply Co?\r\n"]
[37,"o","  \u001b[32m│\u001b[0m \u001b[90mVendor\u001b[0m  LabSupply Co\r\n"]
[37.062,"o","  \u001b[32m│\u001b[0m \u001b[90mTotal \u001b[0m  $412.80\r\n"]
[37.125,"o","  \u001b[32m│\u001b[0m PO number  \u001b[2m[________]\u001b[0m \u001b[90m(required)\u001b[0m\r\n"]
[37.188,"o","  \u001b[32m│\u001b[0m \u001b[32m[ Approve ]\u001b[0m  \u001b[90m[ Cancel ]\u001b[0m\r\n"]
[37.251,"o","  \u001b[90mthe execution is now suspended, durably, waiting on a human\u001b[0m\r\n"]
[45.9,"o","\r\n"]
[45.962,"o","\u001b[1m\u001b[35m──────────────────────────────────────────────────────────────────────────\u001b[0m\r\n"]
[46.024,"o","\u001b[1m\u001b[35m ACT 3\u001b[0m\u001b[1m  Now break it. SIGKILL the server before anyone decides.\u001b[0m\r\n"]
[46.086,"o","\u001b[1m\u001b[35m──────────────────────────────────────────────────────────────────────────\u001b[0m\r\n"]
[46.149,"o","  \u001b[31m✗\u001b[0m kill -9 42824   \u001b[90m(no graceful shutdown, no drain, no flush)\u001b[0m\r\n"]
[46.215,"o","  \u001b[32m✓\u001b[0m server is gone — the port refuses connections\r\n"]
[51.349,"o","\u001b[36m▸\u001b[0m Restart it. Same state directory, brand-new process:\r\n"]
[52.885,"o","  \u001b[32m✓\u001b[0m server back up — pid 57140, healthz {\"status\":\"ok\",\"version\":\"0.4.1\"}\r\n"]
[56.86,"o","  \u001b[2m\u001b[34mGET /api/v1/ui/frames\u001b[0m\r\n"]
[56.929,"o","  \u001b[32m│\u001b[0m frame_id    uif-312ea719291448d8\r\n"]
[56.984,"o","  \u001b[32m│\u001b[0m frame_hash  9caabdbdab09fb7035a662b04feadf519e94095c9288ffbc35c39ef99e173786\r\n"]
[57.047,"o","  \u001b[32m✓\u001b[0m \u001b[1midentical\u001b[0m to before the kill — id and hash, byte for byte\r\n"]
[57.11,"o","  \u001b[32m✓\u001b[0m the pending decision survived a termination it could not catch\r\n"]
[64.984,"o","\r\n"]
[65.046,"o","\u001b[1m\u001b[35m──────────────────────────────────────────────────────────────────────────\u001b[0m\r\n"]
[65.109,"o","\u001b[1m\u001b[35m ACT 4\u001b[0m\u001b[1m  The human decides. Only inside the vocabulary the frame declared.\u001b[0m\r\n"]
[65.173,"o","\u001b[1m\u001b[35m──────────────────────────────────────────────────────────────────────────\u001b[0m\r\n"]
[65.235,"o","\u001b[36m▸\u001b[0m First, something the frame never offered — action \"launch\":\r\n"]
[65.297,"o","  \u001b[2m\u001b[34mPOST /api/v1/ui/decisions/uif-312ea719291448d8\u001b[0m\r\n"]
[65.359,"o","  \u001b[2m\u001b[34m     {\"action\":\"launch\"}\u001b[0m\r\n"]
[65.43,"o","  \u001b[31m✗\u001b[0m 400 validation_failed — refused at the boundary, never reached the workflow\r\n"]
[70.96,"o","\u001b[36m▸\u001b[0m Now the real approval, with the PO number the frame required:\r\n"]
[71.023,"o","  \u001b[2m\u001b[34mPOST /api/v1/ui/decisions/uif-312ea719291448d8\u001b[0m\r\n"]
[71.085,"o","  \u001b[2m\u001b[34m     {\"action\":\"approve\",\"values\":{\"po_number\":\"PO-4471\"}}\u001b[0m\r\n"]
[71.197,"o","  \u001b[32m✓\u001b[0m decided — the workflow resumes\r\n"]
[71.268,"o","  \u001b[32m✓\u001b[0m execution \u001b[1m\u001b[32mcompleted\u001b[0m\r\n"]
[74.08,"o","\u001b[36m▸\u001b[0m The decision is now part of the execution's durable event log, not a side note:\r\n"]
[74.155,"o","  \u001b[32m│\u001b[0m \u001b[2mactivity_completed\u001b[0m  id: confirm\r\n"]
[74.221,"o","  \u001b[32m│\u001b[0m action        \u001b[1mapprove\u001b[0m\r\n"]
[74.284,"o","  \u001b[32m│\u001b[0m values        {\"po_number\":\"PO-4471\"}\r\n"]
[74.345,"o","  \u001b[32m│\u001b[0m decided_by    \u001b[1mprocurement-admin\u001b[0m   \u001b[90m(the verified principal, not a client claim)\u001b[0m\r\n"]
[74.408,"o","  \u001b[32m│\u001b[0m decided_at_ms 1786028797790\r\n"]
[74.47,"o","  \u001b[32m│\u001b[0m frame_hash    9caabdbdab09fb7035a662b0…   \u001b[90m(binds the decision to exactly what was shown)\u001b[0m\r\n"]
[74.531,"o","  \u001b[32m✓\u001b[0m you cannot claim a human approved something other than what they saw\r\n"]
[82.394,"o","\r\n"]
[82.457,"o","\u001b[1m\u001b[35m──────────────────────────────────────────────────────────────────────────\u001b[0m\r\n"]
[82.52,"o","\u001b[1m\u001b[35m ACT 5\u001b[0m\u001b[1m  Prove it. The whole story, hash-linked, in order.\u001b[0m\r\n"]
[82.584,"o","\u001b[1m\u001b[35m──────────────────────────────────────────────────────────────────────────\u001b[0m\r\n"]
[82.646,"o","\u001b[36m▸\u001b[0m Every record the server wrote for this session — nothing filtered out:\r\n"]
[82.717,"o","  \u001b[32m✓\u001b[0m \u001b[2mseq   0\u001b[0m  \u001b[2mworkflow.execution.submit \u001b[0m\u001b[90mdemo-poisoned-1786028726  \u001b[0m\u001b[2mprev  → e3af9566…\u001b[0m\r\n"]
[82.786,"o","  \u001b[31m✗\u001b[0m \u001b[2mseq   1\u001b[0m  \u001b[1mui.frame.block            \u001b[0m\u001b[90muif-ffb833a180ec02ca      \u001b[0m\u001b[2mprev e3af9566… → cdaa4ea8…\u001b[0m\r\n"]
[82.848,"o","  \u001b[32m✓\u001b[0m \u001b[2mseq   2\u001b[0m  \u001b[2mworkflow.execution.submit \u001b[0m\u001b[90mdemo-checkout-1786028726  \u001b[0m\u001b[2mprev cdaa4ea8… → 245cda8a…\u001b[0m\r\n"]
[82.911,"o","  \u001b[32m✓\u001b[0m \u001b[2mseq   3\u001b[0m  \u001b[1mui.frame.present          \u001b[0m\u001b[90muif-312ea719291448d8:9ca  \u001b[0m\u001b[2mprev 245cda8a… → 40f7ab69…\u001b[0m\r\n"]
[82.974,"o","  \u001b[32m✓\u001b[0m \u001b[2mseq   4\u001b[0m  \u001b[1mui.decision.submit        \u001b[0m\u001b[90muif-312ea719291448d8:9ca  \u001b[0m\u001b[2mprev 40f7ab69… → d57c1023…\u001b[0m\r\n"]
[83.036,"o","\r\n"]
[83.099,"o","  \u001b[32m✓\u001b[0m chain verified client-side: 5 entries, 4/4 prev_hash values match their predecessor\r\n"]
[83.163,"o","  \u001b[90meach hash is a keyed HMAC, so an attacker with full write access to the log\u001b[0m\r\n"]
[83.226,"o","  \u001b[90mcan neither forge an interior entry (no key) nor truncate the tail undetected\u001b[0m\r\n"]
[83.289,"o","  \u001b[90m(a monotonic head anchor is written separately on every append).\u001b[0m\r\n"]
[88.042,"o","\r\n"]
[88.103,"o","\u001b[1m\u001b[32m══════════════════════════════════════════════════════════════════════════\u001b[0m\r\n"]
[88.166,"o","\u001b[1m  What just happened, in one line each:\u001b[0m\r\n"]
[88.23,"o","  \u001b[31m✗\u001b[0m a credential input never reached a human — structurally impossible\r\n"]
[88.293,"o","  \u001b[32m✓\u001b[0m a legitimate frame rendered, hashed, and pended durably\r\n"]
[88.357,"o","  \u001b[32m✓\u001b[0m kill -9 changed nothing: same frame_id, same frame_hash\r\n"]
[88.419,"o","  \u001b[31m✗\u001b[0m an undeclared action was refused before the workflow saw it\r\n"]
[88.482,"o","  \u001b[32m✓\u001b[0m every step is provable to an auditor, in order, tamper-evident\r\n"]
[88.545,"o","\u001b[1m\u001b[32m══════════════════════════════════════════════════════════════════════════\u001b[0m\r\n"]
[88.609,"o","\r\n"]
[88.672,"o","  \u001b[90mSelf-hosted. One Rust binary. Runs air-gapped.\u001b[0m\r\n"]
[88.735,"o","  \u001b[1mwovyr.com\u001b[0m   \u001b[90m·   cargo install wovyr-cli\u001b[0m\r\n"]
[88.797,"o","\r\n"]
