Dormouse

dor CLI reference

dor is on the PATH of every terminal Dormouse launches. This page is generated from the CLI's own help output.

Targeting

Action commands (read, send, kill) take a surface handle — there is 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.

  2. Address by identity key. Surfaces with a natural identity skip handle bookkeeping: dor ensure -- <command> uses its exact command + cwd as an implicit key (match-or-create in one idempotent call), and browser surfaces are addressed by an explicit key (dor ab --key <name>). A browser you did not create has no key you know — hold its ref and use dor ab --surface <ref>.

  3. Rediscover. When you hold nothing — a fresh session, or a process the user started by hand — dor list (filtered) turns a description (--command, --cwd, --port) into a handle.

Text output is designed for you to read: it is terse and carries the same refs. Reach for --json (every command except dor ab supports it) only when a shell script or pipeline using jq consumes the output.

Surface handles

  • surface:N — short ref, e.g. surface:3. Stable for the surface's whole life: reordering, minimizing, zooming, and focus changes never change it, and numbers are never reused after a kill. A ref for a killed surface fails loudly instead of silently retargeting, so refs from earlier in your session stay safe to use.

  • A stable surface id (or surface:<stable-id>) — from --json output.

  • surface:self — the terminal you are running in.

  • surface:focused — whatever the user currently has focused.

  • title:<exact title> — exists for human recovery; avoid it in automation (titles drift). Prefer refs from command responses or dor list.

Bare numbers and pane:N are not valid handles.

dor

dor --help

dor split [--left|--right|--up|--down|--auto] [--json] [--minimize] [--surface id|ref] [-- <command>...]
dor ensure [--json] [--minimize] [--restart] [--surface id|ref] [--cwd path] -- <command>...
dor version [--json]
dor skill [--install] [--json]
dor send <surface> ([--text value] [--key value] | --stdin | --sequence json) [--json] [--raw]
dor read <surface> [--json] [--lines count] [--scrollback]
dor await <surface> --until condition [--json] [--timeout seconds]
dor kill <surface> [--confirm-if-read text|--confirm-dangerously] [--json]
dor iframe [--json] [--minimize] [--surface id|ref] <target>
dor agent-browser [--key name|--session name|--surface handle] [args...]
dor list [--command text] [--cwd path] [--id-format refs|ids|both] [--json] [--kind terminal|browser] [--port number] [--ports] [--view paned|zoomed|minimized]
dor --help

Dormouse bundles the dor CLI into every terminal it launches.

FLAGS

-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

COMMANDS

splitCreate a new terminal surface by splitting an existing surface.
ensureEnsure one surface is running a command.
versionPrint the dor CLI version.
skillPrint the Dormouse agent skill, or install its bootstrap stub.
sendSend text or key input to a terminal surface.
readRead terminal text from a surface.
awaitWait until a terminal surface finishes.
killKill a surface.
iframeOpen a target in an iframe surface.
agent-browserDrive a browser surface via your agent-browser install (alias: dor ab).
listList Dormouse Surfaces.
Exact dor --help output
USAGE
  dor split [--left|--right|--up|--down|--auto] [--json] [--minimize] [--surface id|ref] [-- <command>...]
  dor ensure [--json] [--minimize] [--restart] [--surface id|ref] [--cwd path] -- <command>...
  dor version [--json]
  dor skill [--install] [--json]
  dor send <surface> ([--text value] [--key value] | --stdin | --sequence json) [--json] [--raw]
  dor read <surface> [--json] [--lines count] [--scrollback]
  dor await <surface> --until condition [--json] [--timeout seconds]
  dor kill <surface> [--confirm-if-read text|--confirm-dangerously] [--json]
  dor iframe [--json] [--minimize] [--surface id|ref] <target>
  dor agent-browser [--key name|--session name|--surface handle] [args...]
  dor list [--command text] [--cwd path] [--id-format refs|ids|both] [--json] [--kind terminal|browser] [--port number] [--ports] [--view paned|zoomed|minimized]
  dor --help

Dormouse bundles the dor CLI into every terminal it launches.

FLAGS
  -h --help  Print help information and exit
     --      All subsequent inputs should be interpreted as arguments

COMMANDS
  split          Create a new terminal surface by splitting an existing surface.
  ensure         Ensure one surface is running a command.
  version        Print the dor CLI version.
  skill          Print the Dormouse agent skill, or install its bootstrap stub.
  send           Send text or key input to a terminal surface.
  read           Read terminal text from a surface.
  await          Wait until a terminal surface finishes.
  kill           Kill a surface.
  iframe         Open a target in an iframe surface.
  agent-browser  Drive a browser surface via your agent-browser install (alias: dor ab).
  list           List Dormouse Surfaces.

Commands

dor split

dor split --help

dor split [--left|--right|--up|--down|--auto] [--json] [--minimize] [--surface id|ref] [-- <command>...]
dor split --help

If no direction is provided, --auto is used. --auto chooses right when the target surface is wide, down when it is narrow, and right when the target is minimized.

