bead-remote — the remote-control face of a bead (Remote)

**Note** from Bead: Remote · [canonical source](https://redfish.acequia.io/guerin/.agents/792ebed9-c03a-4ed0-82fb-da4d19a1a5f5/2026-06-17/notes/00-bead-remote.md) · session 2026-06-17 · discussion: Talk: Remote

**Date:** 2026-06-17 **Status:** Design draft — staged in this bead's URI-space, open questions await Stephen (§7). **Hatched from:** a Claude Code session-picker question — "what is a *Web* session, how do I start a *Web* chat?" (Local vs Web tabs; *Interactive* = cloud, *Remote Control* = local session steered from the network). Stephen's pivot: *don't* reach for Anthropic's hosted Remote Control — **let a bead be its own remote-controllable agent.** This note is the self-sovereign generalization of "Remote Control session." **Mounts:** handler bead-as-webdav-handler (`fe7fbaf5`) · live-runtime/router hubler-router-bead (`82bd6fa4`) · bead-orchestrator (`4c6470f9`) · relates decentralized-cache-management (`4456cd24`).

## 1. The frame: a third session that isn't Anthropic's Claude Code's session picker offers **Local** (runs here) and **Web** → *Interactive* (cloud-hosted) or *Remote Control* (this machine, steered from `claude.ai/code` or the phone). Stephen's other choice: > chats running beads, whose `step` listens to an update directory. That is a **remote-controllable agent we already own** — the local bead-runtime (e.g. `stephenguerin.live`'s `server.js`, bead `82bd6fa4`, with the ICS Liaison-Officer as its cognition client). It needs no Anthropic-hosted control plane: the **namespace is the control plane.** A networked human or agent steers the bead by writing into a path; the bead's loop reads that path and acts. "Remote control" = *someone other than the local terminal puts work on a path the bead is watching.* This note adds one concrete surface to make that real: the **`request/` dock.**

## 2. `request/` — a live-request ingress, sibling to `uploads/` Beads already have `uploads/` — the **afferent provenance dock**: immutable, store-and-forward, "hey-you-it's-me" deposits, treated with the same discipline as `chats/` (you don't edit it). It is *correspondence*, not *control*. Proposal: **add a `request/` directory to beads** as a distinct lane — the **remote-control / live-request ingress**: | Dock | Pairs with | Semantics | Mutability | Lane | Analogy | |---|---|---|---|---|---| | `inbox/` ⇄ `uploads/` | — | **receive** — things handed *to* the bead | immutable | async / store-and-forward | inbox / drop-box | | `request/` | `response/` | **HTTP request → response** & `ask` — query/do, expects a reply | ephemeral (req+resp, then reapable) | sync when bound, async when not | HTTP, RPC, control socket | > **Bound 2026-06-17 (Stephen):** > - **`inbox/` and `uploads/` are two facets of the receive dock, not rivals — support both.** `inbox/` is the *active* facet ("I receive and act on this") and reads better; `uploads/` is the *passive* facet ("raw files staged for later management"). Same receiving resource, two names/views — the duck-typing / project_uri-bind-mount principle applied to the dock: a caller can address it as either, and content-negotiation/binding decides which face it sees. *(Don't pick one and delete the other; bind both names to the one dock.)* > - **`request/` affords `response/`.** The pair is the unit, and **the primary use is HTTP request/response** — not a side feature. A request at `request/<id>` is answered at `response/<id>` (or in-band on the sync lane). This is the literal HTTP verb pair made into two folders. > - `/request` is real; the on-the-wire API is in **early flux** — v0 in [request/README.md](https://redfish.acequia.io/guerin/.agents/792ebed9-c03a-4ed0-82fb-da4d19a1a5f5/request/README.md). The split is the same one `fe7fbaf5` §2 draws between the **dock** (receive) and the **handler lanes** (compute) — here it's physical: `request/`→`response/` is *visibly* an RPC pair, distinct from the `inbox/`⇄`uploads/` receive dock. A request/response pair is **garbage-collectible** (apoptotic); inbox/uploads deposits are immutable fossils.

## 3. Two ways a request lands — the binding ladder The point Stephen made: a request *can get there as a file*, **or** the bead can *bind to* `request/` live. Same surface, three liveness levels — exactly `fe7fbaf5` §3's ladder applied to one folder: | Rung | How `request/` is served | Who watches it | Reply latency | |---|---|---|---| | **0 — static folder** | a plain WebDAV dir; requests are `PUT` files | the chat/animator's `step` **polls** it as its *update directory* | next tick (`202 Accepted` + `Location`) | | **1 — browser-bound** | **acequia.js + service worker** intercept the path; **browserdav** serves it from Cache-API/OPFS | the SW `fetch` handler, in the user's session | in-band, sync — never hits the network if local | | **2 — node-bound** | **node.js acequia** (the `server.js`/`uploads-server.mjs` lineage) owns the origin | the animator daemon's watcher | sync when the lease-holder is online | "Bind to it with acequia.js and service workers (browserdav), or node.js acequia" = rungs 1 and 2. The folder is the **degenerate, always-valid** form (rung 0): even with no live process, a request is store-and-forward and gets a `202`. Binding just raises the liveness — **the request protocol (PUT a request, read a reply) is identical at every rung**, which is what makes a bead remotely controllable from anywhere without the caller knowing which rung answered.

## 4. The step loop: a chat that runs a bead by watching `request/` > **BUILT 2026-06-17 (rung 0, run green).** This loop is real code now: > - dock client **[`webdav-bead.mjs`](https://redfish.acequia.io/guerin/.agents/fe7fbaf5-4c47-43b6-be1b-2f6ca15e8bfa/2026-06-17/skills/webdav-bead/webdav-bead.mjs)** in bead `fe7fbaf5` (a `Bead` over a pluggable fs/WebDAV transport — "webdav-bead" *is* that bead; this is the module the `webdav-publish.mjs` shim stood in for, finally written). > - watcher **[`skills/request-watcher/`](https://redfish.acequia.io/guerin/.agents/792ebed9-c03a-4ed0-82fb-da4d19a1a5f5/2026-06-17/skills/request-watcher/SKILL.md)** here, which **imports** it and drives `request/`→`response/`. > - verified: `ping→pong`, `echo→"hello bead-remote"`, `ask→deferred` (honest — no brain at rung 0), re-run idempotent. The reply file is `response/<id>.json` (the `.reply.md` sketch below is superseded by the `request/`→`response/` pair). "chats running beads and their step is listening to the update directory" — concretely: ``` loop (the bead's step / sensorimotor tick): afferent # ← PROPFIND request/ (and uploads/) for new entries for each new request: read it (+ names.json to resolve refs) compute (cognition ladder: rung 0 deterministic → 1 local LLM → 3 BYOK cloud) efferent @ → PUT request/<id>.reply.md (or to the handed Location) ack: mark the request done (sidecar/state.json); reap when consumed apoptosis: no inbound requests → no ticks → decay to static face (correct quiescence) ``` This is the **async lane of `fe7fbaf5` promoted to the bead's main loop.** Each new file in `request/` is one `user` turn. The watcher can be: a Claude Code chat polling the dir (rung 0/3 today, by hand), a node animator (rung 2), or an SW (rung 1). `request/` *is* the message queue; **paths-as-event-bus is the RPC.**

## 5. The UI faces — to humans and to other agents A remote-controllable bead must present an interface to *whoever* is steering. Two callers, two faces, one `request/`: **To humans — an HTML control surface.** The bead's `README`/index can render an **interactive panel** (ambient-auth, browser-side) that PUTs into `request/` and live-renders replies — the same shape as the ai-team `project.json` dashboard (project_agent-coordination-pattern), generalized to "control any bead." This *is* a Remote-Control session, but bead-native and self-hosted: open the bead's URL on a phone, type, the local bead answers. Two builds: - **bead-ships-its-own** control HTML (bespoke per bead), or - a **generic bead-console** app that renders *any* bead's control surface from its `agent.json` + `request/` schema (one app, every bead). *(Q5.)* **To other agents — the A2A machine face.** `agent.json` (the Agent Card) + `OPTIONS <bead>/` capability negotiation declares the verb/request surface; a peer agent discovers it and deposits a **structured** request into `request/` (or POSTs it on the sync lane if a lease-holder is up). This is `world.ask(bead, …)` from the orchestrator side (bead-orchestrator drives `world.ask`), and the `ask`/caller-backref machinery in `82bd6fa4`'s notes 05–06 is exactly the reply-addressing for it. Both faces are **content-negotiated views of the same control resource** (`Accept: text/html` → human panel; `application/json` → A2A surface), per the duck-typing rule.

## 6. What this is *not* re-inventing - It is **not** a new transport — it's WebDAV verbs on a path, like every other corridor. - It is **not** a competitor to Anthropic's Remote Control session — it's the **analogy taken literally**: where Claude Code's Remote Control needs Anthropic's control plane, a bead's `request/` makes the **namespace** the control plane (self-sovereign, mesh-served, offline-tolerant). They can also *compose*: a Claude Code Remote-Control session could itself be the rung-3 animator watching a bead's `request/`. - It is **not** a security regression — credential placement is unchanged (`fe7fbaf5` §4–5): the **caller's** authority steers, the bead writes only within its subtree + foreign docks, and the web-reachable cognition credential is **BYOK API key, never a subscription** (the §5 invariant — a remote-controlled bead serving the web must obey it).

## 7. Open questions (Stephen's bindings) 1. ~~**`request/` vs `uploads/`.**~~ **BOUND 2026-06-17:** true root sibling. `request/` = HTTP requests & `ask` (wants a reply); `uploads/` = raw file staging for later management. Different kinds, two folders. 2. **Universality.** On **all** beads (even static/dead ones, as the honest "I'll store-and-forward" promise) or only agent-face beads? *(open)* 3. ~~**Naming.**~~ **BOUND 2026-06-17:** `request/`. ("update directory" was shorthand, not formal vocabulary.) `uploads/` keeps its name as the file-staging dock. 4. **Sync semantics** *(open — Stephen to decide).* When a handler is bound (rung 1–2), is an `ask` answered **in-band** (`POST`/`200`, blocks for the answer) or **always** as a separate reply resource (`202 + Location`, caller polls)? Proposed reconciliation: **HTTP method picks the lane** — `POST request/` = try-sync (200 if live, else 202), `PUT request/<id>.req.json` = always-async deposit; same reply resource either way. (The "ingress purism" tension from `fe7fbaf5` §8.1.) 5. **UI: bespoke vs generic.** Does each bead ship control HTML, or does one **generic bead-console** render any bead from `agent.json` + a request schema? *(open)* 6. **Reaping.** `request/` entries are ephemeral (unlike immutable `uploads/`). Who garbage-collects request/reply pairs, and when — on read-receipt, TTL, or never (keep as trace for the desire-path ledger)? *(open)* 7. **Who runs the watch loop** *(de-jargoned from "rung-3 animator").* The thing that reads `request/`, thinks, and writes the reply can be: (a) a deterministic script — **built, rung-0, see `skills/request-watcher/`**; (b) a local model; (c) **a Claude Code session left running, pointed at the folder** (the "chats running beads" idea); (d) a node daemon holding a BYOK key. Open: is (c) a first-class answerer, or just a dev-time stand-in for (d)?

## Related - Handler lanes / liveness ladder / credential rules this builds on: [bead-as-webdav-handler.md](https://redfish.acequia.io/guerin/.agents/fe7fbaf5-4c47-43b6-be1b-2f6ca15e8bfa/2026-06-11/notes/bead-as-webdav-handler.md) - The live remote-interaction runtime (server.js + Liaison Officer): [82bd6fa4 router-bead](https://redfish.acequia.io/guerin/.agents/82bd6fa4-4d5a-435b-9deb-ca930a82aa89/about.md) · `ask`/caller-backref: notes 05–06 - Human control-surface prior art: [ai-team dashboard](https://simtable.acequia.io/dev/ai-team/) (project_agent-coordination-pattern) - Three faces / content-negotiated control resource: [bead-duck-typing-file-folder-agent.md](https://redfish.acequia.io/guerin/.agents/d9dfa5e4-3c92-4216-bd53-13b520c59a5e/2026-06-11/notes/bead-duck-typing-file-folder-agent.md) - Paths-as-event-bus (the RPC substrate): [paths-as-event-bus.md](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/paths-as-event-bus.md)

## References (bead cross-links) - Bead: As Webdav Handler · [canonical](https://redfish.acequia.io/guerin/.agents/fe7fbaf5-4c47-43b6-be1b-2f6ca15e8bfa/) - Bead: Stephenguerin.live Router Bead · [canonical](https://redfish.acequia.io/guerin/.agents/82bd6fa4-4d5a-435b-9deb-ca930a82aa89/) - Bead: Agentify Bead · [canonical](https://redfish.acequia.io/guerin/.agents/d9dfa5e4-3c92-4216-bd53-13b520c59a5e/) - Bead: 874fce5b · [canonical](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/)