Verified work survives the agent.
Arrastra Relay is a WebMCP hackathon prototype for evidence-gated incident handoffs. A human sets the completion policy, agents move structured work through the page's tools, and the application alone decides whether the evidence is sufficient to commit a resolution.
Live app: https://durable-handoff.aggie-king21.chatgpt.site/
The final submission should identify the exact release commit used by that deployment.
- Application-authoritative incident state shared across agent contexts in one visitor session.
- Revision checks and stale-write rejection.
- A structured handoff whose predecessor prose is treated as untrusted data.
- A deliberately rejected premature resolution with no false state advance.
- Application-run synthetic verification and an issued receipt.
- A final resolution commit plus a human-readable, exportable audit trail.
- Seven arrastra workflow beats derived from real application events, plus a human audit-view beat, rather than decorative autoplay.
The browser registers exactly five tools through document.modelContext.registerTool in
src/webmcp.js:
| Tool | Purpose |
|---|---|
read_incident |
Read the authoritative incident, evidence, policy, revision, and contract. |
submit_handoff |
Commit an evidence-backed investigator handoff. |
read_handoff |
Read the committed handoff and successor requirements. |
run_verification |
Run the application-owned synthetic checkout check. |
submit_resolution |
Attempt final resolution with the current revision and receipt. |
Consequential workflow results, including the demonstrated completion-gate refusal, are recorded in the visitor's activity history. The visible page provides reset, prompt-copy, audit-view, and proof-export controls, but it does not provide a manual substitute for the agent mutation sequence.
Arrastra Relay deliberately keeps all five tools registered for the page's lifetime. Hiding
submit_resolution until verification passes would hide the most important proof: an early close
attempt reaches the application and is refused with a corrective next action. Keeping the tool
visible is a demonstration choice, not an access-control boundary.
The handoff and resolution tools require the agent to carry forward source, evidence, and receipt identifiers issued by the application. The agent does not calculate those hashes; it preserves their chain of custody. That raises the floor on agent capability in exchange for evidence continuity across the relay.
read_incident and read_handoff use readOnlyHint: false because reads append audit events and
consume a storage revision. read_handoff also uses untrustedContentHint: true because
predecessor prose is context, not authority.
WebMCP client
-> browser-registered site tools
-> same-origin JSON API
-> incident service and deterministic domain gate
-> in-memory store locally / D1 on ChatGPT Sites
-> state-derived UI, choreography, receipts, and audit export
The local server and Sites Worker use the same service and domain logic. Local state is held in
memory. The hosted build binds a D1 database as DB and serves static assets through ASSETS.
- Node.js 18 or newer. The release candidate was verified with Node.js 22.23.2 and npm 10.9.8.
- A browser/client exposing
document.modelContext.registerToolto run the agent workflow. Either of these works:- ChatGPT or Codex in-app browser. Open the app there and the five tools register on load.
- Chrome. Enable
chrome://flags/#enable-webmcp-testing, relaunch Chrome, then load the app.
Ordinary browsers can inspect the interface, but they correctly report that the WebMCP agent tools are unavailable and show the same two options in-page.
npm ci
npm startOpen http://127.0.0.1:4174/. To choose another local port:
PORT=4177 npm startnpm testnpm test first rebuilds dist/, then runs 16 Node tests covering tool registration and
cancellation, the completion gate, evidence identifiers, choreography, HTTP routing, D1-style
compare-and-swap behavior, shared-client state, and Sites packaging.
To build without running the tests:
npm run buildThe build creates dist/client/, a bundled dist/server/index.js, and copied Sites metadata.
dist/ is generated and intentionally excluded from source control.
- Open the app in a supported client and confirm Agent tools ready · 5.
- Copy the agent task from the page into the adjacent ChatGPT or Codex conversation.
- Have the first context read the incident and submit an evidence-backed handoff.
- Continue in a successor context, read the handoff, and attempt resolution before verification.
- Confirm
VERIFICATION_REQUIRED, no receipt, and no revision advance. - Run the synthetic checkout verification and retry with the application-issued receipt.
- Confirm revision 3, the committed resolution receipt, seven event-derived workflow beats, and the human audit-view beat.
- Export the proof and reset your visitor-scoped demo record when finished.
.openai/hosting.jsondeclares the existing Sites project linkage and the D1 bindingDB.drizzle/0000_durable_handoff.sqldocuments the state table; the Worker also creates the table defensively when it is first used.npm run buildprepares the artifact but does not deploy it.- A fork needs its own Sites project linkage and should follow the current account-authorized Sites deployment workflow rather than reusing this project's identifier.
After deployment, verify the exact release commit, public access, the DB binding, all five tools,
the reject-verify-resolve flow, browser console, and Worker logs.
This is a focused hackathon prototype, not a production incident-management service:
- It uses one deterministic synthetic checkout incident.
- The verification step does not contact a real checkout system.
- Structural checks, revisions, and hashes do not prove semantic or external-world truth.
- WebMCP callbacks do not authenticate the calling provider or model.
- Each visitor gets an independent D1-backed demo record, keyed by a same-origin session cookie, so one visitor's contexts share state while unrelated visitors do not collide. A caller without that cookie gets a fresh record rather than another visitor's. Local state is lost when the local server restarts.
- The prototype does not implement authentication, tenant isolation, rate limiting, unbounded event retention, production load testing, or a broad browser compatibility matrix.
The project source code and documentation are released under the MIT License. The
generated interface image at assets/arrastra_relay_interface.png is entrant-provided content and
is not covered by that grant. See ASSETS.md for its provenance and rights basis and
for the vendored Phosphor attribution.
AI tools assisted with research, adversarial review, implementation review, and asset generation. All final product decisions, source selection, and verification remained under the entrant's control.