Use -- followed by a command to run an initial command in the new terminal surface.

Focus depends only on whether you pass --. A bare "dor split" (no --) moves focus to the new surface so a human can start typing in it — avoid it in automation, since it steals the user's keystrokes. Anything with -- leaves focus on the caller: "dor split -- <command>" runs the command in the background, and a bare "dor split --" opens a blank terminal without stealing focus.

--minimize creates the surface and immediately sends it to the minimized area.

--surface selects the surface to split. If the target is minimized, the new surface is created minimized too and inserted immediately to the right of the target door. If omitted, Dormouse uses the caller surface when available, then the focused surface.

split creates terminal Surfaces. Compose browser content commands through the initial command:

dor split --right -- dor iframe https://example.com dor split --auto -- dor agent-browser open https://example.com

FLAGS

[--left|--right|--up|--down|--auto]Split direction. Mutually exclusive; default is --auto.
[--json]Print JSON output.
[--minimize]Create the surface minimized.
[--surface]Surface to split.
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

Text output:

  created surface:2  [right]
  created surface:3  [down]  [minimized]  "pnpm dev"

JSON output:

  {
    "status": "created",
    "surface_id": "pane-abc",
    "surface_ref": "surface:2",
    "direction": "right",
    "minimized": false,
    "command": "pnpm dev"
  }
Exact dor split --help output
USAGE
  dor split [--left|--right|--up|--down|--auto] [--json] [--minimize] [--surface id|ref] [-- <command>...]
  dor split --help

If no direction is provided, --auto is used. --auto chooses right when the target surface is wide, down when it is narrow, and right when the target is minimized.

Use -- followed by a command to run an initial command in the new terminal surface.

Focus depends only on whether you pass --. A bare "dor split" (no --) moves focus to the new surface so a human can start typing in it — avoid it in automation, since it steals the user's keystrokes. Anything with -- leaves focus on the caller: "dor split -- <command>" runs the command in the background, and a bare "dor split --" opens a blank terminal without stealing focus.

--minimize creates the surface and immediately sends it to the minimized area.

--surface selects the surface to split. If the target is minimized, the new surface is created minimized too and inserted immediately to the right of the target door. If omitted, Dormouse uses the caller surface when available, then the focused surface.

split creates terminal Surfaces. Compose browser content commands through the initial command:

  dor split --right -- dor iframe https://example.com
  dor split --auto -- dor agent-browser open https://example.com

Text output:
  created surface:2  [right]
  created surface:3  [down]  [minimized]  "pnpm dev"

JSON output:
  {
    "status": "created",
    "surface_id": "pane-abc",
    "surface_ref": "surface:2",
    "direction": "right",
    "minimized": false,
    "command": "pnpm dev"
  }

FLAGS
     [--left|--right|--up|--down|--auto]
                  Split direction. Mutually exclusive; default is --auto.
     [--json]      Print JSON output.
     [--minimize]  Create the surface minimized.
     [--surface]   Surface to split.
  -h  --help       Print help information and exit
      --           All subsequent inputs should be interpreted as arguments

dor ensure

dor ensure --help

dor ensure [--json] [--minimize] [--restart] [--surface id|ref] [--cwd path] -- <command>...
dor ensure --help

Ensures one surface in the current workspace is running the given command at the given path. If it's already running, no-op. If it isn't, then it creates a split and runs the command.

ensure never changes focus. Whether it reuses a match, restarts one, or creates a new split, the surface you ran it from keeps focus — a newly created surface (visible or minimized) starts in the background.

Matching uses the command each shell reports it is running via Dormouse shell integration (OSC 633), not process inspection. This captures the typed command (`npm run dev`), not the forked child process (`node .../vite`), and works for shells the user started by hand as well as shells Dormouse started. The match is exact: `npm run dev` and `npm run dev --host` are different commands and get separate surfaces.

ensure requires that integration: a surface can only be matched, reused, or restarted if its shell reports its command. So if the shell has no OSC 633 integration (e.g. cmd.exe), ensure fails with an error rather than starting an untrackable surface — run it from a shell with integration, such as Git Bash or PowerShell.

A surface matches only while the command is live. Once the command exits and the shell returns to its prompt, the surface no longer matches; the next ensure causes a fresh split rather than reusing the idle shell. Minimized surfaces participate in matching. Closed/killed surfaces do not.

Two surfaces running the same command in different working directories are distinct (e.g. the same dev server in two worktrees). Both keep running; ensure never collapses them.

--cwd sets the working directory used both for matching and for the new command. If omitted, Dormouse uses the directory dor was invoked from. The path is resolved to an absolute path and matched exactly; symlinks are not resolved, so two routes to the same directory are treated as distinct.

--minimize applies only when creating a new surface; it does not minimize an existing match.

--restart applies only to an already-running match: it interrupts the live command (Ctrl+C), waits for the shell to return to its prompt, then re-runs the command in place and blocks until the command is live again. A restarted surface keeps its minimized/visible state. If no surface is running the command, --restart behaves like a plain ensure and creates one.

