Control API

Command reference

All 64 commands of the agterm control API, with arguments and return values. Every one is reachable from the agtermctl CLI and from the local control socket.

For the narrative introduction — what the socket is, how to install the CLI, and worked recipes — see the agtermctl section of the docs.

Overview

agterm listens on a local unix-domain socket. Each connection carries one newline-delimited JSON request and receives one response, then closes. The scope is personal scripting — fire-and-forget commands. There is no scrollback streaming and no event subscription.

Socket resolution. With --socket omitted, agtermctl resolves the same rendezvous the app bound: <AGTERM_STATE_DIR>/agterm.sock, else ~/Library/Application Support/agterm/agterm.sock. A spawned shell also sees the bound path in $AGTERM_SOCKET; passing --socket "$AGTERM_SOCKET" is the safe explicit form.

Response shape. {"ok": true, "result": {…}} or {"ok": false, "error": "<message>"}. The process exit code is non-zero when ok is false. result carries one of: id (affected/new session, workspace, or window), text (session copy/text), exitCode (overlay result), count (search matches, keymap/config diagnostics), ratio (session resize), tree, or windows.

Options go after the subcommand. agtermctl session type "ls" --target active, never before it. Add --json to print the raw response object — without it, mutations print ok and tree / window list print a human listing. Use --json when you need to read ids or values back.

Addressing

--target defaults to active (the selected session, or the current workspace). It accepts a full UUID (case-insensitive) or a unique, git-style prefix. Zero matches gives notFound; an ambiguous prefix gives ambiguous, listing the candidates.

--window <id|prefix|active> (on session, workspace, tree, font, and notify commands) picks which window's tree to act on; the default is the frontmost. With it set, that window must be open; without it, an id/prefix session target is matched across all open windows. The window.* commands instead take the window selector as a positional argument, defaulting to active (frontmost). A window need not be open to be a window.* target — window select opens a closed one.

For an agent, active is the user's GUI-selected session, not yours. Your own shell is $AGTERM_SESSION_ID. Pass --target "$AGTERM_SESSION_ID" on any session-scoped command that must act on the session you run in — otherwise it hits whatever the user has selected.

tree

agtermctl tree [--json] [--window W]
tree

Print the workspace/session tree. This is the read side of most of the API — nearly every state-mutating command has a matching field here, so a script can record a value, change it, and restore it.

Session node: id, name, cwd, title (raw OSC terminal title, omitted when none), active, split, splitRatio, splitFocused, overlay, overlaySizePercent (a percent-mode overlay's floating-panel percent), overlayCols / overlayRows (a cells-mode overlay's requested grid), overlayColsApplied / overlayRowsApplied (the realized grid any floating overlay rendered after clamping), overlayAnchor (which of nine positions any open overlay anchors to, reported even for a full overlay), scratch, flagged, status, statusPane, statusBlink, statusColor, foreground / splitForeground (each pane's live foreground argv, omitted at the shell prompt or for a setuid program like top/sudo), background, restoreCommand / splitRestoreCommand (each pane's pinned restore override, omitted when none and an empty string when pinned to nothing), commandWait (a held --command session created with session new --wait; omitted otherwise), unseen, and canvasCols / canvasRows (the terminal content area — the overlay "canvas" — in whole cells at the base font, the coordinate system overlay open --cols/--rows land in, so a script can size a floating overlay as a fraction of the canvas; split-agnostic full height and full width. A floating overlay is inset by a uniform one-line-height safe-area margin, so a --cols canvasCols request clamps to the usable area — read overlayColsApplied/overlayRowsApplied back for the realized grid. Omitted when no surface is realized).

Workspace node: id, name, active, sessions, focused (the read side of workspace focus, distinct from active), and collapsed (the read side of workspace collapse/expand; true when collapsed, omitted when expanded).

Top level: idleMs (ms since last user input; live, so tree-only), autoFollowMs, sidebarVisible, sidebarMode, and quickVisible. All five are read-only projections of GUI state.

