Skip to content
Logo

IPC Socket

Boo exposes a Unix domain socket at ~/.boo/boo.sock (also available as $BOO_SOCK in terminal sessions) for communication between child processes, plugins, and the app.

Protocol

Newline-delimited JSON. One request per line, one response per request. Long-lived connections can subscribe to push events.

Commands

CategoryCommands
Queryget_context, get_theme, get_settings, get_workspaces, list_themes, get_state, get_screen
Controlset_theme, toggle_sidebar, switch_workspace, new_tab, new_workspace, send_text, send_key, select_pane, select_tab
Panessplit_pane, close_pane, focus_pane, resize_pane, swap_pane, zoom_pane, equalize_splits, get_layout
Windowsnew_window, move_workspace_to_new_window, merge_all_windows
Agentsagent_event, agent_idle, agent_inbox, agent_jump, agent_respond, agent_timeline, new_agent_task, review_changes
Recipesrun_recipe, list_recipes
Processset_status, clear_status, list_status
Eventssubscribe, unsubscribe
Status Barstatusbar.set, statusbar.clear, statusbar.list
Plugin<namespace>.<action>

Examples

# Query current terminal context
echo '{"cmd":"get_context"}' | nc -U "$BOO_SOCK"
 
# Register as an AI agent
echo '{"cmd":"set_status","pid":'"$$"',"name":"claude","category":"ai"}' | nc -U "$BOO_SOCK"
 
# Send a command to the active terminal
echo '{"cmd":"send_text","text":"echo hello\n"}' | nc -U "$BOO_SOCK"
 
# Push a status bar segment
echo '{"cmd":"statusbar.set","id":"ci","text":"CI: passing","icon":"checkmark.circle","tint":"green"}' \
  | nc -U "$BOO_SOCK"

Workspaces, Tabs and Keys

Without a pane_id, commands go to the frontmost Boo window.

CommandArgumentsReply
get_workspacesworkspaces (index, id, name, path, is_active, pane_count)
get_stateworkspaces, panes of the active workspace with their tabs, agents, theme
list_themesthemes (names)
switch_workspaceindex or id
new_taboptional cwd (default: the workspace folder), command (run in the new shell), env (object of strings; BOO_* keys ignored); opens in the active panetab_id
new_workspaceoptional path (default: home)
new_windowwindows (count)
select_paneid of a pane in the active workspace
select_tabindex of a tab in the active pane
send_keykey: enter, tab, escape, backspace, up, down, left, right, ctrl_c, ctrl_d, ctrl_z or ctrl_l; goes to the active terminal
agent_idlepane_id: marks activity on that pane's tab, even when it is in front
run_recipename (file name in ~/.boo/recipes without .json; case-insensitive) or path; opens a recipe as a new workspaceworkspace_id, name; an unknown name's error lists the recipes
list_recipesrecipes (name, path, folder, null when the file is invalid)

Event Subscriptions

Keep the connection open after subscribe to receive push events:

EventData
cwd_changedpath, is_remote, pane_id
title_changedtitle, pane_id
process_changedname, category, pane_id, pid, metadata
remote_session_changedtype, host, active, pane_id
focus_changedpane_id
workspace_switchedworkspace_id
theme_changedname, is_dark
settings_changedtopic
cmd_startedcommand, pane_id
cmd_endedcommand, exit_code, duration, pane_id

Use "events": ["*"] to subscribe to all events.

send_text and get_screen

send_text writes text directly to the active terminal's PTY — identical to typing it. With pane_id it targets that pane, in any workspace of its window; with submit: true the text is pasted as one input and Return is pressed, which is how to send a prompt to an agent.

get_screen with pane_id and/or lines (max 5000) returns that pane's last lines of output, scrollback included, as text, plus title and cwd; with pane_id but no lines, the visible screen. Without either, it returns the visible screen of the active pane, plus cols, rows and a styled vt snapshot.

echo '{"cmd":"send_text","text":"cd ~/projects/myapp\n"}' | nc -U "$BOO_SOCK"
echo '{"cmd":"send_text","pane_id":"<id>","text":"npm test","submit":true}' | nc -U "$BOO_SOCK"
echo '{"cmd":"get_screen","pane_id":"<id>","lines":50}' | nc -U "$BOO_SOCK"

Pane Layout

