| name | controlling-shepherd |
| description | Use when running inside a Shepherd terminal pane and you need to drive the terminal itself — spawn or command other panes/agents, split/focus/zoom/close panes, create/switch/rename workspaces or tabs, read another pane's output, change Shepherd config, or orchestrate parallel agents across panes. |
Controlling Shepherd
Overview
Shepherd is an agent-native macOS terminal. From inside a pane you can drive the
whole app with the shepherd CLI, which speaks to the running app over a
local unix socket. This lets you spawn helper panes, command other agents, read
their output, and reconfigure the terminal — without the user touching the
keyboard.
First: confirm the channel
shepherd ping
If shepherd is missing or ping hangs/fails, the control channel isn't
available in this pane (the running app may predate it, or $SHEPHERD_CTL_SOCK
is unset) — fall back to asking the user, don't guess.
Panes/tabs/workspaces are addressed by handles — p1/t1/ws1 from
shepherd ls; shepherd whoami gives your own. Raw UUIDs also work.
Quick reference
| Command | Does |
|---|
shepherd ls | workspace → tab → pane tree with handles + state |
shepherd whoami | your own handles: pane tab workspace |
shepherd state <p> | one pane's agent state (bare word) |
shepherd tab new [<ws>] [--cwd <dir>] | new tab, opened in --cwd; prints the new pane handle |
shepherd tab new [<ws>] --worktree <branch> | new tab in a fresh git worktree of the workspace's dir |
shepherd workspace hook get|set|clear <ws> [--file <path|-> | "<script>"] | the bash run after git worktree add |
shepherd pane split <p> [--down] | split right, or down; prints the new pane handle |
shepherd focus <p> / zoom <p> / pane close <p> [--force] | focus / zoom / close |
shepherd workspace new|rename <ws> <name>|switch <ws>|rm <ws> [--force] | workspace CRUD |
shepherd tab rename|switch|close <t> [--force|--archive] | tab ops |
shepherd tell <p> "text" [--no-enter] | type text (+Enter) into a pane |
shepherd tell <p> --file <path|-> [--no-enter] | same, text from a file (- = stdin) |
shepherd view <p> [--lines N] [--raw] | read a pane's output |
shepherd config get|set|list [key] [value] | config (theme, worktree-base, sleep.mode, serve.remote) |
shepherd wait <p> --state s[,s] [--timeout secs] | block until a state (also --any-attention) |
Output shapes
ls prints an indented tree; view prints text; config prints
key = value (backend) lines.
- Handle-returning verbs print one bare, scriptable token — capture with
$(...): tab new and pane split print the new pane handle,
workspace new the workspace handle, state the state word, and
whoami prints pane tab workspace (space-separated).
tell / focus / zoom / close print nothing on success (check the
exit code).
Running something in a pane
There is no inline-command split. Create the pane in the directory you want,
capture its handle, then tell it:
p=$(shepherd tab new --cwd ~/repo)
shepherd tell "$p" "tail -f /tmp/build.log"
Long text: tell pastes it
Typed newlines are Enter presses. A multi-line prompt typed into an agent
submits its first line and orphans the rest — so tell pastes anything
containing a newline instead of typing it, then sends one Enter at the end.
Nothing to opt into; it reads the text and decides. --file <path> (or - for
stdin) carries a brief too long or too quote-laden for an argument:
shepherd tell "$p" --file /tmp/brief.md
If a pane won't accept a paste, tell types the text as a fallback and exits
non-zero saying so — so a mangled prompt is always reported, never silent.
Orchestrating another agent
p=$(shepherd tab new --cwd "$(pwd)")
shepherd tell "$p" "claude"
shepherd wait "$p" --state idle --timeout 60
shepherd tell "$p" "run the test suite; report each failure with file:line, then stop"
shepherd wait "$p" --any-attention --timeout 1200
shepherd view "$p" --lines 120
To hand a new, independent session a whole task and walk away, use the
shepherd:handoff skill instead — it covers what the brief
must contain and how not to leave two agents fighting over one worktree.
view is target-aware: an agent pane returns its Claude session transcript
(no serve needed); a shell pane returns the ANSI-stripped output ring (only
when Serve to remote devices is on).
Common mistakes
- Inventing flags. No
--sock, no --column, no split -- <cmd>. Split axis
is --down (default is right), and --cwd exists on tab new only — a split
inherits its parent pane's directory.
- Skipping the boot wait. After
tell "$p" "… && claude", wait --state idle
before sending the real prompt, or it types into a bare shell.
wait timed out. It exits non-zero on timeout — re-wait for long jobs; a
pane that goes blocked returns early (a permission/plan prompt you can answer
by tell-ing it, or surface to the user).
- Destructive ops refuse.
pane close / tab close / workspace rm on live
work need --force (or --archive for a worktree tab).
Worktree tabs
tab new --worktree <branch> does what the sidebar's New Worktree Tab… does:
git worktree add under the workspace's directory (reusing <branch> if it exists,
else branching off origin's default), then a tab in it. It needs the workspace to
have a directory. It prints handles as soon as the tab exists — git is still
running, so the pane starts in a provisioning state and a git failure surfaces in the
app rather than in the exit status. wait "$p" --state shell before tell-ing it.
workspace hook is the bash that runs right after each git worktree add, cwd = the
new worktree, with WORKTREE_DIR / WORKTREE_SRC / WORKTREE_BRANCH /
WORKTREE_NAME / REPO_NAME in the environment — the place to link gitignored deps a
fresh worktree lacks. It is per-workspace app state, so it is not a config key,
and the workspace is always explicit. Pass a multi-line script by file:
shepherd workspace hook set ws1 --file ./worktree-hook.sh
shepherd workspace hook get ws1 > /tmp/hook.sh
v1 limits
--cwd is ignored on a mirror workspace; the host owns those directories.
--worktree and workspace hook are errors there, for the same reason.
- No
tell --raw keystrokes, no view --follow, no view --screen.
- Single running Shepherd (single-window).