--surface selects the surface to split only when creating a new surface. If the target is minimized, the new surface is created minimized too and inserted immediately to the right of the target door. If omitted, Dormouse uses the same caller/focused fallback as dor split.

FLAGS

[--json]Print JSON output.
[--minimize]Create the surface minimized.
[--restart]Restart a matching surface in place.
[--surface]Surface to split when creating.
[--cwd]Working directory for matching and for the new command.
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

Text output:

  created surface:3  "npm run dev"
  existing surface:3  "npm run dev"
  restarted surface:3  "npm run dev"

JSON output:

  {
    "status": "created",
    "surface_id": "pane-def",
    "surface_ref": "surface:3",
    "command": "npm run dev",
    "cwd": "/Users/me/projects/site",
    "minimized": false
  }
Exact dor ensure --help output
USAGE
  dor ensure [--json] [--minimize] [--restart] [--surface id|ref] [--cwd path] -- <command>...
  dor ensure --help

Ensures one surface in the current workspace is running the given command at the given path. If it's already running, no-op. If it isn't, then it creates a split and runs the command.

ensure never changes focus. Whether it reuses a match, restarts one, or creates a new split, the surface you ran it from keeps focus — a newly created surface (visible or minimized) starts in the background.

Matching uses the command each shell reports it is running via Dormouse shell integration (OSC 633), not process inspection. This captures the typed command (`npm run dev`), not the forked child process (`node .../vite`), and works for shells the user started by hand as well as shells Dormouse started. The match is exact: `npm run dev` and `npm run dev --host` are different commands and get separate surfaces.

ensure requires that integration: a surface can only be matched, reused, or restarted if its shell reports its command. So if the shell has no OSC 633 integration (e.g. cmd.exe), ensure fails with an error rather than starting an untrackable surface — run it from a shell with integration, such as Git Bash or PowerShell.

A surface matches only while the command is live. Once the command exits and the shell returns to its prompt, the surface no longer matches; the next ensure causes a fresh split rather than reusing the idle shell. Minimized surfaces participate in matching. Closed/killed surfaces do not.

Two surfaces running the same command in different working directories are distinct (e.g. the same dev server in two worktrees). Both keep running; ensure never collapses them.

--cwd sets the working directory used both for matching and for the new command. If omitted, Dormouse uses the directory dor was invoked from. The path is resolved to an absolute path and matched exactly; symlinks are not resolved, so two routes to the same directory are treated as distinct.

--minimize applies only when creating a new surface; it does not minimize an existing match.

--restart applies only to an already-running match: it interrupts the live command (Ctrl+C), waits for the shell to return to its prompt, then re-runs the command in place and blocks until the command is live again. A restarted surface keeps its minimized/visible state. If no surface is running the command, --restart behaves like a plain ensure and creates one.

--surface selects the surface to split only when creating a new surface. If the target is minimized, the new surface is created minimized too and inserted immediately to the right of the target door. If omitted, Dormouse uses the same caller/focused fallback as dor split.

Text output:
  created surface:3  "npm run dev"
  existing surface:3  "npm run dev"
  restarted surface:3  "npm run dev"

JSON output:
  {
    "status": "created",
    "surface_id": "pane-def",
    "surface_ref": "surface:3",
    "command": "npm run dev",
    "cwd": "/Users/me/projects/site",
    "minimized": false
  }

FLAGS
     [--json]      Print JSON output.
     [--minimize]  Create the surface minimized.
     [--restart]   Restart a matching surface in place.
     [--surface]   Surface to split when creating.
     [--cwd]       Working directory for matching and for the new command.
  -h  --help       Print help information and exit
      --           All subsequent inputs should be interpreted as arguments

dor version

dor version --help

dor version [--json]
dor version --help

Prints the latest released Dormouse version from CHANGELOG.md, the build commit, and a prerelease-style build suffix when the build contains commits after that version tag.

FLAGS

[--json]Print JSON output.
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

Text output:

  dor 0.11.0 [1a2b3c4d] (0.11.0+12)

JSON output:

  {
    "version": "0.11.0",
    "commit": "1a2b3c4d",
    "commits_since_version": 12,
    "build": "0.11.0+12"
  }
Exact dor version --help output
USAGE
  dor version [--json]
  dor version --help

Prints the latest released Dormouse version from CHANGELOG.md, the build commit, and a prerelease-style build suffix when the build contains commits after that version tag.

Text output:
  dor 0.11.0 [1a2b3c4d] (0.11.0+12)

JSON output:
  {
    "version": "0.11.0",
    "commit": "1a2b3c4d",
    "commits_since_version": 12,
    "build": "0.11.0+12"
  }

FLAGS
     [--json]  Print JSON output.
  -h  --help   Print help information and exit
      --       All subsequent inputs should be interpreted as arguments

dor skill

dor skill --help

