Agents running inside programa (Claude Code, Codex, OpenCode, or anything else that reads Anthropic-style SKILL.md files) can drive the app itself, not just the shell inside their own pane — inspect the window/workspace/pane/surface hierarchy, split panes and run commands without stealing the user's focus, read output from a sibling pane, spawn a helper agent, and coordinate with it.
The skill is SKILL.md at the repo root. This page is the longer version — background, the install flow, and the full command reference the skill points at.
SKILL.md gets dropped automatically by the existing integration installers, so a normal programa claude install-integration / programa codex install-integration / programa opencode install-integration is enough — there's no separate skill-install step.
| Tool | Install command | Skill location |
|---|---|---|
| Claude Code | programa claude install-integration |
~/.claude/skills/programa/SKILL.md (or $CLAUDE_CONFIG_DIR/skills/programa/SKILL.md) |
| Codex | programa codex install-integration |
~/.agents/skills/programa/SKILL.md |
| OpenCode | programa opencode install-integration |
~/.config/opencode/skills/programa/SKILL.md (or $OPENCODE_CONFIG_DIR/skills/programa/SKILL.md) |
Inside a Programa pane, the claude wrapper also appends a short system prompt to every Claude Code session telling it to read this skill and prefer worktrees, race, review, and wait-surface where the skill says so, and passes the bundled programa-mcp server (see mcp-server.md). So a session uses these features without the user asking, as long as the skill is installed.
~/.claude/skills and ~/.agents/skills are also both read by OpenCode's own global skill discovery, so running any one of the three installers above already covers OpenCode for most setups — the OpenCode-specific install just makes it explicit and respects OPENCODE_CONFIG_DIR.
Uninstalling (programa claude uninstall-integration, programa codex uninstall-integration, programa opencode uninstall-integration) removes the matching copy the same way it already removes hooks/plugin files, and refuses to touch a file that isn't marked as programa-managed.
Every terminal surface programa creates already exports PROGRAMA_SURFACE_ID, PROGRAMA_WORKSPACE_ID, and PROGRAMA_SOCKET_PATH (see TerminalSurface.swift), and the programa CLI is already on PATH. An agent running in that pane has everything it needs to call the socket API — it just has no reason to know that unless something tells it. The skill is that something.
The first thing the skill does is check PROGRAMA_SURFACE_ID and PROGRAMA_SOCKET_PATH. If either is unset, it stops and reports that it isn't running inside programa — no socket call, no guessed path. This matters because the same SKILL.md gets installed globally (~/.claude/skills/...) and loaded by every session that tool runs, including ones in a plain Terminal.app window with no programa socket to talk to.
- When to use what: a table near the top maps situations to features, so an agent reaches for them unprompted: conflicting parallel work goes to a worktree (
programa worktree create, oragent_spawnwithneeds_isolation), competing attempts toprograma race, a finished diff toprograma review, long jobs to a split pluswait-surface, work the user should watch to a split oragent_spawn(naming the pane), a coordinated team to a suggestion that the user restart withprograma claude-teams, a blocking question from a tool without hooks to theagent_needs_inputMCP tool (orprograma rpc agent.needs_input), text for another agent's prompt to thesurface_send_pasteMCP tool, and a repeated pane arrangement toprograma layout. - Inspecting your surroundings —
programa tree(the hierarchy, with◀ active/◀ heremarkers), pluslist-workspaces/list-panes/list-pane-surfaces/identify/list-portsfor narrower queries. - Splitting and running without stealing focus —
new-split/new-pane/new-surfacecreate UI without moving the user's cursor;send/send-key/send-panel/send-key-panelrun commands in another pane the same way. Onlyfocus-pane,focus-window,focus-panel,select-workspace, and thenext/previous/last-windowtriad actually move focus — see the socket focus policy in the rootCLAUDE.md. - Reading a sibling pane —
read-screen(aliascapture-pane), with--scrollback/--linesfor history beyond the visible viewport.programa handoff --from <ref> [--lines <n>] [--note <text>] [--to <ref>]pastes a pane's last lines (default 200, max 1000) into a prompt as context without pressing Return; the command palette's "Paste Context From Pane…" does the same for the focused terminal. - Spawning and coordinating a helper agent — split,
senda command likeclaude ...into the new surface, then read its output and answer it the same way you'd talk to any other pane.set-statusandnotifyreport progress through the sidebar instead of a pane the user isn't looking at. - Worktrees:
programa worktree create <branch> [--base <ref>] [--layout <name>]opens a branch in its own worktree and workspace without taking focus;worktree listandworktree remove(never deletes the branch) manage them.worktree create --from-issue <number> [--agent <claude|opencode|codex>]reads a GitHub issue withgh, names the branchissue-<number>-<title-slug>, and can start an agent on the issue in the new workspace. The agent gets the issue through a prompt file in$TMPDIR/programa-issue-prompts, kept for 7 days.programa storage scan [--json]shows each worktree's size and why it is kept, plus caches grouped by category with sizes, item ids, automatic cleanup eligibility and blockers.programa storage clean [--dry-run] [--include-external] [--now] [--json]removes the merged, clean, idle worktrees that hold no ignored env files (never with--force, never deleting branches).--nowskips theworktrees.autoRemoveAfterHourswait, and--include-externalalso covers worktrees outsideworktrees.directory. Repeatable--path <dir>restricts worktree removal to the named directories or descendants. Cache cleanup requires--xcode,--android,--packages,--caches(all three), or repeatable--item <id>; item ids narrow chosen categories or select matching ids across categories if no category is given. Manual cleanup includes manual-only caches and rechecks blockers before deletion. Node modules and user data are excluded. The six-hour background pass cleans only eligible, unblocked automatic caches whenstorage.autoCleanCachesis on (default). - Racing:
programa race "<prompt>" [--n <count>] [--agent <claude|opencode|codex>] [--base <ref>] [--prefix <slug>] [--layout <name>]starts one agent per worktree on branches<prefix>/<index>. It only spawns them; the agent waits on each, compares the branches, merges the winner, and removes the rest. - Reviewing a diff:
programa review open [--workspace <ref>] [--mode uncommitted|branch] [--base-branch <ref>]opens the review panel beside a terminal without taking focus;review comment add <file> <line|start-end> <text>,review comment list, andreview send [--preamble <text>]send line comments into that terminal's agent. - Resuming an agent:
programa resume [--surface <ref>] [--session <id> [--provider <name>]] [--print] [--force]types the resume command for the last Claude Code, Codex or OpenCode session that ended in a pane, once that pane is back at its shell prompt. Seedocs/workspace-interface.md. - Layouts:
programa layout save <name>,layout apply <name>, andlayout listkeep named split arrangements (geometry and cwds, not running commands). - Waiting:
wait-surfacegives a server-owned blocking wait on a surface:--pattern <regex>resolves when new output matches,--exitwhen the process exits, and--agent-state <idle|working|blocked|any_change>when the agent in it reaches that state (thesurface.waitagent_statecondition, seedocs/socket-api.md), each with--timeout. If the surface closes first, the wait ends with theclosedoutcome.prompt-agentis built on the same condition to send a prompt and wait for the agent to go idle again. The tmux-compatiblewait-for/wait-for -Snamed-signal rendezvous covers two cooperating processes. - Authoring screen-detection manifests for an unsupported agent — programa's agent-state detection reads a pane's own lifecycle hooks when available (Claude Code, Codex, OpenCode), and otherwise falls back to regex-matching visible screen text against a manifest. For any other agent,
programa agent-detection scaffold <agent-id>captures the current screen and writes a starter manifest to~/.config/programa/agent-detection/<agent-id>.json; fill in itspatternsarrays, thenprograma agent-detection test <agent-id>to check them against the live screen.programa agent-detection listshows every loaded manifest (bundled + your overrides). - Reporting a normalized lifecycle event —
programa agent-event --event <event_type> [--provider <p>] [--session-id <id>] [--workspace <id|ref>] [--surface <id|ref>]reports one of the structured events documented indocs/plans/agent-events.md(session.started,turn.started,request.opened,user-input.requested,turn.completed,session.exited, and the rest) instead of a bareworking/blocked/idlestring. It's what the shipped Claude Code/Codex/OpenCode hooks call internally; use it directly only if you're wiring a new provider's hook or testing the event path by hand — reach forset-statusfor everything else. - Writing a recap — when the user asks for a summary of a change, write markdown to
.programa/recaps/<slug>.mdand open it withprograma recap open <slug>(programa recap listshows what's saved). The markdown panel renders mermaid diagrams, GitHub-style alerts, and:::comparebefore/after blocks, so the skill tells the agent to reach for those instead of plain prose when they fit. - Browser work — Aside (via its MCP server, or
aside "<task>"from the shell) handles previews, smoke tests and logged-in sites.programa aside install-mcpregisters Aside with Claude Code and Codex. Seedocs/aside-browser.md.
There's no automated test for "does an agent actually behave correctly" — this is prompt content, not code. Manually verify by starting a fresh Claude Code (or Codex/OpenCode) session inside a programa pane with the skill installed and asking it to open a split and tail a dev server log; it should do so via the programa CLI, and the user's focus should stay on the pane they were already in.
The skill only covers the commands relevant to agent coordination. For the full CLI surface (tmux-compat commands, hooks) run programa help, see aside-browser.md for browser work through Aside, or see docs/socket-api.md for the underlying socket API.