From 6ed6cb6f792ef87ef05f3da4e4dadda1f4a8f0f3 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Thu, 3 Sep 2026 15:31:21 -0700 Subject: [PATCH 1/2] docs: refresh dor agent skill --- docs/specs/dor-cli.md | 6 ++--- docs/specs/glossary.md | 2 +- docs/specs/glossary.rationale.md | 2 +- dor/skill.md | 45 ++++++++++++++++++-------------- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/docs/specs/dor-cli.md b/docs/specs/dor-cli.md index 5ab23ed72..8f54d5afb 100644 --- a/docs/specs/dor-cli.md +++ b/docs/specs/dor-cli.md @@ -462,9 +462,9 @@ Source of truth: `extractSessionFlags` / `resolveSession` in These scenarios are the CLI's product-level acceptance tests: the commands must *compose*, not merely work alone. All reduce to one shape — **discover the target Surface with `dor list` (filtered), then act on it with a handle-taking -command.** So matching lives in `dor list` alone; `read` / `send` / `kill` -**must not grow their own match syntax**, and a bare `dor kill "npm dev"` stays -unsupported. +command.** So matching lives in `dor list` alone; `read` / `send` / `await` / +`kill` **must not grow their own match syntax**, and a bare `dor kill "npm dev"` +stays unsupported. **Identity follows the Surface, not a user-supplied key:** a terminal Surface is named by its Workspace-stable `surface:N` ref, or rediscovered after layout diff --git a/docs/specs/glossary.md b/docs/specs/glossary.md index bf92fa90b..5fbe4f0ad 100644 --- a/docs/specs/glossary.md +++ b/docs/specs/glossary.md @@ -15,7 +15,7 @@ A **Surface** is the durable occupant of a Pane — the content in a slot. Two k A **Pane** is one Lath leaf, a slot in the tiling layout (`docs/specs/tiling-engine.md`); `lib/src/components/Wall.tsx` owns Panes and Surfaces both. -A Pane holds exactly one Surface today, but the model reserves several (a future in-pane surface strip), so **`dor` targets content — `read` / `send` / `kill` — by Surface ref (`surface:N`)**, holding Pane refs back for layout-only commands (rationale). +A Pane holds exactly one Surface today, but the model reserves several (a future in-pane surface strip), so **`dor` targets content — `read` / `send` / `await` / `kill` — by Surface ref (`surface:N`)**, holding Pane refs back for layout-only commands (rationale). **Surface kinds** — the `kind` a `dor` handle reports, derived from the Pane's params, never stored on the id: diff --git a/docs/specs/glossary.rationale.md b/docs/specs/glossary.rationale.md index e93aef8a3..b5a552f06 100644 --- a/docs/specs/glossary.rationale.md +++ b/docs/specs/glossary.rationale.md @@ -4,7 +4,7 @@ ## Panes and Surfaces -**Why `dor` addresses content by Surface ref, not Pane ref.** Once an in-pane surface strip puts several Surfaces in one Pane, every `read` / `send` / `kill` spelled against a Pane becomes ambiguous, while the layout-only commands still mean one thing — so Pane refs are left unspent for those. +**Why `dor` addresses content by Surface ref, not Pane ref.** Once an in-pane surface strip puts several Surfaces in one Pane, every `read` / `send` / `await` / `kill` spelled against a Pane becomes ambiguous, while the layout-only commands still mean one thing — so Pane refs are left unspent for those. **Why every row carries both capability flags.** `kind` is an enum, so a caller that branches on `kind === 'terminal'` silently stops matching the day a kind carrying both capabilities ships — the staged `tool` (`docs/specs/dor-tool.md`) is that kind. `has_terminal` / `has_browser` express the same fact in a form that keeps matching, so a script written against today's two kinds still selects correctly against three; emitting them unconditionally, rather than only where they differ from the kind, is what makes that free to rely on. diff --git a/dor/skill.md b/dor/skill.md index 4b94ece36..bd88eff78 100644 --- a/dor/skill.md +++ b/dor/skill.md @@ -23,7 +23,7 @@ The rest of this guide is how to do everything well. ## Targeting: three ways to name a surface -Action commands (`read`, `send`, `kill`) take a surface handle — there is +Action commands (`read`, `send`, `await`, `kill`) take a surface handle — there is deliberately no `dor kill "npm dev"`. You name the surface you want one of three ways: @@ -139,6 +139,20 @@ dor read surface:3 # visible screen, printed directly dor read surface:3 --scrollback --lines 200 ``` +### `dor await` — wait for a terminal to finish + +```sh +dor await surface:3 --until quiet +dor await surface:3 --until exit --timeout 1800 +``` + +Use `--until quiet` for agents that may stay alive after answering; it wakes +when the terminal settles, its foreground command exits, or it rings. Use +`--until exit` for builds, tests, and migrations that can fall silent before +their command finishes. `await` prints the reason it woke, not the terminal +text, so follow it with `dor read` when you need the result. Waiting absorbs +the alert it receives because the program has handled it. + ### `dor kill` — kill a surface (confirmation required) ```sh @@ -158,6 +172,7 @@ so the user watches what you drive. ```sh dor ab open http://localhost:5173 # key "default" +dor ab open surface:3 # auto-detect that terminal's port dor ab --key server open http://localhost:3000 dor ab click @e3 # further args are agent-browser's own dor ab --key server reload @@ -169,33 +184,23 @@ one surface, reused across commands. Use distinct keys when you need independent browsers at once. `--surface ` drives whatever browser a handle names, so a ref from -`dor list` works here exactly as it does for `read` / `send` / `kill`. Prefer -it whenever you hold a ref rather than a key — it is the only way to reach a -browser the *user* opened from the GUI, which has no key. It fails on a +`dor list` works here exactly as it does for `read` / `send` / `await` / `kill`. +Prefer it whenever you hold a ref rather than a key — it is the only way to +reach a browser the *user* opened from the GUI, which has no key. It fails on a terminal (no browser), and on an `iframe`-rendered surface (nothing to drive — -open it with `dor ab` instead). The three identity flags are mutually -exclusive. +open it with `dor ab` instead). The three identity flags are mutually exclusive. `dor ab` has no `--json` of its own; any JSON flags belong to `agent-browser`. -### `dor iframe` — high-fidelity URL pane for the user - -```sh -dor iframe http://localhost:6006 # absolute http(s) URL required -``` - -For *showing* a page to the human at full fidelity (no automation hooks). -Provisional: some sites refuse framing. To *drive* a page, use `dor ab`. - ## Recipes -**Run a dev server and show it to the user.** Ensure it, find its port, open a -browser on it: +**Run a dev server and show it to the user.** Keep the surface handle from +`ensure` and open a browser against it; Dormouse detects the server's port: ```sh -dor ensure -- npm run dev -dor list --command "npm run dev" --cwd . --ports # read the port -dor ab open http://localhost: +$ dor ensure -- npm run dev +created surface:3 "npm run dev" +$ dor ab open surface:3 ``` **Launch and drive a sub-agent** (another CLI agent in a sibling pane): From cf16df13d7f12d4f50742305ace6a215aa4cc19b Mon Sep 17 00:00:00 2001 From: dormouse-bot <287024035+dormouse-bot@users.noreply.github.com> Date: Thu, 3 Sep 2026 22:59:05 +0000 Subject: [PATCH 2/2] docs: drop iframe from the agent skill's surface-creating command lists --- dor/skill.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dor/skill.md b/dor/skill.md index bd88eff78..f277b8c5e 100644 --- a/dor/skill.md +++ b/dor/skill.md @@ -27,9 +27,9 @@ Action commands (`read`, `send`, `await`, `kill`) take a surface handle — ther deliberately no `dor kill "npm dev"`. You name the surface you want one of three ways: -1. **Hold the handle.** Commands that create surfaces (`split`, `ensure`, - `iframe`) print the new ref (`created surface:3`). Capture it and act on - it directly — refs stay valid across any layout churn. +1. **Hold the handle.** Commands that create surfaces (`split`, `ensure`) + print the new ref (`created surface:3`). Capture it and act on it + directly — refs stay valid across any layout churn. 2. **Address by identity key.** Surfaces with a natural identity skip handle bookkeeping: `dor ensure -- ` uses its exact command + cwd as an implicit key (match-or-create in one idempotent call), and browser @@ -263,8 +263,8 @@ dor kill surface:N --confirm-if-read "npm run dev" -- `, or a bare-terminal `dor split --`) never steal focus. Only a bare `dor split` with no `--` does — never run that in automation; use `dor split --` for an empty pane instead. -- **Take refs from responses.** Capture the ref that `split`/`ensure`/`iframe` - print rather than re-listing and guessing. +- **Take refs from responses.** Capture the ref that `split`/`ensure` print + rather than re-listing and guessing. - **`--command` is exact.** Match the command string you launched with, including its flags. - **Prefer `--confirm-if-read` over `--confirm-dangerously`** unless you have