dor skill [--install] [--json]
dor skill --help

Prints the Dormouse agent skill — instructions that teach a coding agent to drive Dormouse through the dor CLI: run background processes in visible panes, open browser surfaces, and launch and coordinate sub-agents. The text ships inside the CLI, so it always matches the Dormouse that staged it.

--install instead writes a marker-delimited bootstrap stub into the project's agent instructions file. The stub is the detection rule — if DORMOUSE_SURFACE_ID is set, run `dor skill` and follow it — plus two loud, mandatory directives (use `dor ensure` for long-running processes, `dor ab` for browsers) that must land before an agent would think to run `dor skill`. It stays otherwise fact-free, so a committed stub does not go stale.

If AGENTS.md or CLAUDE.md already contains the block, it is rewritten in place. Otherwise the stub goes to AGENTS.md when it exists, else to CLAUDE.md when it exists and does not already import AGENTS.md (via `@AGENTS.md`), else to a newly created AGENTS.md. Everything outside the markers is left untouched, so re-running is idempotent.

FLAGS

[--install]Install the bootstrap stub into the project's agent instructions file.
[--json]Print JSON output.
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

Text output:

  created AGENTS.md
  updated CLAUDE.md

JSON output:

  {
    "status": "created",
    "file": "AGENTS.md"
  }
Exact dor skill --help output
USAGE
  dor skill [--install] [--json]
  dor skill --help

Prints the Dormouse agent skill — instructions that teach a coding agent to drive Dormouse through the dor CLI: run background processes in visible panes, open browser surfaces, and launch and coordinate sub-agents. The text ships inside the CLI, so it always matches the Dormouse that staged it.

--install instead writes a marker-delimited bootstrap stub into the project's agent instructions file. The stub is the detection rule — if DORMOUSE_SURFACE_ID is set, run `dor skill` and follow it — plus two loud, mandatory directives (use `dor ensure` for long-running processes, `dor ab` for browsers) that must land before an agent would think to run `dor skill`. It stays otherwise fact-free, so a committed stub does not go stale.

If AGENTS.md or CLAUDE.md already contains the block, it is rewritten in place. Otherwise the stub goes to AGENTS.md when it exists, else to CLAUDE.md when it exists and does not already import AGENTS.md (via `@AGENTS.md`), else to a newly created AGENTS.md. Everything outside the markers is left untouched, so re-running is idempotent.

Text output:
  created AGENTS.md
  updated CLAUDE.md

JSON output:
  {
    "status": "created",
    "file": "AGENTS.md"
  }

FLAGS
     [--install]  Install the bootstrap stub into the project's agent instructions file.
     [--json]     Print JSON output.
  -h  --help      Print help information and exit
      --          All subsequent inputs should be interpreted as arguments

dor send

dor send --help

dor send <surface> ([--text value] [--key value] | --stdin | --sequence json) [--json] [--raw]
dor send --help

Sends text or key input to a target terminal surface. Special keys must be sent with --key so values like "enter" are never confused with literal text.

Exactly one input mode is required: --text/--key, --stdin, or --sequence. --text and --key may be combined only in that order; text is sent first, then the key. Duplicate input flags are rejected. Use --sequence for arbitrary ordering or multiple text/key events.

Text input interprets backslash escapes for \n, \r, \t, and \\ unless --raw is set.

Supported keys: enter, escape, esc, tab, backspace, delete, up, down, left, right, ctrl-a through ctrl-z.

Sequence input is an ordered JSON array of {"text":"..."} and {"key":"..."} objects.

FLAGS

[--json]Print JSON output.
[--key]Send a named key or chord.
[--raw]Do not interpret backslash escapes in text input.
[--sequence]Send an ordered JSON sequence of text and key events.
[--stdin]Read text from standard input and send it as text.
[--text]Send literal text.
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

ARGUMENTS

surfaceTarget surface.

Examples:

  dor send surface:3 --text "echo hello"
  dor send surface:3 --text "npm test" --key enter
  dor send surface:3 --key ctrl-c
  cat script.sh | dor send surface:3 --stdin
  dor send surface:3 --sequence '[{"text":"npm test"},{"key":"enter"}]'

JSON output:

  {
    "status": "sent",
    "surface_id": "...",
    "surface_ref": "surface:3",
    "input_count": 1
  }
Exact dor send --help output
USAGE
  dor send <surface> ([--text value] [--key value] | --stdin | --sequence json) [--json] [--raw]
  dor send --help

Sends text or key input to a target terminal surface. Special keys must be sent with --key so values like "enter" are never confused with literal text.

Exactly one input mode is required: --text/--key, --stdin, or --sequence. --text and --key may be combined only in that order; text is sent first, then the key. Duplicate input flags are rejected. Use --sequence for arbitrary ordering or multiple text/key events.

Text input interprets backslash escapes for \n, \r, \t, and \\ unless --raw is set.

Supported keys: enter, escape, esc, tab, backspace, delete, up, down, left, right, ctrl-a through ctrl-z.

