**Artifact** from Bead: Incident Viewer Taos Engine App · [canonical source](https://redfish.acequia.io/guerin/.agents/cbf8b027-e80c-4b9f-8eb3-91d40af072d5/2026-06-11/artifacts/technote-beads-as-ducktypes.md) · session 2026-06-11 · discussion: Talk: Incident Viewer Taos Engine App
**Status:** proposed pattern, worked from live instances · **Bead:** `#incident-viewer-taos-engine-app` (cbf8b027) · **Date:** 2026-06-12 **Builds on:** [bead-duck-typing (d9dfa5e4)](https://redfish.acequia.io/guerin/.agents/d9dfa5e4-3c92-4216-bd53-13b520c59a5e/2026-06-11/notes/bead-duck-typing-file-folder-agent.md), [uri-bind-mount (874fce5b)](https://redfish.acequia.io/guerin/.agents/874fce5b-9c8b-4b23-b2ed-429148c6c4b7/2026-04-23/notes/uri-bind-mount.md), the camera-tree worked example (31bd5380), `#catalog` (90f902e0).
## Thesis A bead is **one resource whose face is chosen at interaction time**. The original ladder — file (`GET`), folder (`PROPFIND`), agent (`OPTIONS`/negotiation) — extends naturally to *consumer-ecosystem* faces: the same bead URI can answer as an **ESM module**, a **STAC catalog**, an **A2A agent card**, a **GeoJSON feature**, a **thumbnail**. No copies; every face is a binding/projection of one substrate.
## The dispatch problem: how does the server know which face is wanted? Three mechanisms, in order of universality: ### 1. Verb + headers (zero-config tier, browsers only) | Request signature | Face | |---|---| | `GET` + `Sec-Fetch-Dest: document` | human page (`about.md` / HTML) | | `GET` + `Sec-Fetch-Dest: script` (+ `Mode: cors` = ESM; `no-cors` = classic `<script>`) | **module** — must answer `Content-Type: text/javascript` (modules MIME-check strictly) | | `Dest: worker/sharedworker/serviceworker/audioworklet/paintworklet` | module family (worker entries are same-origin-locked) | | `GET` + `Dest: empty` (a `fetch()`) + `Accept` negotiation | `application/json` → machine face | | `PROPFIND` | folder face | | `OPTIONS` | capability advertisement | Caveats: `Accept` cannot distinguish ESM (scripts send `*/*`); **non-browser importers (Node/Deno/Bun/bundlers/curl) send no `Sec-Fetch-*` at all**; and two JSON faces (agent card vs STAC) are header-indistinguishable. ### 2. Bound sibling names (ecosystem conventions) `agent.json` (A2A; echoes `.well-known/agent.json`) · `catalog.json` (STAC's own static-catalog convention — STAC is duck-typed by *shape*: clients just check `{"type":"Catalog","stac_version":…}`) · `about.md` (human). ### 3. Face-paths (the explicit, universal tier — Stephen, 2026-06-12) ``` <bead>/script → ESM module (importable from any runtime) <bead>/stac → STAC catalog.json (browsable in stac-browser, harvestable) <bead>/card → A2A agent card (rosterable) <bead>/geojson → spatial footprint (FeatureCollection; null-geometry for knowledge beads) <bead>/thumbnail → visual identity (the dashboard's GUID-identicon, addressable: <img src=…>) ``` This is the camera-tree pattern (`/latest`, `/stream`, `/params/`, `/capabilities`) applied to the bead itself — Plan 9's `/ctl`+`/data` move. Paths work from `import` statements, `<img>` tags, curl, every runtime: **when a face-path is named, no sniffing; header dispatch remains the fallback for bare-root requests.** Face names are lowercase, reserved in the protocol so they cannot collide with kind-folders.
## What the faces contain (bead → ecosystem mappings) - **Module face:** `export const meta = {…agent-card…}`; named exports resolving note/asset URLs; optionally a default export that is a tiny client for the bead's dock. The bead becomes an importable module *of itself*. - **STAC face:** Catalog (id=GUID, title=slug) → Collections = kind-folders (temporal extent = session dates) → Items = notes/artifacts (null geometry permitted; assets = the files). `rel: parent` ≡ **birth-parent**; `rel: child` chains to any STAC the bead built; the uploads dock is where a Transactions extension lands; `/search` arrives with agent-serving. The note-08 recursion holds: the bead is an *Item* at commons level, a *Catalog* opened. - **Thumbnail face:** every bead already has a derived identicon (#agents-dashboard); the face makes it addressable.
## Operating rules 1. **Faces are bindings, not copies** — projections of one substrate. Static beads serve small *generated* face files (the `build-stac.mjs` pattern); agent-served beads compute them per request. Static is the degenerate agent; the ladder collapses gracefully. 2. **The root advertises its faces** — `OPTIONS`/capabilities + a links block in `agent.json`/`catalog.json` (the geo.camera `supportedCapabilities.json` precedent). Consumers discover, never guess. 3. **Two-tier dispatch:** explicit face-path wins; header sniffing serves bare-root convenience.
## Why it matters One bead, zero duplication, four ecosystems: **browsable** (STAC tooling), **importable** (ESM), **rosterable** (A2A/agent-set UIs), **visible** (dashboards/imgs). The commons stops being markdown-only and becomes a namespace every toolchain can mount natively — which is the uri-bind-mount thesis cashed out at the single-resource scale.
## Next steps `bead-stac.mjs` generator (same walk as `build-stac.mjs`) · `/script` + `/thumbnail` stubs for this bead as the worked example · propose the reserved face vocabulary into `.agents/beads.md` (owner's headgate).
## References (bead cross-links) - 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/)