workspace

agtermctl workspace new [name] [--collapsed] [--window W]
workspace.new

Create a workspace. The name defaults to an auto-generated one. --collapsed creates it closed in the sidebar tree, so a script can fill it with session new --no-select without it opening. Returns result.id.

agtermctl workspace rename <name> [--target T] [--window W]
workspace.rename

Rename the target workspace.

agtermctl workspace delete [--target T] [--window W]
workspace.delete

Delete the target workspace. Keep-at-least-one: deleting the last workspace is an error. Unlike the GUI, nothing blocks on a confirm dialog.

agtermctl workspace select [--target T] [--window W]
workspace.select

Select the target workspace.

agtermctl workspace move --to up|down|top|bottom [--target T] [--window W]
workspace.move

Reorder the workspace among its siblings. A missing or invalid --to is an error.

--target active resolves to the current workspace, which with no selected session falls back to the last workspace — address a specific workspace by id to step the same one repeatedly.

agtermctl workspace focus [on|off|toggle] [--target T] [--window W]
workspace.focus

Collapse the sidebar tree to a single workspace's subtree, hiding the others, or restore the full tree. on focuses the target, off unfocuses it only when it is the currently focused one, and toggle (the default) flips. Per-window and persisted; orthogonal to sidebar mode. An unknown mode errors. Returns result.id.

While a workspace is focused, session go navigation is scoped to its sessions. An explicit session select of a session outside it auto-unfocuses. Read back via the workspace node's focused field.

agtermctl workspace collapse [--target T] [--window W]
workspace.collapse

Collapse a single workspace's subtree in the sidebar tree, hiding its sessions. The per-workspace counterpart of sidebar collapse (which collapses every workspace but the active one) — this targets exactly the addressed workspace. Idempotent and persisted. Returns result.id.

Read the open/closed state back via the workspace node's collapsed field (true when collapsed, omitted when expanded).

agtermctl workspace expand [--target T] [--window W]
workspace.expand

Expand a single workspace's subtree, showing its sessions — the inverse of workspace collapse and the per-workspace counterpart of sidebar expand. Idempotent and persisted. Returns result.id.

To toggle a workspace, read its collapsed field off tree first, then call expand or collapse.

session

agtermctl session new [--cwd DIR] [--workspace W | --workspace-name NAME [--create-workspace]] [--command CMD] [--wait] [--name NAME] [--after SID | --before SID] [--no-select] [--window W]
session.new

Create a session and focus it. --cwd sets the start directory (default $HOME). The destination workspace is addressed either by --workspace (id / prefix / active) or by --workspace-name (the sidebar label) — the latter errors when no workspace has that name, unless --create-workspace is also passed, which reuses or creates it idempotently. --name seeds the sidebar label. Returns result.id.

--after SID / --before SID place the new session directly after or before an anchor session instead of appending. The anchor carries its own workspace, so it names the destination itself — these are mutually exclusive with each other and with --workspace / --workspace-name. The headline case: session new --after active.

--command runs a program as the session's process instead of the login shell (no echoed command line; the session closes when it exits). It runs argv-style — tokenized with quotes respected, but no shell, so ;, &&, $VAR, redirects and globs are not interpreted. It also inherits the app's GUI PATH (the launchd default — no /opt/homebrew/bin), so a bare Homebrew binary fails with exit 127. Use an absolute path, or wrap it: --command "zsh -lc 'htop'". The command is persisted and re-runs on restore when Restore running commands on restart is enabled.

--no-select creates the session in the background: it is added to the sidebar but not selected or focused, leaving the current selection untouched (the new node is not active in tree — that flag is the read-back). Omit it for the default select-and-focus behavior.

--wait (only with --command, else an error) holds the session open after the command exits — the press-any-key prompt with the final output intact instead of closing — so a build, test, or deploy's last output (or an early failure) stays readable. It persists across restart, so a restored command session that re-runs its command holds again. Read it back on tree's commandWait.