Sequence input is an ordered JSON array of {"text":"..."} and {"key":"..."} objects.

JSON output:
  {
    "status": "sent",
    "surface_id": "...",
    "surface_ref": "surface:3",
    "input_count": 1
  }

Examples:
  dor send surface:3 --text "echo hello"
  dor send surface:3 --text "npm test" --key enter
  dor send surface:3 --key ctrl-c
  cat script.sh | dor send surface:3 --stdin
  dor send surface:3 --sequence '[{"text":"npm test"},{"key":"enter"}]'

FLAGS
     [--json]      Print JSON output.
     [--key]       Send a named key or chord.
     [--raw]       Do not interpret backslash escapes in text input.
     [--sequence]  Send an ordered JSON sequence of text and key events.
     [--stdin]     Read text from standard input and send it as text.
     [--text]      Send literal text.
  -h  --help       Print help information and exit
      --           All subsequent inputs should be interpreted as arguments

ARGUMENTS
  surface  Target surface.

dor read

dor read --help

dor read <surface> [--json] [--lines count] [--scrollback]
dor read --help

Reads the visible screen text from the target terminal surface. Use --scrollback to include terminal history, and --lines to limit how much text is returned.

Text mode prints terminal text directly.

FLAGS

[--json]Print JSON output.
[--lines]Maximum number of lines to return.
[--scrollback]Include terminal scrollback/history instead of only the visible screen.
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

ARGUMENTS

surfaceSurface to read.

JSON output:

  {
    "workspace_ref": "workspace:1",
    "surface_id": "...",
    "surface_ref": "surface:3",
    "text": "..."
  }
Exact dor read --help output
USAGE
  dor read <surface> [--json] [--lines count] [--scrollback]
  dor read --help

Reads the visible screen text from the target terminal surface. Use --scrollback to include terminal history, and --lines to limit how much text is returned.

Text mode prints terminal text directly.

JSON output:
  {
    "workspace_ref": "workspace:1",
    "surface_id": "...",
    "surface_ref": "surface:3",
    "text": "..."
  }

FLAGS
     [--json]        Print JSON output.
     [--lines]       Maximum number of lines to return.
     [--scrollback]  Include terminal scrollback/history instead of only the visible screen.
  -h  --help         Print help information and exit
      --             All subsequent inputs should be interpreted as arguments

ARGUMENTS
  surface  Surface to read.

dor await

dor await --help

dor await <surface> --until condition [--json] [--timeout seconds]
dor await --help

Waits until a terminal surface finishes what it is doing, then reports why the wait ended. Lets an agent block on a peer it launched with `dor split` instead of polling `dor list` in a loop.

Prints no terminal text. Follow with `dor read` to see the screen.

--until says what counts as finished: quiet The surface settled, the running command exited, or the surface rang the bell. Use for agents that keep running, such as claude or codex. exit The running command exited, and nothing else. Use for builds and test runs, which can fall silent mid-run without being finished.

Waiting absorbs the alert. A surface that finishes while awaited does not ring the bell, speak an alarm, or notify a paired phone, and is not marked TODO — the wait already delivered the news.

Text mode prints the cause alone on stdout: quiet, exit, bell, or idle. An idle result means nothing was running and nothing started, so there was never anything to wait for.

A one-line summary naming the cause and how long the wait took goes to stderr, so it stays out of the captured value: `quiet: output stopped after 10m 15s`. The duration is how long this command blocked, not how long the surface had been working.

--timeout accepts whole seconds up to 86400 (24h). The default is 600.

Exits 0 on any resolution, 2 on timeout, and 3 if the surface died before finishing. The JSON above is printed only on a resolution; a timeout or a death reports itself through the exit code and the stderr line, with nothing on stdout.

FLAGS

[--json]Print JSON output.
[--timeout]Seconds to wait before giving up. Default 600; max 86400.
--untilWhat to wait for: quiet or exit.
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

ARGUMENTS

surfaceSurface to wait on.

Examples:

  dor await surface:3 --until quiet
  dor await surface:3 --until quiet && dor read surface:3
  dor await surface:3 --until exit --timeout 1800
  CAUSE=$(dor await surface:3 --until quiet)

JSON output:

  {
    "workspace_ref": "workspace:1",
    "surface_id": "...",
    "surface_ref": "surface:3",
    "cause": "quiet",
    "waited_ms": 615000,
    "detail": "output stopped after 10m 15s"
  }
Exact dor await --help output
USAGE
  dor await <surface> --until condition [--json] [--timeout seconds]
  dor await --help

Waits until a terminal surface finishes what it is doing, then reports why the wait ended. Lets an agent block on a peer it launched with `dor split` instead of polling `dor list` in a loop.

Prints no terminal text. Follow with `dor read` to see the screen.

--until says what counts as finished:
  quiet  The surface settled, the running command exited, or the surface rang the bell. Use for agents that keep running, such as claude or codex.
  exit   The running command exited, and nothing else. Use for builds and test runs, which can fall silent mid-run without being finished.

