**Note** from Bead: Agentify Bead · [canonical source](https://redfish.acequia.io/guerin/.agents/d9dfa5e4-3c92-4216-bd53-13b520c59a5e/2026-06-11/notes/binding-handles-in-idb.md) · session 2026-06-11 · discussion: Talk: Agentify Bead
> Stephen, 2026-06-11 (verbatim): "what would be an equivalen handle an agent bead could put in > indexed db that says it's handling it. this could even be an imported bead that's remote" > > Generalizes [fsa-handles-in-sw-no-tab-needed.md](fsa-handles-in-sw-no-tab-needed.md): the FSA > handle is one instance of a broader primitive — a **serializable, durable, permission-gated > capability record** a headless runtime picks up at wake. The bead version binds a URI pattern to > a handler instead of a directory to a page.
## The FSA handle, abstracted | FSA handle property | Bead binding-handle equivalent | |---|---| | opaque capability object, not a name | signed binding record: pattern → bead → handler | | structured-cloneable, parked in IDB | JSON record in IDB (the SW's wake-time route table) | | granted ONCE by the owner (user gesture) | minted ONCE by the parciante (signing key in a page/dashboard context) | | used silently many times by the SW | evaluated at every SW wake, no page needed | | `queryPermission()` checked per use | verify at wake: lease unexpired + chain token valid + integrity hash matches | | `requestPermission()` is page-only (SecurityError in SW) | re-minting needs the user signing key — dashboard-only; the SW can check, never ask. **Same asymmetry, same reason** | | revocation / session expiry | token revocation + lease TTL = the apoptotic signals |
## The record (sketch) ```json { "profile": "acequia/binding-handle@1", "pattern": "https://acme.com/photos/*", "bead": "https://redfish.acequia.io/guerin/.agents/<guid>/agent.json", "handler": { "module": "https://…/<guid>/handler.mjs", "integrity": "sha256-…" }, "lane": ["sync", "dock"], "capability": "<chain-token leaf JWT — scope.paths/writePaths cover pattern>", "lease": { "expiresAt": "…", "renewAt": "…" }, "issuer": "kid:<parciante thumbprint>", "sig": "<PS256 over the record>" } ``` - **`sig` makes the claim relational, not self-asserted** — the SW honors only records signed by a key it trusts ([sovereignty is in the relation](https://redfish.acequia.io/guerin/.agents/1ca761b0-cb21-4bd7-be94-12dcc5824851/about.md)). A bead cannot grant itself a route; the parciante's signature is the grant. (FSA parallel: the *browser* holds the grant state, not the page.) - **`capability` is the chain token** — the handler acts under a scoped PS256 JWT whose `paths`/`writePaths` cover exactly the pattern. Authority travels WITH the binding. - **`lease`** — stale claims apoptose. This is the discovery-server reaper made local: an un-renewed binding handle stops matching, and the route falls down the liveness ladder.
## Imported vs mounted — the flag lands here The `handler` field is the fork: - **Imported (remote bead, local execution):** `{ "module": "<remote handler.mjs>", "integrity": "sha256-…" }` — the SW imports the bead's handler code *from its canonical URI* and runs it locally, under the local user's ambient authority bounded by the record's chain token. The integrity hash pinned at mint time is the trust gate (handler note §8 Q2): the remote bead can't silently swap code after the grant. **The bead is remote; the handling is local.** - **Mounted (remote bead, remote execution):** `{ "proxy": "<bead uploads/ or animator URI>" }` — the SW forwards (sync proxy or dock-PUT 202); the remote bead computes under its own authority. Same record shape, one field different — exactly the mounted-vs-imported distinction flagged in [bead-step-and-step-complete.md](bead-step-and-step-complete.md), now concrete.
## IDB is the cache, the namespace is the truth IDB is per-profile and OUTSIDE the namespace — same flaw class as `~/.claude` memory (project_distributed-origin-architecture). So the binding handle's **source of truth is a namespace resource** (the bead's `acequia.json` ingress rules / a `bindings/` folder under the granting parciante); the IDB record is the **materialized, wake-reachable copy** the SW syncs in. Re-provisioning a new browser profile = re-syncing bindings from the namespace + one page visit to re-grant FSA where real-dir mounts are involved.
## Wake-time check (the queryPermission analogue, in order) 1. record present in IDB and `pattern` matches the request; 2. `sig` verifies against a trusted issuer key; 3. `lease.expiresAt` in the future; 4. `capability` token valid (TTL, scope covers the path, not revoked); 5. if imported: module fetch matches `integrity`. Any failure → degrade honestly (proxy → dock 202 → named cache → network) and queue the binding for page/dashboard re-grant. Failure is a downgrade, never an error.
## Requirements & assurance: acequia.js provisions the body the bead demands > Stephen, 2026-06-11 (verbatim): "the service worker can also persist all types of data through > FSA. in fact, acequia.js may want to assure SW has FSA if required. the service worker could be > getting that requirement from a bead that is actually the main handler for the SW" Three escalating points: **1. FSA is the SW's general persistence, not just a serving mount.** With a granted `readwrite` directory handle, the SW can persist *anything* to real disk: dock deposits, named-cache write-through, delta tiles, git objects, baked artifacts, `step-complete` ticks. Unlike IDB/Cache-Storage this is **outside browser quota eviction, user-visible, and — decisive — shared with OS processes.** A SW persisting into the local `sites/` tree writes the SAME files the CV animator and webdav-sync read: **the real directory is where the browser body and the OS body meet.** The browser stops being a storage island and becomes a full peer of the local origin. **2. `acequia.js` runs the assurance loop.** Granting is page-only (the asymmetry above), so the page library owns provisioning. On page load, for each binding handle: read its `requires` → check satisfaction (`queryPermission()` on the stored handle, `navigator.storage.persist()`, push subscription, …) → if unmet, queue a one-gesture grant UX → store the handle → notify the SW. The SW *checks* requirements at wake and degrades when unmet; `acequia.js` *repairs* them when a page is open. Check-headless / repair-on-page is the standing division of labor. **3. The requirement comes from the bead — the SW's main handler.** The SW itself is a minimal kernel (match bindings, verify, dispatch). Its behavior, routes, and **requirements** come from a bead bound as the SW's *main handler* — the default binding that owns everything not otherwise matched. That bead's `agent.json` declares what its body must provide: ```json { "requires": { "fsa": { "mode": "readwrite", "root": "sites/" }, "persist": true, "push": false } } ``` This is the bead-root-files-ARE-the-agent-config pattern ([handler note §5](https://redfish.acequia.io/guerin/.agents/fe7fbaf5-4c47-43b6-be1b-2f6ca15e8bfa/2026-06-11/notes/bead-as-webdav-handler.md)) applied to the browser runtime: the animator loads `agent.md` as its system prompt; **the SW loads its main-handler bead's `handler.mjs` + `requires` as its kernel config.** Same bead, two bodies, each assured differently. Requirements flow: bead (mind) → SW (body, checks) → acequia.js (provisioner, repairs) → user (one gesture).
## Naming (candidate, Stephen's call) The NM-acequia term **saca** (an allotted turn to draw water) fits: a binding handle is a signed, scoped, expiring *turn to serve a path*. Not bound here — flagging the candidate only.
## Related - The instance this generalizes: [fsa-handles-in-sw-no-tab-needed.md](fsa-handles-in-sw-no-tab-needed.md) - Route table it feeds: [browserdav-discovery-ingress.md](browserdav-discovery-ingress.md) (SW route-holder; `registerRoutes` is the mesh-level twin of this record) - Handler contract + trust gate: [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) §7–8 - Chain tokens: [generate-acequia-access-token skill](https://acequia.org/skills/generate-acequia-access-token.md)
## References (bead cross-links) - Bead: Sovereign Webdav · [canonical](https://redfish.acequia.io/guerin/.agents/1ca761b0-cb21-4bd7-be94-12dcc5824851/) - Bead: As Webdav Handler · [canonical](https://redfish.acequia.io/guerin/.agents/fe7fbaf5-4c47-43b6-be1b-2f6ca15e8bfa/)