Commands act on the active workspace of the frontmost Boo window. split_pane, close_pane and get_layout also take a pane_id: the command then goes to the window and workspace holding that pane, even in the background. focus_pane, resize_pane, swap_pane, zoom_pane and equalize_splits take a pane_id too, but only for a pane on screen; in a background workspace they fail with pane is in a background workspace; switch to it first. direction is left, right, up or down.

CommandArgumentsReply
split_panedirection (default right): side of the new pane; pane_id to split (default active); command to run in it; cwd; focus (default true)pane_id, started
close_panepane_id (default active); never the only paneactive_pane
focus_panedirection, or next / previous; pane_id alone focuses that pane, with a direction it moves from thereactive_pane
resize_panedirection, amount in points (default 10), pane_id
swap_panedirection, pane_id
zoom_panezoomed (true/false; omit to toggle), pane_idzoomed
equalize_splitsoptional pane_id
get_layoutpane_id: lay out that pane's workspacetree, panes, windows, workspace_visible
move_workspace_to_new_windowindex (default active)windows
merge_all_windowsmoves every window's workspaces into the active oneworkspaces

get_layout returns the split tree with ratios, each pane's on-screen frame (top-left origin, points) whether it is visible (hidden while another pane is zoomed), its terminal grid (columns, rows) and its tabs (id, title, type, active, cwd, process). Frames are left out for a background workspace. A pane split into a background workspace (started: false) gets its shell, and runs its command, when the workspace is next shown.

echo '{"cmd":"split_pane","direction":"down"}' | nc -U "$BOO_SOCK"
echo '{"cmd":"get_layout"}' | nc -U "$BOO_SOCK"

Agent Inbox

Boo keeps one list of coding agents across all windows: which are working, which wait for an answer, which finished. The status bar shows it; clicking lists every agent and jumps to its tab.

Claude Code feeds it automatically: on launch Boo registers ~/.boo/shell-integration/boo-claude-hook in ~/.claude/settings.json for UserPromptSubmit, PostToolUse, Notification, Stop and SessionEnd (only if that file already exists; your own hooks are kept). For Codex, add to ~/.codex/config.toml:

notify = ["~/.boo/shell-integration/boo-claude-hook", "codex"]

Other agents can report directly:

CommandArgumentsReply
agent_eventevent: working, needs-input, done, error or end; tab_id or pane_id ($BOO_TAB_ID / $BOO_PANE_ID); optional agent, message, tool, session_id, cwdstate
agent_inboxattention, items
agent_jumptab_id, or omit for the next agent waiting
agent_respondtab_id, response: approve (types Return) or deny (types Escape); optional updated_at from agent_inbox to refuse if the agent asked something newer

needs-input waits until the agent works again; done and error wait until you look at the tab. Entering either state sends a notification unless the tab is in front.

echo '{"cmd":"agent_event","pane_id":"'"$BOO_PANE_ID"'","event":"needs-input","agent":"aider","message":"Apply edits?"}' | nc -U "$BOO_SOCK"

Agent Timeline