Waiting absorbs the alert. A surface that finishes while awaited does not ring the bell, speak an alarm, or notify a paired phone, and is not marked TODO — the wait already delivered the news.

Text mode prints the cause alone on stdout: quiet, exit, bell, or idle. An idle result means nothing was running and nothing started, so there was never anything to wait for.

A one-line summary naming the cause and how long the wait took goes to stderr, so it stays out of the captured value: `quiet: output stopped after 10m 15s`. The duration is how long this command blocked, not how long the surface had been working.

--timeout accepts whole seconds up to 86400 (24h). The default is 600.

JSON output:
  {
    "workspace_ref": "workspace:1",
    "surface_id": "...",
    "surface_ref": "surface:3",
    "cause": "quiet",
    "waited_ms": 615000,
    "detail": "output stopped after 10m 15s"
  }

Exits 0 on any resolution, 2 on timeout, and 3 if the surface died before finishing. The JSON above is printed only on a resolution; a timeout or a death reports itself through the exit code and the stderr line, with nothing on stdout.

Examples:
  dor await surface:3 --until quiet
  dor await surface:3 --until quiet && dor read surface:3
  dor await surface:3 --until exit --timeout 1800
  CAUSE=$(dor await surface:3 --until quiet)

FLAGS
     [--json]     Print JSON output.
     [--timeout]  Seconds to wait before giving up. Default 600; max 86400.
      --until     What to wait for: quiet or exit.
  -h  --help      Print help information and exit
      --          All subsequent inputs should be interpreted as arguments

ARGUMENTS
  surface  Surface to wait on.

dor kill

dor kill --help

dor kill <surface> [--confirm-if-read text|--confirm-dangerously] [--json]
dor kill --help

Kills a surface. One confirmation mode is required.

--confirm-if-read kills only if dor read <surface> would return visible text containing the provided text. The text must contain at least 4 non-whitespace characters.

--confirm-dangerously kills without further confirmation. Use only when automation has already validated the target.

FLAGS

[--confirm-dangerously]Kill without further confirmation.
[--confirm-if-read]Kill only if dor read contains this text.
[--json]Print JSON output.
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

ARGUMENTS

surfaceSurface to kill.

Text output:

  killed surface:3

JSON output:

  {
    "status": "killed",
    "surface_id": "...",
    "surface_ref": "surface:3"
  }
Exact dor kill --help output
USAGE
  dor kill <surface> [--confirm-if-read text|--confirm-dangerously] [--json]
  dor kill --help

Kills a surface. One confirmation mode is required.

--confirm-if-read kills only if dor read <surface> would return visible text containing the provided text. The text must contain at least 4 non-whitespace characters.

--confirm-dangerously kills without further confirmation. Use only when automation has already validated the target.

Text output:
  killed surface:3

JSON output:
  {
    "status": "killed",
    "surface_id": "...",
    "surface_ref": "surface:3"
  }

FLAGS
     [--confirm-dangerously]  Kill without further confirmation.
     [--confirm-if-read]      Kill only if dor read contains this text.
     [--json]                 Print JSON output.
  -h  --help                  Print help information and exit
      --                      All subsequent inputs should be interpreted as arguments

ARGUMENTS
  surface  Surface to kill.

dor iframe

dor iframe --help

dor iframe [--json] [--minimize] [--surface id|ref] <target>
dor iframe --help

Opens a target in a high-fidelity iframe surface for human inspection.

If the caller surface is an untouched terminal, Dormouse replaces that terminal with the iframe. Otherwise Dormouse creates a split next to the caller/focused surface.

The target is one of: <url> An absolute http:// or https:// URL (an explicit scheme is always honored). host:port A schemeless host:port, defaulted to http:// (e.g. localhost:5173, box.ts.net:3000). The explicit port marks a dev/infra server, which is http far more often than not. :<port> Sugar for http://localhost:<port> (e.g. :5173). surface:<ref> A terminal Surface handle (surface:N, surface:self, surface:focused, or a stable id). Dormouse scans that terminal's listening ports and opens http://localhost:<port>/; it fails if the terminal owns zero or multiple ports.

FLAGS

[--json]Print JSON output.
[--minimize]Create or replace the surface minimized.
[--surface]Surface to replace or split from.
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

ARGUMENTS

targetURL, host:port, :port, or surface handle to open.

Text output:

  created surface:3  "http://localhost:5173"
  replaced surface:1  "http://localhost:5173"

JSON output:

  {
    "status": "created",
    "surface_id": "pane-abc",
    "surface_ref": "surface:3",
    "url": "http://localhost:5173",
    "minimized": false
  }
Exact dor iframe --help output
USAGE
  dor iframe [--json] [--minimize] [--surface id|ref] <target>
  dor iframe --help

Opens a target in a high-fidelity iframe surface for human inspection.

If the caller surface is an untouched terminal, Dormouse replaces that terminal with the iframe. Otherwise Dormouse creates a split next to the caller/focused surface.

