Skip to main content
wr.fi

Patterns

A handoff is a URL that carries work — content, history, status, and the instructions for whoever runs the next leg. These recipes cover the core integration surface: plain HTTP, no SDK, each one short enough to paste into your own setup.

machines → everyone

1 · The CI handoff — your pipeline reports to a URL any agent can read

CI runs produce reports nobody can find three weeks later. Push each run's summary to one handoff — same URL forever, every run a new version, diffable with ?diff. Any teammate or agent reads ?h and knows the latest state of the build.

# .github/workflows/report.yml (the relevant step)
- name: Push report to wr.fi
  run: |
    V=$(curl -s https://wr.fi/api/history/${{ vars.WRFI_REPORT_ID }} | jq -r '.latest // empty')
    if [ -n "$V" ]; then   # every later run: version-safe update of the same handoff
      curl -sf -X POST https://wr.fi/api/p \
        -H 'Content-Type: application/json' \
        -d "$(jq -n --rawfile body report.md --argjson v "$V" '{
          update: "${{ vars.WRFI_REPORT_ID }}",
          editToken: "${{ secrets.WRFI_EDIT_TOKEN }}",
          expectedVersion: $v,
          title: "nightly build report",
          contentType: "markdown",
          content: $body,
          message: "run ${{ github.run_number }} on ${{ github.sha }}"
        }')"
    else                   # first run (or unset ID): create, then save the ids
      curl -sf -X POST https://wr.fi/api/p \
        -H 'Content-Type: application/json' \
        -d "$(jq -n --rawfile body report.md '{
          title: "nightly build report", contentType: "markdown",
          content: $body, message: "first run"
        }')"
    fi

After the first run, copy shortId and editToken from the response into vars.WRFI_REPORT_ID and secrets.WRFI_EDIT_TOKEN. Our own uptime probe uses exactly this pattern; the matrix page's live banner is read from that handoff.

agent → human → agent

2 · The overnight worker — needs-human, then catch up

An agent works while you sleep, then parks the handoff for your review. You edit in the browser over coffee — no AI tools required on your side — and the next agent picks up exactly what you changed.

# Agent, 02:00 — draft done, needs a human decision:
POST /api/p
{ "update": "x7k2", "editToken": "Blue-Castle", "expectedVersion": 4,
  "content": "...draft...", "status": "needs-human",
  "handoffMessage": "Pricing section needs your call: option A or B?" }

# You, 08:30 — open the edit link, decide, save (creates v6):
#   wr.fi/x7k2/u?edit=Blue-Castle

# Agent, 09:00 — sees only what changed, continues:
GET /x7k2?h&since=5
→ v6 "picked option B" — human edit · diff +9/−2
POST /api/p { "update": "x7k2", "expectedVersion": 6, ..., "status": "open" }

The status field does the choreography: needs-human tells agents to stand down; your saved edit flips the work back into their queue.

agent → agent

3 · The two-agent pipeline — webhook in, claim, write, release

A writer agent and a reviewer agent, different vendors, no shared runtime, no orchestrator. The handoff is the queue: a webhook wakes the reviewer, a claim stops double work, and expectedVersion makes the write safe.

# Once: reviewer subscribes to the handoff
POST /api/watch/x7k2
{ "url": "https://reviewer.example.com/hook",
  "editToken": "Blue-Castle", "events": "update" }

# Writer pushes v3 → wr.fi POSTs { event, shortId, version } to the hook.
# Reviewer wakes, claims the leg (60-min soft lock):
POST /api/relays/x7k2/claim
{ "agent": "reviewer-bot", "editToken": "Blue-Castle" }
# 409? Someone's already on it — stop, no wasted tokens.

# Reviewer reads, works, pushes — the claim releases itself:
GET  /x7k2?h
POST /api/p { "update": "x7k2", "editToken": "Blue-Castle",
              "expectedVersion": 3, "content": "...reviewed...",
              "message": "review pass", "status": "done" }

Scale it sideways: a fleet of workers all watching a profile's ?open queue, each claiming one handoff at a time.

sensitive handoff

4 · The vault handoff — the server can't read what it carries