agtermctl session duplicate [--target T] [--window W]
session.duplicate

Create a fresh session in the same workspace as the target, directly after it, rooted at the target's focused-pane working directory — then select and focus it. There are no other options: the target names both the destination workspace and the directory. Equivalent to session new --cwd <source cwd> --after <source> in one round-trip. Returns result.id.

Only the directory carries over. The duplicate is a plain login shell with the auto basename — it does not inherit the source's custom name, --command, split, scratch, status, flag, font size, or background. It is the control half of the sidebar row's Duplicate Session context-menu item (single-selection only). Read back from tree: no new field — the new session node appears directly after its source, carrying the source's focused-pane cwd (equal to the source node's tree.cwd unless the source is a split focused off its primary pane, where tree.cwd reports the primary).

agtermctl session close [--target T ...] [--window W]
session.close

Close the target session. Repeat --target to close a batch as one grouped undo when close grace is enabled, or immediately when it is disabled. Batch output reports the number of sessions actually closed.

agtermctl session select [--target T] [--window W]
session.select

Select the target session. Selecting one outside a focused workspace auto-unfocuses to reveal it.

agtermctl session rename <name> [--target T] [--window W]
session.rename

Set the session's custom sidebar label.

agtermctl session reveal [--target T] [--window W]
session.reveal

Select the target session's focused-pane working directory in Finder. Errors if the directory no longer exists.

agtermctl session move <workspace> | --to up|down|top|bottom | --after SID | --before SID [--target T ...] [--window W]
session.move

Three mutually-exclusive placement intents, exactly one required. A positional <workspace> relocates the session there (appending). --to reorders it within its own workspace. --after / --before place it directly after or before an anchor session — the anchor carries its own workspace, so cross-workspace placement falls out for free. Repeat --target with a workspace or --after / --before to move an ordered batch atomically; batch relative reorder via --to is not supported. Batch output reports the number of sessions actually moved.

agtermctl session go --to next|prev|first|last|next-attention|prev-attention [--window W]
session.go

Move the selection relative to the current one — there is no --target. It operates over the visible, filtered set: the flagged sessions in flagged mode, the focused workspace's sessions when one is focused, else all. next/prev wrap at the ends; next-attention / prev-attention step only through sessions needing attention (status blocked or completed), also wrapping. Returns the newly selected result.id.

The attention variants only step the selection; unlike the GUI attention-nav they do not themselves move focus into a tagged pane.

agtermctl session type <text> [--stdin] [--select] [--pane left|right|scratch] [--target T] [--window W]
session.type

Inject text as real keystrokes — printable runs plus a Return for each newline, with no bracketed-paste markers. So a trailing newline submits the command. --stdin reads the text from stdin instead of the argument. --select selects and realizes a never-shown session first (the main pane only); any realized session is normally typable without it.

--pane left is the main pane (the default), right the split pane, and scratch the scratch terminal even while hidden. Note the shell quoting: a literal \n inside plain single quotes reaches the CLI as two characters — use $'make test\n' or pipe a real newline via --stdin.

agtermctl session copy [--target T] [--window W]
session.copy

Returns result.text with the session's current selection. It does not touch the system clipboard — pipe the returned text into another session type. Selection is surface state independent of focus, so any realized session can be read. No or empty selection gives a no selection error.

agtermctl session paste [--target T] [--window W]
session.paste

Paste the system clipboard into the session's main pane — the socket analogue of ⌘V / Edit ▸ Paste. It runs libghostty's paste_from_clipboard as a bracketed paste with no prompt, so the text lands at the prompt without auto-submitting.

Read it back with session text. A never-shown session gives session not realized.

agtermctl session select-all [--target T] [--window W]
session.selectall

Select the session's entire terminal buffer (main pane) — the socket analogue of ⌘A / Edit ▸ Select All, running libghostty's select_all.

Read the resulting selection back with session copy. A never-shown session gives session not realized.

agtermctl session text [--all] [--lines N] [--pane left|right|scratch] [--target T] [--window W]
session.text