The target is one of:
  <url>          An absolute http:// or https:// URL (an explicit scheme is
                 always honored).
  host:port      A schemeless host:port, defaulted to http:// (e.g.
                 localhost:5173, box.ts.net:3000). The explicit port marks a
                 dev/infra server, which is http far more often than not.
  :<port>        Sugar for http://localhost:<port> (e.g. :5173).
  surface:<ref>  A terminal Surface handle (surface:N, surface:self,
                 surface:focused, or a stable id). Dormouse scans that terminal's
                 listening ports and opens http://localhost:<port>/; it fails if
                 the terminal owns zero or multiple ports.

Text output:
  created surface:3  "http://localhost:5173"
  replaced surface:1  "http://localhost:5173"

JSON output:
  {
    "status": "created",
    "surface_id": "pane-abc",
    "surface_ref": "surface:3",
    "url": "http://localhost:5173",
    "minimized": false
  }

FLAGS
     [--json]      Print JSON output.
     [--minimize]  Create or replace the surface minimized.
     [--surface]   Surface to replace or split from.
  -h  --help       Print help information and exit
      --           All subsequent inputs should be interpreted as arguments

ARGUMENTS
  target  URL, host:port, :port, or surface handle to open.

dor agent-browser

dor agent-browser --help

dor agent-browser [--key name|--session name|--surface handle] [args...]
dor agent-browser --help

Forwards all arguments verbatim to your own agent-browser binary and binds the session to a Dormouse browser surface.

dor intercepts exactly three mutually exclusive identity flags: --key <name> Managed, workspace-scoped browser identity (default "default"). Maps to agent-browser session dormouse.1.<name>. --session <name> Attach to a raw agent-browser session by its literal name. --surface <handle> Drive the browser Surface a handle names (surface:N, surface:focused, a stable id, title:<title>). dor asks the host which agent-browser session that Surface is bound to, which is the only way to address a GUI-spawned session.

Everything else — subcommands, flags, selectors — is agent-browser's own command surface. The binary is resolved from PATH (override with DORMOUSE_AGENT_BROWSER_BIN) and is never bundled; install it with: npm i -g agent-browser

After a successful command, dor opens (or reuses) the browser surface bound to the session: one session is always exactly one surface.

In an "open" command, dor also resolves a Dormouse target in place of a URL: a schemeless host:port (and the ":<port>" localhost shorthand) defaults to http:// rather than agent-browser's https://, and a terminal Surface handle (surface:N, surface:self, surface:focused, or a stable id) resolves to the dev-server URL that terminal owns via the host port scan.

FLAGS

[--key]Workspace-scoped browser key (default "default").
[--session]Raw agent-browser session name (mutually exclusive with --key/--surface).
[--surface]Surface handle whose bound session to drive (mutually exclusive with --key/--session).
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

ARGUMENTS

args...Arguments forwarded verbatim to agent-browser.

Examples:

  dor ab open http://localhost:5173        # key "default"
  dor ab open localhost:5173                # → http://localhost:5173/
  dor ab open :5173                         # → http://localhost:5173/
  dor ab open surface:3                     # open the port terminal surface:3 owns
  dor ab --key storybook open http://localhost:6006
  dor ab click @e3                          # drives key "default"
  dor ab --key storybook reload             # drives key "storybook"
  dor ab --surface surface:4 click @e3      # drives whatever surface:4 is bound to
Exact dor agent-browser --help output
USAGE
  dor agent-browser [--key name|--session name|--surface handle] [args...]
  dor agent-browser --help

Forwards all arguments verbatim to your own agent-browser binary and binds the session to a Dormouse browser surface.

dor intercepts exactly three mutually exclusive identity flags:
  --key <name>       Managed, workspace-scoped browser identity (default "default").
                     Maps to agent-browser session dormouse.1.<name>.
  --session <name>   Attach to a raw agent-browser session by its literal name.
  --surface <handle> Drive the browser Surface a handle names (surface:N,
                     surface:focused, a stable id, title:<title>). dor asks the
                     host which agent-browser session that Surface is bound to,
                     which is the only way to address a GUI-spawned session.

Everything else — subcommands, flags, selectors — is agent-browser's own
command surface. The binary is resolved from PATH (override with
DORMOUSE_AGENT_BROWSER_BIN) and is never bundled; install it with:
  npm i -g agent-browser

After a successful command, dor opens (or reuses) the browser surface bound to
the session: one session is always exactly one surface.

In an "open" command, dor also resolves a Dormouse target in place of a URL:
a schemeless host:port (and the ":<port>" localhost shorthand) defaults to
http:// rather than agent-browser's https://, and a terminal Surface handle
(surface:N, surface:self, surface:focused, or a stable id) resolves to the
dev-server URL that terminal owns via the host port scan.

