**Note** from Bead: Stephenguerin.live Router Bead · [canonical source](https://redfish.acequia.io/guerin/.agents/82bd6fa4-4d5a-435b-9deb-ca930a82aa89/2026-06-13/notes/04-node-connection-and-identity.md) · session 2026-06-13 · discussion: Talk: Stephenguerin.live Router Bead
**Date:** 2026-06-13. From Stephen (verbatim seeds): > all modules will have access to requester session object and agent-id {person-GUID, bead-GUID, etc} > agents.md / singleton.set acequia.mjs / connect (localhost, your mayordomo.your-domain) > Kotlin coupled webview-node.js will have acequia.js too. probably web-socket. This note covers the **node/runtime** layer beneath the per-bead modules: how a runtime boots its identity + credential singleton and wires its connections. (Per-bead module taxonomy is in [03-module-types.md](03-module-types.md); the credential rule is [EULA-compliance](https://redfish.acequia.io/skills/EULA-compliance.md).)
## 1. Identity is ambient — session + agent-id in every `ctx` See [03 §Cross-cutting](03-module-types.md): every module receives `ctx.session` and `ctx.agentId = {person, bead, device?, …}`. The agent-id is a **tuple of GUIDs**, not one opaque token — it names *who* (person-GUID), *as which bead* (bead-GUID), and optionally *from which device*. This is the "it's me" of [hey-you-its-me](https://redfish.acequia.io/skills/webdav-context/SKILL.md) promoted from a per-message envelope to a standing `ctx` field, so authorization (`guard`), personalization (`dashboard`), attribution (`ledger`), and scoping (`cache-sync`) all read the same identity. Beside `ctx.agentId` (who is calling) `ctx` also carries `ctx.caller` — the **`"myself"` back-reference** to the caller (`{agentId, dock, replyTo}`): not just the identity tuple but a *live handle to reach back*. `agentId` = **who**; `caller` = **how to speak back**. See [06-ask-and-the-caller-backref.md](06-ask-and-the-caller-backref.md) (`ask bead-guid("prompt")` as the call projection of hey-you-its-me; the reverse edge that makes request-response into conversation and carries the advanced wave home). > **Concrete instance (2026-06-13):** the CV node that authored this bead is named **`my-claude-vscode`** > (Stephen). That string is the human alias for this node's **`device`-GUID** — it resolves via > `agents.md`/`names.json` and rides `ctx.agentId.device`. A worked grounding of the abstract tuple: a > real node, with a real name, identifying itself in the chain.
## 2. `agents.md` — the node's connection/roster config Where `agent.md` is the operative self of one **bead**, **`agents.md`** is the operative config of the **node/animator** — the runtime that hosts beads. It declares the runtime's singletons and connections (a small, human-readable bootstrap; `agents.json` would be its machine twin). Two things it sets: ### 2a. `singleton.set acequia.mjs` — one credential custodian per runtime `acequia.mjs` (the ESM credential-custody client; `acequia.js` is the same in a `<script>` runtime) is registered as a **singleton**: exactly one instance per runtime owns auth + key custody, and every module/bead binds to *that* instance rather than constructing its own. It holds: - the **namespace plane** — chain-token minting (`createChainToken`), ambient auth, scoped `writePaths`; - the **cognition plane** — the BYOK keystore (capability objects, never key strings). "singleton" is the same concern `dashboard.mjs` confirms on a full page (one service worker, one `acequia`): rival custodians would fork identity and credentials. `agents.md` makes it explicit at the node level: `singleton.set(acequia)`. ### 2b. `connect(localhost, your mayordomo.your-domain)` — inward + outward A runtime opens (at least) two connections: - **`connect(localhost)`** — inward to the local animator/runtime (the in-box services: the bead server, the cognition client, `sensor-domo`, `cache-sync`). The CV/Node side of the node. - **`connect(your mayordomo.your-domain)`** — outward to the parciante's **mayordomo**, the coordination agent over the shared commons at the user's own domain. The mayordomo is where cross-bead coordination, leases, and the advanced-wave ledger live; the node registers with it and receives dispatch. So a node is *dual-homed*: local runtime + remote mayordomo. (More connections — peers in the distributed-origin mesh — are the same `connect()` shape.)
## 3. Transport — probably WebSocket The connections in §2b are **persistent duplex links — probably WebSocket**, the same inward-client pattern already running here: [`server.js`](../artifacts/server.js) is a WS server and the cognition client connects to it as a client. Generalized: `connect(target)` opens a WS to `localhost` (the local node) and to `mayordomo.your-domain` (the remote coordinator); identity (`ctx.agentId`) is established at connection time and rides every framed message. WebSocket fits because the links are long-lived, bidirectional, and identity-bound — not request/response.
## 4. Runtimes that carry `acequia` — the parciante-node set Any runtime that loads the `acequia` singleton is a **first-class parciante node** (per feedback_browser-is-a-parciante-node): credential placement is scope × blast-radius, uniform across runtimes. The set now includes: | Runtime | UI face | Animator | `acequia` | |---|---|---|---| | **Browser** (CE/CB) | DOM + `dashboard.mjs` | service worker (singleton) | `acequia.js` | | **CV / Node** | (headless) | `server.js` animator | `acequia.mjs` | | **Kotlin-coupled WebView + node.js** (mobile) | WebView (`dashboard.mjs`) | embedded **node.js** | `acequia.js` | The **Kotlin + WebView + node** runtime is the mobile parciante node: a Kotlin host couples a **WebView** (the human view-controller — `dashboard.mjs`) to an **embedded node.js** (the animator — `server.js`, `sensor-domo`, `cache-sync`). It carries `acequia.js` like any other node. The **WebView ↔ node coupling is probably WebSocket too** — the same transport as §3, so the in-app UI talks to the in-app animator over the identical framed, identity-bound channel it would use to reach `localhost` or the mayordomo. This makes "browser is a parciante node" generalize cleanly to mobile: the phone is a node with sensors (`sensor-domo` over the device APIs), a UI (`dashboard`), an animator (node), and credentials (`acequia`), connected to its mayordomo over WebSocket.
## 5. Mounting chains identity *(Stephen, 2026-06-13: "a domain can mount a bead which chains its identities")* A domain can **mount** a bead — bind the bead's subtree into the domain's namespace ([uri-bind-mount](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/uri-bind-mount.md), Plan-9 mount; the [`mount.mjs`](03-module-types.md) half of `start-bead <url>`). The claim here: **mounting is not only a namespace bind — it chains identity.** ### One act, two faces `mount(domain, bead)` simultaneously: 1. **composes namespace** — the bead now answers under the domain's URI; and 2. **chains identity/authority** — the mounted bead operates under a **delegation chain rooted at the domain**, which itself roots at the person's signing key. This is exactly the chain-token model (`acequia.chains`: `root user-signed → leaf → sub-leaf`, each segment **attenuated** ⊆ parent scope, the whole chain **cascade-revocable** — kill the domain's grant and every bead mounted under it apoptoses). Namespace mount and auth delegation are the **same operation** — the [downstream-pattern](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/downstream-pattern.md) claim made concrete: a binding is at once devops + governance + ACL + attribution + ledger. ### `ctx.agentId` IS the materialized chain The agent-id tuple from §1 is not a flat record — it is the **mount chain read out**: ``` person-GUID (root — the signing key / the domain owner) └─ bead-GUID (the mounted bead, leaf under the domain) └─ device-GUID (the runtime/node the request entered through) ``` Each mount link adds a chain segment; resolving `ctx.agentId` walks the mount path the request arrived by. So identity is **per-mount**: the *same* bead mounted under two domains has **two identity chains** (two effective identities, two scopes, two attribution trails) — Plan-9 per-process namespace applied to identity, not just to paths. `guard.mjs` authorizes along the chain (a request can do only what *every* link permits); `ledger.mjs` attributes up the chain; revocation anywhere on the chain cascades down. ### Why this matters - **Self-sovereign delegation without a central registry.** A domain lends authority by mounting; it revokes by unmounting (the apoptotic cascade). No global ACL table — the mount graph *is* the ACL. - **Attribution follows the mount, not the bytes.** Who a bead "is" depends on whose namespace mounted it — the advanced-wave debt flows up the chain to the mounting domain. - **Composability.** Chains nest: a domain mounts a bead that mounts another; authority only ever narrows downward (attenuation), and identity is the full path from root.
## Open questions for Stephen - `agents.md` exact schema (singletons, connect list, identity source) — sketch above; needs binding. - Is the WebView↔node link literally WebSocket, or a native bridge that *presents* as one (`connect()` is transport-abstract)? - Where does `ctx.agentId` get *authenticated* — `acequia` verifies the chain token and emits the tuple?
## References (bead cross-links) - Bead: 874fce5b · [canonical](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/)