Returns result.text with the terminal buffer as plain text (no ANSI or color). By default it reads the visible screen of the on-screen pane. --all adds scrollback; --lines N keeps only the last N content lines. The two are mutually exclusive and N must be greater than 0 (enforced server-side too).

A genuinely blank screen is not an error — it returns ok with an empty string, unlike session copy's no selection. A failed read is an error (failed to read surface buffer). Plain text only; there is no --ansi.

agtermctl session search [needle] [--next | --prev | --close] [--target T] [--window W]
session.search

Search the session's live scrollback. It selects the target first, so the search bar and match highlights render. With a needle it sets the query (opening the bar if needed); with no needle and no flag it just opens an empty bar. The three flags are mutually exclusive. Returns result.count (total matches) and result.text (the counter string — "N of M", "M matches", or "no matches").

The count settles asynchronously, so the command waits briefly for it.

agtermctl session split [on|off|toggle] [--target T] [--window W]
session.split

A side-by-side second shell in the same session. off hides it but keeps the shell alive (mirroring ⌘D); the pane's surface is torn down only when its own shell exits. Idempotent; an unknown mode errors.

agtermctl session scratch [on|off|toggle] [--command CMD] [--target T] [--window W]
session.scratch

A third, full-coverage shell that renders like a full overlay but behaves like the split. off hides it keep-alive; typing exit closes it and the next on spawns a fresh shell. on selects the target first. Not persisted; an unknown mode errors.

--command (only when showing) runs a program instead of a login shell — argv-style with the same GUI-PATH exit-127 caveat as session new --command, and run-once. A scratch is expendable, so passing --command while one is open respawns it.

agtermctl session focus [left|right|other] [--target T] [--window W]
session.focus

Move keyboard focus between the two split panes; other toggles and is the default. Errors when the session has no split. It works whether the split is shown side-by-side or hidden — when hidden, focusing a pane swaps which one shows maximized. Read back via the session node's splitFocused.

agtermctl session resize (--split-ratio R | --grow-left D | --grow-right D) [--target T] [--window W]
session.resize

Move the split divider. Provide exactly one form: --split-ratio sets the absolute left-pane fraction (0–1); --grow-left D / --grow-right D nudge it by the fraction D. The result is clamped to 0.05–0.95 and persisted. Returns the applied fraction as result.ratio. Errors when the session has no split.

Control-native: the divider is otherwise mouse-drag only, with no GUI, menu, or keymap action — bind a key by mapping a command "agtermctl session resize …" custom action. Resizing a hidden split updates the stored fraction, applied when it is next shown.