Examples:
  dor ab open http://localhost:5173        # key "default"
  dor ab open localhost:5173                # → http://localhost:5173/
  dor ab open :5173                         # → http://localhost:5173/
  dor ab open surface:3                     # open the port terminal surface:3 owns
  dor ab --key storybook open http://localhost:6006
  dor ab click @e3                          # drives key "default"
  dor ab --key storybook reload             # drives key "storybook"
  dor ab --surface surface:4 click @e3      # drives whatever surface:4 is bound to

FLAGS
     [--key]      Workspace-scoped browser key (default "default").
     [--session]  Raw agent-browser session name (mutually exclusive with --key/--surface).
     [--surface]  Surface handle whose bound session to drive (mutually exclusive with --key/--session).
  -h  --help      Print help information and exit
      --          All subsequent inputs should be interpreted as arguments

ARGUMENTS
  args...  Arguments forwarded verbatim to agent-browser.

dor list

dor list --help

dor list [--kind terminal|browser] [--view paned|zoomed|minimized] [--command text] [--cwd path] [--port number] [--ports] [--json] [--id-format refs|ids|both]
dor list --help

Lists every Surface in the current Workspace — terminals and browser Surfaces, including minimized ones (view "minimized").

Text output prints one row per Surface: a * marks the focused Surface, then the handle, kind, render mode ("-" for terminals), view, location (cwd for terminals, URL for browser Surfaces), and title. Trailing tags: (you) for the calling terminal, [ringing], [todo], [awaited] while a dor await is parked on it, and listening ports with --ports.

--ports adds each terminal's listening TCP ports. The host shells out per pane (lsof / PowerShell), so it is opt-in; remote sessions report none.

--port <number> filters to terminal Surfaces listening on that port. It implies the same opt-in port scan as --ports, includes port details in JSON, and shows port tags in text output.

Filters are ANDed. --command is an exact match against the running command reported by shell integration. --cwd resolves to an absolute path like dor ensure --cwd, relative to the invoking shell's PWD when available.

JSON output (--json) always includes both stable ids and refs, and each row carries has_terminal (a PTY) and has_browser (a browser renderer) — gate on those, not on kind, so a Surface that has both still matches. It adds top-level caller_surface_ref/caller_surface_id and focused_surface_ref/focused_surface_id — the calling and focused Surfaces, null when neither is in the list — plus workspace_ref, window_ref, and a host block (app, workspace, cli_js_path, node_path): the identity dump dor identify used to print.

FLAGS

[--command]Exact running command to match.
[--cwd]Working directory to match.
[--id-format]Handle format for text output.
[--json]Print JSON output.
[--kind]Surface kind to show.
[--port]Show terminal Surfaces listening on this TCP port.
[--ports]Include each terminal's listening ports.
[--view]Surface view to show.
-h --helpPrint help information and exit
--All subsequent inputs should be interpreted as arguments

Text output:

  * surface:1  terminal  -              paned  ~/projects/site  pnpm dev  :5173
Exact dor list --help output
USAGE
  dor list [--kind terminal|browser] [--view paned|zoomed|minimized] [--command text] [--cwd path] [--port number] [--ports] [--json] [--id-format refs|ids|both]
  dor list --help

Lists every Surface in the current Workspace — terminals and browser Surfaces, including minimized ones (view "minimized").

Text output prints one row per Surface: a * marks the focused Surface, then the handle, kind, render mode ("-" for terminals), view, location (cwd for terminals, URL for browser Surfaces), and title. Trailing tags: (you) for the calling terminal, [ringing], [todo], [awaited] while a dor await is parked on it, and listening ports with --ports.

--ports adds each terminal's listening TCP ports. The host shells out per pane (lsof / PowerShell), so it is opt-in; remote sessions report none.

--port <number> filters to terminal Surfaces listening on that port. It implies the same opt-in port scan as --ports, includes port details in JSON, and shows port tags in text output.

Filters are ANDed. --command is an exact match against the running command reported by shell integration. --cwd resolves to an absolute path like dor ensure --cwd, relative to the invoking shell's PWD when available.

JSON output (--json) always includes both stable ids and refs, and each row carries has_terminal (a PTY) and has_browser (a browser renderer) — gate on those, not on kind, so a Surface that has both still matches. It adds top-level caller_surface_ref/caller_surface_id and focused_surface_ref/focused_surface_id — the calling and focused Surfaces, null when neither is in the list — plus workspace_ref, window_ref, and a host block (app, workspace, cli_js_path, node_path): the identity dump dor identify used to print.

Text output:
  * surface:1  terminal  -              paned  ~/projects/site  pnpm dev  :5173

FLAGS
     [--command]    Exact running command to match.
     [--cwd]        Working directory to match.
     [--id-format]  Handle format for text output.
     [--json]       Print JSON output.
     [--kind]       Surface kind to show.
     [--port]       Show terminal Surfaces listening on this TCP port.
     [--ports]      Include each terminal's listening ports.
     [--view]       Surface view to show.
  -h  --help        Print help information and exit
      --            All subsequent inputs should be interpreted as arguments