File → Agent Timeline (or Show Timeline in the Agents sidebar and the status bar's agent menu) opens a tab with what a Claude Code session did, read from its transcript in ~/.claude/projects ($CLAUDE_CONFIG_DIR if set): each prompt with its tool calls, duration, tokens and cost, the reply, and the files edited. Calls repeated three or more times in a row fold into one row marked in the warning color, so runaway loops stand out; Loops & failures only hides the rest. The tab refreshes every few seconds while the session runs.

Cost is exact (Claude Code's own figure) once a session has ended; while it runs, Boo estimates it from token counts and public prices, shown with ≈. Subagent tokens count toward the total.

CommandArgumentsReply
agent_timelinetab_id (an inbox agent) or session_id; optional turns (default 10), open: true to show the tabcost, cost_exact, tokens, prompts, tool_calls, loops, files, last turns

Agent Tasks

File → New Agent Task… gives an agent its own checkout: Boo creates branch boo/<task> from the HEAD of the repository the active terminal is in (falling back to the workspace folder) in ~/.boo/worktrees/<repo>/<task>, opens it as a workspace and starts the agent with your first message. Several agents can work on one repository without touching each other.

Right-click a task's workspace for Merge Worktree… (git merge --no-ff into the branch checked out in the main repository; refuses with uncommitted changes, aborts on conflicts) or Discard Worktree…. Both can delete the worktree and branch and close the workspace.

File → Review Changes… (or Review Changes… in a task's context menu) opens a diff tab with everything the agent changed: for a task, all commits since it branched off plus uncommitted and untracked files; for any other repository, the changes since the last commit. Click a line to comment, then Send to Agent (⌘↩) pastes all comments as one numbered message into the workspace's agent terminal.

CommandArgumentsReply
new_agent_taskname and/or prompt; optional agent (claude, codex, opencode) and repo (default: active terminal's repo, else workspace)path, workspace_id
review_changesoptional workspace_id or pane_id (default: active workspace)—
echo '{"cmd":"new_agent_task","name":"fix login","prompt":"The login redirect loops, fix it"}' | nc -U "$BOO_SOCK"

Handing context to an agent

Terminal → Send to Agent (⌥⌘↩) pastes the selection, or else the output of the last command, into the prompt of the nearest agent, without pressing Return, and brings its tab to the front. The agent in the same workspace wins, then the most recently active one. The text arrives fenced, with a header naming the command, its exit code and the directory. Long output keeps its last 60,000 characters, where errors usually are.

Right-click a terminal for Send Selection to … and Send Output of “…” to …, with a submenu when several agents run. Dropping text or files onto an agent pane pastes them too (files as shell-escaped paths).

Last-command output needs shell integration: Boo cuts it out of the scrollback between the command line and the next prompt.

MCP Server

Boo is also an MCP server, so an agent running in a Boo terminal can arrange its own workspace: start a dev server or test watcher in a pane beside it and read the output later, type into other panes, start parallel agent tasks, or open the review for you. Boo (the installed app, not a bare development binary) writes a launcher to ~/.boo/shell-integration/boo-mcp on every start; register it once:

claude mcp add -s user boo -- ~/.boo/shell-integration/boo-mcp
codex mcp add boo -- ~/.boo/shell-integration/boo-mcp
ToolWhat it does
get_layoutPanes of the agent's workspace with tabs, cwd and running process; your_pane is the agent's own
split_paneNew pane beside the agent's (direction, command, cwd, pane_id); focus stays with you unless focus
read_paneLast lines (default 100) of a pane's output
send_textType into another pane, pressing Return unless submit is false
close_paneClose another pane
list_agentsThe agent inbox
new_agent_taskWorktree task on the agent's repository with a first prompt
run_recipeOpen a saved recipe by name as a new workspace
open_reviewReview tab for the agent's workspace
wait_for_eventsBlocks until an agent changes state, a task is spawned or finishes, a pane closes or an approval resolves (since, timeout)
agent_respondApprove, deny or answer a waiting agent by tab_id
focus_paneBring an agent's tab to the front
task_statusA task's commits, uncommitted changes, merge conflicts, and whether the main checkout is dirty
task_diffA task's changes (stat_only for the summary)
merge_taskMerge a task into its main checkout (cleanup removes the worktree)
discard_taskDelete a task's worktree and branch

The server (Boo --mcp) talks to the running app over $BOO_SOCK and defaults to the agent's pane through $BOO_PANE_ID, which every Boo terminal sets. It refuses to type into or close the agent's own pane.

Status Bar Segments

External processes can publish status bar segments. Tint accepts named colors (red, green, yellow, blue, orange, purple, accent) or #hex. Segments are auto-cleaned on disconnect.

Security

  • Socket I/O runs on a dedicated serial queue
  • Connecting processes are verified with LOCAL_PEERCRED
  • Registered PIDs are checked as descendants of the shell
  • Dead processes and disconnected clients are cleaned up automatically

Capability tokens

Every Boo terminal gets a random BOO_TOKEN next to BOO_PANE_ID. A command needs this token when it would give a process power it lacks in its own shell:

  • agent_respond
  • send_text or send_key into an agent or a remote session
  • close_pane on an agent pane
  • merging or discarding a task

Send the token as "token" in the request. The MCP server does this for you.

  • A normal terminal's token runs these commands directly.
  • The orchestrator's token puts them on an approval card, except writes to agents it started. Merge and discard always need a card. The reply is {"status":"pending","approval_id":…}.
  • Without a token, these commands are rejected. Everything else works without a token, so scripts keep working as long as they do not type into agents or remote sessions.

Tokens are kept in memory and change when Boo restarts. They catch mistakes and overreach by a model. They do not stop an attacker running as the same user, who can read another process's environment.