diff --git a/AGENTS.md b/AGENTS.md index 61edb5cf1..bfa51022c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,7 +48,7 @@ A spec is the accurate reference for the current code: it states the invariants **May combine a concise `Files` / `Code Map` section with section-local `Source of truth:` pointers.** The map gives readers key entrypoints to follow through imports; the pointers locate the implementation of a particular rule. Map the useful starting points, not every file. Short specs need no map when their local pointers already make navigation clear. Keep behavior and invariants in their owning sections, rather than repeating them in map descriptions. - **`docs/specs/glossary.md`** — Canonical vocabulary: the Surface model, Session layers, `Window ⊃ Workspace ⊃ Pane ⊃ Surface`, transition verbs, invariants I1–I10. Read first; every spec defers to it for state, kind, and verb names. -- **`docs/specs/layout.md`** — The interaction model over the tiling engine: modes, command-mode dispatch, navigation, minimize/reattach, kill/rename, session lifecycle and persistence recovery, the workspaces-rollout ledger. Read before touching keyboard/navigation/mode/workspace behavior. +- **`docs/specs/layout.md`** — The interaction model over the tiling engine: modes, command-mode dispatch, navigation, minimize/reattach, kill/rename, session lifecycle and persistence recovery, the Workspace model. Read before touching keyboard/navigation/mode/workspace behavior. - **`docs/specs/shortcuts.md`** — Quick-reference table of every shortcut by mode/context; layout.md owns the behavior — update both when a binding changes. - **`docs/specs/tiling-engine.md`** — **Lath**, the in-house headless tiling engine: pure split-tree core, never-re-parent LathHost adapter, wall store + engine, Lath-only persistence. - **`docs/specs/alert.md`** — The Activity layer: alert tracks, attention model, TODO lifecycle, notification protocols with their sanitization rules, the Workspace union projection. @@ -101,7 +101,7 @@ Specs are written ahead of the code: a new component's spec starts as a full des - **The fold.** Everything above `## Future` describes the code as it is — present tense, anchored with `Source of truth:` pointers. Everything unbuilt lives under `## Future`, always the last section; a spec with no unbuilt design has none. - **Design-stage specs.** A spec for a component that does not exist yet keeps its whole design under `## Future`, opens with `> Status: design — nothing here is implemented yet.`, and is indexed above like any other. -- **Named scopes.** A cut is recorded as a named scope at the top of `## Future` (`**Scope: workspaces-rollout**`), listing what remains in staged order. A scope is defined in exactly one spec; other specs link it by name and never restate it. Rollout ledgers live in the owning spec's `## Future`, nowhere else. +- **Named scopes.** A cut is recorded as a named scope at the top of `## Future` (`**Scope: dor-tools**`), listing what remains in staged order. A scope is defined in exactly one spec; other specs link it by name and never restate it. Rollout ledgers live in the owning spec's `## Future`, nowhere else. - **Reservations.** Unbuilt design that constrains present code — a reserved wire field, a reserved ref grammar, an additive-evolution guarantee — is stated in the body, marked `Reserved:`, pointing at the `## Future` item it serves. Test: if deleting the sentence would let someone break future compatibility today, it belongs in the body. - **Promotion is part of done.** A staged item is finished only when its text moves above the fold — "will" rewritten to "is", `Source of truth:` added — and the built portion is deleted from `## Future`. Never leave completed plan text (build orders, phase lists) below the fold; git keeps the record. diff --git a/docs/specs/dor-browser.md b/docs/specs/dor-browser.md index 1334c1745..f0104e13a 100644 --- a/docs/specs/dor-browser.md +++ b/docs/specs/dor-browser.md @@ -209,12 +209,28 @@ PATH. **Both `dor ab` and the host must spawn `agent-browser` through `.cmd`-shim recipe applies even to that absolute path (`docs/specs/dor-cli.md` → Spawning External Binaries). -Managed identity: - -- Default is `--key default`; `--key ` maps to `dormouse.1.` and must - match `[A-Za-z0-9._-]+`. `--key`, raw `--session`, `--surface` are mutually - exclusive. -- GUI-spawned sessions use `dormouse.1.gui-`, which no `--key` names; they +### Managed identity + +- Default is `--key default`; `--key ` must match `[A-Za-z0-9._-]+`. + `--key`, raw `--session`, `--surface` are mutually exclusive. +- **A key is namespaced by the Workspace that holds the browser** — + `dormouse..`, the Workspace's *stable* id so a strip reorder + renames nothing — and `dormouse.1.` for a bare Wall, which has no + Workspace id (VS Code, the website, Pocket). The same key in two Workspaces is + therefore two browsers, which is what keeps one Surface per session (below) + once several Workspaces each run `dor ab --key default`. **Only the answering Workspace can name it**, + so `dor ab` asks the host (`surface.resolveAgentBrowser` with `key`) before it + forwards anything, and namespaces the key itself only when there is no control + endpoint at all — outside Dormouse, where `dor ab` is a pure passthrough. + **Every managed `dor ab` invocation depends on the host answering** — a + passthrough verb included — with no CLI-side fallback: a refusal (a Wall still + mounting, a webview mid-reload, the VS Code guard) fails the command with the + host's message before the binary runs, and the router answers the no-Wall + case after its bounded retry rather than leaving `dor ab` to its deadline + (`docs/specs/dor-cli.md` → "Handle Model"). A CLI-namespaced fallback would + name the wrong Workspace's browser. +- GUI-spawned sessions use `dormouse.1.gui-`, minted host-wide (the Window's + one agent-browser host, not a Workspace), which no `--key` names; they are reachable by `dor ab --surface ` (`docs/specs/dor-cli.md` → Agent-Browser Surface Addressing). **The host answers only for an agent-browser-rendered Surface** — an `iframe`-rendered Surface has a browser @@ -225,7 +241,8 @@ Managed identity: or render-swapped mid-command leaves the trailing request to mint a fresh pane (rationale). -Source of truth: `dor/src/commands/agent-browser.ts`, `dor/src/commands/types.ts` +Source of truth: `sessionForKey` in `dor-lib-common/src/agent-browser.ts`, +`resolveSession` in `dor/src/commands/agent-browser.ts`, `dor/src/commands/types.ts` (`AgentBrowserSurfaceRequest`, `ResolveAgentBrowserSessionRequest`), `lib/src/components/Wall.tsx` / `lib/src/components/wall/use-dor-control.ts` (`findAgentBrowserSurface`, `surface.agentBrowser`, `surface.resolveAgentBrowser`). diff --git a/docs/specs/dor-cli.md b/docs/specs/dor-cli.md index 11023b1c0..c4f7092fa 100644 --- a/docs/specs/dor-cli.md +++ b/docs/specs/dor-cli.md @@ -250,12 +250,11 @@ and each host's hop in `standalone/src/tauri-adapter.ts`, ## Handle Model -`Window ⊃ Workspace ⊃ Pane ⊃ Surface` (`docs/specs/glossary.md`). **User-facing -`dor` commands expose Surface handles only**, and because a Window can hold -several Workspaces — and standalone can hold several Windows — the handle model -reserves `workspace:` and `window: