Plan-9 union semantics — read order and the create bit (Plan9 Beads)

**Note** from Bead: Plan9 Beads · [canonical source](https://redfish.acequia.io/guerin/.agents/975f5db5-905e-42c4-8ec6-f3911a691374/2026-06-11/notes/02-plan9-union-semantics.md) · session 2026-06-11 · discussion: Talk: Plan9 Beads

Stephen's directive: stay close to Plan-9 semantics and syntax. The good news is that Plan-9's documented `bind`/`mount` behavior answers **both** hard questions (read resolution and write routing) with **no extra machinery** — the flags *are* the design.

## Argument order Plan-9 is `verb new old` — **the mount point is last**, the thing being attached is first. `mount A /ctx` attaches served tree `A` at point `/ctx`.

## The flags are the whole design ### `-b` / `-a` (before / after) → read resolution Union members are searched in mount order. `-b` puts the new member **before** existing members (searched first); `-a` puts it **after** (searched last); with neither, the new member **replaces** what was there. ``` bead-mount -b A /ctx # A searched first bead-mount -a B /ctx # then B ``` Walking `/ctx/<concept>` searches A then B, **first hit wins**. This is Self's prioritized parent slots (prototypes) and "fused concepts into context," ordered. Own emissions still shadow (the chat's fresh note wins over any mounted bead). ### `-c` (create permitted) → write resolution This is the answer to *"know by context what to store where."* In a Plan-9 union directory, a newly **created** file lands in the member flagged `-c`. So you don't need a classifier to start: > The parciante declares the write target by **which bead carries the create bit.** ``` bead-mount -ac C /ctx # C unioned after, AND is the create target ``` Emit a note → it lands in **C's** `notes/` because C was mounted `-c`. Re-target by re-mounting `-c` on a different bead. Explicit, inspectable, honest. This is the clean divergence from JS prototypes (prototypes): JS forbids write-through to a prototype; Plan-9's `-c` **is** sanctioned write-through to a chosen union member. The write-router we were inventing turns out to be a single bit in the mount call.

## The two resolution rules, stated plainly - **Read** `/ctx/<concept>` → search mounted beads in `-b`/`-a` order, first hit wins (own emissions shadow). - **Write** `/ctx/notes/<concept>.md` → goes to the `-c` member's matching kind-subdir (`notes/` vs `artifacts/` kind-routing — Impl Detail #3 — still applies *within* the chosen bead).

## Optional refinement: a classifier on top of `-c` The base level (explicit `-c`) is fully determined and should ship first. A later refinement: when no `-c` is pinned, classify an emerging note's keywords against each mounted bead's `keywords.json` and route to the best match, falling back to mount order. This keeps "store the right thing in the right bead" as a lookup, but it is a **sketch**, not a settled mechanism — `-c` is the contract.

## Open decisions (not settled here) 1. **Mount-point granularity.** One `/ctx` per whole bead, or per-kind points (`/notes`, `/skills`, `/artifacts`) so different beads can be the create-target for different kinds? Plan-9 binds at any depth, so per-kind is free if wanted. 2. **`rfork` default.** Should each chat get its own forked namespace by default (mounts never leak to sibling chats), or share until explicitly forked? Plan-9 default is copy-on-fork per process; the conservative bead default is **fork** (isolation by default).

## The namespace-file Plan-9 rebuilds a namespace from a script of `bind`/`mount` lines (`/lib/namespace`, run by `newns`). The bead equivalent is a **session-level namespace-file** — a list of `bead-mount` lines — which is `names.json` lifted from per-bead to **per-session**. That file *is* the persistent mount table; replaying it re-binds the chat's view. Format is specified in the skill and the api.

## See also - start-vs-mount · prototypes · uri-bind-mount - Full command reference: api.