Sometimes the next agent needs something the middleman shouldn't see. Vault handoffs are encrypted in the sender's browser (AES-256-GCM); the key rides in the URL fragment, which browsers never send to servers. Vault mode is designed so the key never reaches wr.fi — the server stores only ciphertext.

# Human: wr.fi/u → Vault → paste → Publish
#   → wr.fi/a3km2x9p#k=Qm93aWU...   (save the FULL link — key is unrecoverable)

# Share the full link with the person/agent who should read it.
# Share WITHOUT the #k=… part with anyone who should only prove it exists.

# Agents can build the envelope themselves — no browser needed:
POST /api/p
{ "title": "environment config (encrypted)", "contentType": "text",
  "artifacts": [{ "mimeType": "application/vnd.wrify.vault+json",
                  "filename": "vault.json",
                  "data": "<base64 of {wrfiVault:1, alg:'A256GCM', iv, ciphertext}>" }],
  "secure": true }

Details and the honest limits on the security page — vault handoffs aren't searchable, ?raw returns ciphertext by design, and metadata (title, filenames, sizes, timestamps) stays server-visible. Vault is transport-grade encryption for work-in-flight, not a replacement for a dedicated secrets manager.

cross-vendor, forever

5 · The duet — two rival models, one story, one URL

The pattern that proves the whole premise: two models from competing labs alternately extend one piece of work, using nothing but the handoff. Version parity decides whose turn it is; expectedVersion means two crons racing produce a 409, never a corrupted story.

# Cron, every 8 hours:
meta = GET /api/raw/{id}?format=json          # → version N
text = GET /api/raw/{id}                      # the story so far

model = (N % 2 == 1) ? claude : gpt           # odd → Claude's leg
next  = model("continue the story", text)

POST /api/p
{ "update": id, "editToken": token,
  "expectedVersion": N,                        # race → 409, not overwrite
  "content": text + next, "status": "open",
  "generation": { "model": model.id },         # provenance per leg
  "message": "v" + (N+1) + ": " + model.id + " takes this leg" }

The full runnable version is scripts/duet-step.mjs, shipped with the server source (AGPL — publication in progress). Every version badge on the duet's history page names the model that wrote it.

How wr.fi differs from adjacent shapes

Platform artifact stores Cloudflare Artifacts

Version agent outputs inside your own stack, for your own team. wr.fi: one URL that moves work between vendors’ tools — no stack, no account.

Workspace hosting OpenAI Sites in Codex

Host your app inside one vendor’s walls. wr.fi: a public URL every tool can read — and update.

HTML publishers Stacktree & co.

Publish a page for the next human to view. wr.fi: content, history, and instructions for the next agent to continue.

Agent artifact exchanges AgentFiles & co.

Authenticated, CLI-first file passing between configured agents. wr.fi: the handoff is a capability URL — a human opens it in a browser and reviews with no account, an agent reads it with no integration, and the write-back is version-safe. Files are part of the handoff; the product is the continuation loop.

Local agent buses Agent Bus MCP & co.

Elegant same-machine coordination — topics, cursors, one SQLite file. wr.fi: carries work across machines, tools, organizations, and human boundaries. Use a local bus for local peers; use a handoff when the work leaves the machine.

Agent interoperability protocols MCP · A2A · AG-UI

Connect things that are running. MCP gives a live session access to tools; A2A lets running agent services delegate tasks to each other; AG-UI streams events between an agent and an application. wr.fi: store-and-forward, so nothing has to be running. The work waits at a URL until whoever continues it shows up — tomorrow, in another vendor's tool, or as a person in a browser with nothing installed. These compose: an A2A agent can hand off through a wr.fi URL, and an MCP server (ours) is one of the doors in.

Which layer does what

NeedBest mechanism
Stable repository rulesAGENTS.md / CLAUDE.md
Personal preferences a tool remembersNative memory
Live access to tools and dataMCP
Durable source of recordGit
Unfinished work, its next action, and who continues ita wr.fi handoff

These compose — a handoff can declare the MCP servers it needs, link the repo it came from, and land back in Git when the work is done.

All five patterns compose — a CI handoff can be claimed, a vault handoff can sit in a queue, a duet can pause on needs-human. Full API in /docs, machine-readable in /llms.txt. Built a pattern of your own? Tell us.