agtermctl session status <idle|active|completed|blocked> [--blink] [--auto-reset] [--sound NAME] [--color #rrggbb] [--pane left|right|scratch] [--pane-id TOKEN] [--target T] [--window W]
session.status

Set the sidebar agent-status glyph. Setting a non-idle status is for agents and hooks; idle clears it (also available in the GUI). An unknown state errors. --blink pulses the glyph; --auto-reset clears it back to idle once the session is visited (a one-shot completion flash).

--sound plays a one-shot sound: default or a system sound name (Basso, Glass, Ping, … plus any custom sound in ~/Library/Sounds); an unknown name errors. Without it, a blocked status plays the user's configured Blocked sound, if any. --color #rrggbb overrides the glyph tint for this call only; the next status set without it reverts.

--pane (default left) records which pane set the status. It makes keystroke-clear pane-scoped — a status set from a background pane survives typing in a different pane — and it makes any user-initiated GUI selection reveal and focus the tagged pane. An agent running in a split or scratch should set its own pane. Read back as the session node's statusPane, statusBlink, and statusColor. --pane-id is the surface's stable spawn token (the shell's $AGTERM_PANE_ID), forwarded automatically by the agent-status hook; when it resolves it overrides --pane, so a status from a promoted-then-re-split pane lands on its current slot. Scripts leave it to the hook.

agtermctl session flag [on|off|toggle|clear] [--target T] [--window W]
session.flag

Flag or unflag a session for the flagged working-set view — a durable, persisted membership. on/off/toggle act on the target and are idempotent; clear ignores the target and unflags every session in the window. Unknown mode errors. Pair with sidebar mode flagged. Read back via the node's flagged field.

agtermctl session seen [--target T] [--window W]
session.seen

Clear the session's unseen-notification badge without changing the selection, focus, or agent status — the focus-free counterpart to notify. Idempotent. Read the current count from the node's unseen field.

Lets an orchestrator acknowledge a driven session's notifications over the socket, keeping the badge a real attention signal on the sessions a human tends.

agtermctl session background image <path> [--opacity F] [--fit contain|cover|stretch|none] [--position P] [--repeat]
agtermctl session background text <text> [--color #rrggbb] [--opacity F] [--fit …] [--position …]
agtermctl session background color <#rrggbb>
agtermctl session background clear
session.background

Set or clear a per-session background composited behind the terminal grid. Persisted, so it survives a relaunch. All four forms accept [--target T] [--window W].

image — PNG or JPEG only; libghostty auto-fits it and re-fits on resize. --opacity is 0.0–1.0 (default 1.0), --fit defaults to contain, --position is center or an edge/corner anchor, and --repeat tiles. text — rasterizes a word or two (capped at 256 characters); --color defaults to the terminal foreground.

color — a solid terminal background color, taking no opacity: it is drawn at the Settings window translucency, so it honors your opacity and blur. An image/text watermark instead forces the pane opaque. Read the current spec back from the node's background object.

agtermctl session restore (<command> | --none | --clear) [--pane left|right] [--pane-id TOKEN] [--target T] [--window W]
session.restore

Pin the command a pane re-runs on the next launch, overriding the captured foreground. Provide exactly one form: a <command> shell line to pin, --none to pin nothing (the pane restores a plain shell, suppressing the captured command), or --clear to drop the override and go back to auto-capture. Read back as the session node's restoreCommand (main pane) or splitRestoreCommand (split pane).

The override is written now and consumed on the next launch — it never touches the running session — and it is sticky: it fires again on every restart until cleared. It wins over the session's own session new --command as well as the captured foreground — a pinned line (or --none) suppresses it, so a restored command session no longer takes the exec path or its --wait close-on-exit behavior. It is gated on the Restore running commands on restart setting (a pinned command while the setting is off succeeds with a note that nothing will run; --none/--clear get no note, since their outcome is delivered either way) but bypasses restore-denylist.conf, since it names its command deliberately. A split hidden at quit is not restored, so its pin is dropped on that launch rather than left to fire into a later manual split. It exists for non-idempotent commands like claude --resume … --fork-session: a SessionStart hook can rewrite it to the live session id on every start so the next restart reattaches instead of forking.

--pane (default left) picks the pane; right needs a split, and scratch is rejected (the scratch is never restored). --pane-id (the shell's $AGTERM_PANE_ID) resolves the pane's live slot; unlike session status, a token that does not resolve is an error unless --pane is also given as the fallback. The pinned value is shell code stored in the window's state file and readable via tree, so it must not carry secrets. Not to be confused with restore clear, which is app-global and clears every session's captured command.

session overlay

An ephemeral terminal running one program on top of a session. It closes when the program exits.

agtermctl session overlay open <command> [--cwd DIR] [--wait] [--block] [--size-percent N | --cols N --rows M] [--anchor POS] [--background-color #rrggbb] [--follow] [--target T] [--window W]
session.overlay.open

Full-size by default, hiding the session. Make it a floating framed panel — the session visible behind — with --size-percent N (1–100 of the pane) or --cols N --rows M (an exact terminal grid, both required). Both are adaptive: a --cols/--rows request larger than the pane clamps to the whole cells that fit (a --size-percent panel is a fraction of the pane, never larger), and the realized grid reads back on tree as overlayColsApplied/overlayRowsApplied. An out-of-range --size-percent is a hard error (no longer silently clamped on open). Returns the overlay's result.id. --background-color gives the overlay pane its own solid color, independent of the session's.

--anchor POS parks a floating panel at one of nine positions — top-left, top, top-right, left, center (default), right, bottom-left, bottom, bottom-right — inside a uniform safe-area margin of one line-height on all four sides (never flush with any border; symmetric and anchor-independent, so a full-width band is inset left/right exactly like the top). It requires a floating size; on a full-pane overlay it errors.

It does not switch the active session by default — both variants open on --target and run in the background. Pass --follow to select the target too. An automated caller should pass --target "$AGTERM_SESSION_ID", or a blocking full-pane overlay lands on whatever session the user has selected.

--wait keeps the overlay open after the command exits (press a key to close). --block waits for the command and makes agtermctl exit with its status — it cannot combine with --wait. The program's output is its own concern; the control channel does not capture stdout.

Unlike session new --command, the overlay command runs through sh -c, so shell operators do work — but it still inherits the app's GUI PATH, so a bare Homebrew binary fails with exit 127 (the overlay flashes open then vanishes). Give an absolute path or wrap in "zsh -lc '…'".

agtermctl session overlay resize [--size-percent N | --cols N --rows M | --full] [--anchor POS] [--target T] [--window W]
session.overlay.resize

Resize and/or re-anchor an already-open overlay in place. Give at most one size mode — --size-percent N (1–100) or --cols N --rows M (floating), or --full — and/or --anchor POS; at least one is required. --anchor alone re-anchors keeping the current size; a size mode alone keeps the anchor. The program keeps running across the resize — it is a layout re-flow, never a re-spawn. Errors no overlay when none is open.

--full cannot be combined with --anchor, but a --full round-trip preserves the anchor. Record the node's overlaySizePercent (or overlayCols/overlayRows) and overlayAnchor first to restore the exact size and position after a zoom to --full.

agtermctl session overlay close [--target T] [--window W]
session.overlay.close

Close and destroy the overlay.

agtermctl session overlay result [--target T] [--window W]
session.overlay.result

Returns result.exitCode once the overlay has closed. Errors still running while it is up, and no result if none ran.

window

These take the window selector as a positional argument (default active, the frontmost). A window need not be open to be a target.

agtermctl window new [name]
window.new

Create and open a window. Returns result.id.

agtermctl window list
window.list

Returns result.windows, each with id, name, open, active, autoFollowMs, sidebarVisible, geometry ({x, y, width, height, display}, the read side of window move/resize, in the same units they take), plus fullscreen and zoomed. The last three are omitted for a closed window.

geometry/fullscreen/zoomed stay current across hand-drags and GUI toggles. Unlike tree, this does not carry idleMs — a live metric would freeze in the cache.

agtermctl window select <id>
window.select

Raise the window if open, else open it.

agtermctl window close <id>
window.close

Close the on-screen window; the bundle is kept, so window select reopens it.

agtermctl window rename <id> <name>
window.rename

Rename the window.

agtermctl window delete <id>
window.delete

Delete the window bundle entirely. Keep-at-least-one: deleting the last errors.

agtermctl window resize <id> --width W --height H
window.resize

Frame size in points. The window must be open. The size is clamped into the window's minimum and the display's visible frame, so an oversized request is bounded rather than applied verbatim. Control-native (the title bar already drags-to-resize).

agtermctl window move <id> --x X --y Y [--display N]
window.move

Top-left position in points relative to display N (default the window's current display; y measured from the display top). The window must be open. The origin is clamped so an off-screen request keeps a grabbable strip on the target display. Control-native.

agtermctl window zoom <id>
window.zoom

Toggle between the normal frame and a maximized, fill-screen frame — not native full screen. A second call restores the prior frame. The window must be open. This is the control half of the double-click-on-header gesture. Read back via window list's zoomed.

agtermctl window fullscreen <id>
window.fullscreen

Toggle native macOS full screen — a separate Space with an auto-hidden menu bar. A second call exits. The window must be open. The control half of View ▸ Toggle Full Screen (⌃⌘F) and the green traffic-light button; distinct from zoom. Read back via window list's fullscreen.

surface zoom

A view mode that fills the window with one terminal surface. It never touches the macOS window frame — distinct from window zoom.

agtermctl surface zoom [show|hide|toggle] [--target surface:<id>:right | active | quick] [--window W]
surface.zoom

Fill the window with one terminal surface, hiding the sidebar and collapsing the title bar to a slim strip (traffic lights plus an exit button). Omit --target (or pass active) to zoom the active surface — the quick terminal if shown, else the active session's overlay, scratch, focused split, or primary pane. An explicit surface:<session-id>:<left|right|scratch|overlay> id (from tree's surfaces[].id) zooms that exact surface, including a hidden-but-alive split or scratch; quick addresses a quick-terminal zoom.

show is idempotent; hide exits and is idempotent too (an explicit id clears only that target and succeeds even if the surface has since vanished); toggle enters when unzoomed and exits when that surface is already zoomed. Zoom must not mutate split ratios, focus, sidebar state, or split/scratch visibility. Control half of ⌘⇧Return / View ▸ Toggle Terminal Zoom and the title-bar exit button.

Read the current zoom back from the tree's top-level zoomedSurface (the zoomed surface's control id, or quick; omitted when nothing is zoomed).

dashboard

A per-window, view-only grid of live terminal panes. Reciprocally exclusive with surface zoom: opening one closes the other.

agtermctl dashboard <ids…> [--mru] [--font-size N | --auto-size] [--close] [--window W]
dashboard

Open a grid of the named sessions' live panes, populate it from the window's most-recently-used sessions with --mru, or --close the open one. The cell unit is a session+pane: a non-split session is one cell, and a split session shows as two — its left/primary and right/split panes — so the 9-cell cap counts panes (laid out ceil(√n)). Positional ids are session addresses (id / unique prefix / active), deduped by resolved session; unresolved ids are dropped and any panes beyond 9 are trimmed, both reported in the response text. --mru is mutually exclusive with ids and --close, composes with the font flags and --window, and errors no recent sessions when the window has none.

View-only: no cell takes input. Once open the keyboard drives it — arrow keys move a highlight between cells, Enter jumps into the highlighted session and focuses that exact pane (then closes the grid), and Esc closes it. --font-size N sets an absolute cell font in points (finite, positive); --auto-size sizes cells relative to the Settings default font, shrinking as the grid grows; the two are mutually exclusive, and omitting both leaves each pane's own font untouched.

The GUI openers — ⌘⇧D, Navigate ▸ Dashboard, and the command palette's Dashboard entry — toggle the frontmost window's most-recently-used grid auto-sized (the dashboard --mru --auto-size equivalent; no separate control command). Read back from the tree's top-level dashboardMembers (the pane refs shown, in grid order — a split session appears as both <id>:left and <id>:right), dashboardHighlighted (the highlighted cell's pane ref), dashboardFontSize (the applied absolute size, omitted when untouched), and dashboardFontMode (auto/fixed/untouched).

quick

The frontmost window's quick terminal — a single scratch terminal at 90% of the window, not in the tree, whose shell stays alive across hides. All three are frontmost-window-only: no --target, --window, or --pane.

agtermctl quick [show|hide|toggle]
quick

Show, hide, or toggle it. Delta-computed, so it is idempotent. Errors no open window when none is open. Read its visibility back from the tree's top-level quickVisible.

agtermctl quick type <text> [--stdin]
quick.type

Inject literal keystrokes into the quick terminal — the twin of session type. It polls briefly for the surface, so quick show; quick type back-to-back is reliable. Typing into a shown-then-hidden quick terminal still works.

Errors: quick terminal not open (never shown), quick terminal not realized, no open window.

agtermctl quick text [--all] [--lines N]
quick.text

Print the quick-terminal buffer as plain text — the read-back for quick type. It does not touch the system clipboard. --all and --lines N are mutually exclusive. Polls for the surface like quick type.

notify

agtermctl notify <body> [--title T] [--target T] [--window W]
notify

Post a macOS desktop notification attributed to a session (default: the active session of the frontmost window). --title defaults to the session name. Clicking the banner reveals that session. It raises the session's unseen badge; clear it with session seen. Control-native.

For agentic attention — waiting on input, or a finished result — prefer session status. A notification is a one-shot banner with no lasting state, while a status is typed and persistent, and drives the attention list, the title-bar bell, and attention navigation. Keep notify for a one-off nudge.

font

agtermctl font inc|dec|reset [--target T] [--window W]
font.inc · font.dec · font.reset

Increase, decrease, or reset the font size on the target session's surface — three separate commands sharing one CLI subcommand. The per-session zoom is persisted. The GUI half is ⌘+ / ⌘− / ⌘0.

theme

App-global — no --window. The out-of-the-box default is the bundled agterm theme; a separate default ghostty entry means "no theme" — ghostty's own built-in colors.

agtermctl theme list
theme.list

Returns result.themes (the bundled names), result.theme (the current plain theme; absent means ghostty's built-in), and result.sync with result.light/result.dark. While syncing, result.theme is absent — the state rides the three sync fields.

agtermctl theme set [name] [--light NAME] [--dark NAME|none]
theme.set

Set and persist the terminal theme app-wide, per slot — the same change as Settings ▸ Appearance. A positional name (or --light, its alias) sets the light/single theme, keeping a dark theme if one is set. Omit the name for ghostty's built-in default — with a dark theme set, that clears both.

--dark NAME sets the dark theme and turns on appearance syncing: the terminal then tracks the macOS Light/Dark setting, applying the matching side automatically. --dark none clears it, stopping the tracking. The response always echoes the full state. An unknown name errors; a positional name combined with --light is a usage error. Over the socket this is the commit — there is no live preview.

keymap

agtermctl keymap reload
keymap.reload

Re-read and apply keymap.conf. Returns result.count — the number of parse diagnostics (0 is a clean reload). App-global; the same path as File ▸ Reload Keymap. See Customizing keys for the file format.

config

agtermctl config reload
config.reload

Re-read and apply the ghostty config. Returns result.count — the ghostty config-diagnostic count (0 is clean). App-global; the same path as File ▸ Reload Config.

The count spans all config sources, not just the agterm-scoped ghostty.conf — libghostty diagnostics do not record which file they came from — so do not read a non-zero count as proof that ghostty.conf is the culprit.

restore

agtermctl restore clear
restore.clear

Clear every session's saved captured foreground command and persist, so the next restart restores plain shells for those panes. App-global; prints ok.

It does not clear a session new --command session's own command — that is the durable creation identity and still re-runs on restore when the setting is on. This is the counterpart to the opt-in Restore running commands on restart setting.

Errors

Every failure comes back as {"ok": false, "error": "…"} with a non-zero exit code. An unknown command fails to decode and returns a structured error — never a crash.

notFound (target resolution) ambiguous (target resolution) no such session session not realized invalid split mode invalid scratch mode session has no split session has no scratch terminal no selection (copy) overlay already open no overlay still running (overlay) no result (overlay) invalid flag mode invalid fit invalid position invalid opacity invalid color text too long unsupported image (PNG or JPEG only) no such image file invalid background mode invalid sidebar mode invalid focus mode no open window quick terminal not open quick terminal not realized failed to read surface buffer window not open unknown theme: <name> unknown sound: <name> invalid color (expected #rrggbb) invalid restore mode (session restore) session.restore set requires a command command must not contain control characters command too long (max 1024 bytes) the scratch terminal is never restored unknown pane id: <token> failed to save the restore override --pane must be left, right, or scratch
← agterm.com
GitHub Issues Discussions