| name | attyx |
| description | Control the Attyx terminal via IPC — manage splits, send input, read output, track and watch agent status, orchestrate panes. Use when the user asks to interact with terminal panes, run commands in splits, monitor AI agents running in panes, or coordinate multi-pane workflows. |
| allowed-tools | Bash |
| argument-hint | [action] [args...] |
Attyx Terminal IPC Skill
You are running inside Attyx, a terminal emulator with a full IPC interface. You can control it programmatically.
Identifying Panes — Stable IPC IDs
Every pane has a stable numeric ID that never changes once assigned, even when other panes are closed. IDs are monotonically increasing integers (1, 2, 3, ...).
How to find your own pane
Run attyx list splits — the pane marked with * is the active/focused pane (the one you're running in):
1 bash * 80x24 ← this is YOU (pane 1)
3 python 40x24 ← another pane (pane 3)
Or attyx list for the full tree with tab context:
1 bash *
1 bash * 80x24 ← YOU (pane 1)
3 python 40x24 ← another pane (pane 3)
2 vim
2 vim 80x24
Tracking newly created panes
When you create a tab or split, the command returns the new pane's ID:
id=$(attyx tab create)
id=$(attyx tab create --cmd htop)
id=$(attyx split v)
id=$(attyx split v --cmd python3)
Always capture this output so you can target the pane later without guessing:
attyx send-keys -p "$id" "print('hello'){Enter}"
attyx get-text -p "$id"
Waiting for Commands (--wait)
tab create and split support --wait to block until the spawned command exits (requires --cmd):
attyx tab create --cmd "make test" --wait
attyx split v --cmd "cargo build" --wait
The response is the process exit code (first byte) followed by captured stdout. Useful for scripting:
attyx run "make test" --wait && echo "Tests passed"
Don't confuse titles with identity
Multiple panes can have the same title (e.g. two bash panes). Never rely on title matching to find a specific pane. Always use IDs from attyx list or captured from creation.
Session Management
Sessions are independent workspaces, each with their own tabs and panes. They persist across window reconnects.
Creating Sessions
attyx session create
attyx session create ~/Projects/myapp
attyx session create ~/Projects/myapp "dev server"
attyx session create ~/Projects/myapp -b "build"
sid=$(attyx session create ~/Projects/myapp -b)
Session-Targeted Commands
Use -s/--session <id> to route any command to a specific session:
attyx -s 123 tab create
attyx -s 123 send-keys "hello" -p 2
attyx -s 123 get-text -p 5
attyx -s 123 list
When -s is omitted, commands target the currently attached session.
Other Session Commands
attyx session list
attyx session switch 2
attyx session rename "dev server"
attyx session rename 1 "dev server"
attyx session kill 3
Critical Rules
Always Pin Your Session
The user can switch sessions at any time. If you send commands without -s, they'll hit whatever session is currently focused — which may not be yours.
At the start of every interaction, discover your session and pane IDs and use them for all subsequent commands:
attyx list
attyx -s 1 split v --cmd htop
attyx -s 1 send-keys -p 3 "print('hi'){Enter}"
attyx -s 1 get-text -p 3
attyx -s 1 tab create
Never omit -s after the initial discovery. Even if you think you're still in the same session, always be explicit — the user may have switched focus between your commands.
Don't Close Yourself
Before closing a pane, use targeted close with --pane / -p:
attyx split close -p 3
attyx tab close 2
This closes the specified pane/tab without changing focus. Plain attyx split close (no target) closes the focused pane — which is YOU.
Named Keys — Use {Enter}, Not \n
send-keys supports {KeyName} syntax (case-insensitive) for all special keys:
attyx send-keys "ls -la{Enter}"
attyx send-keys "{Down}{Down}{Enter}"
attyx send-keys "{Up}{Enter}"
attyx send-keys "{Ctrl-c}"
attyx send-keys "{Ctrl-d}"
attyx send-keys "{Ctrl-z}"
attyx send-keys "{Tab}{Tab}"
attyx send-keys "{Escape}:wq{Enter}"
attyx send-keys "{F1}"
Full key reference:
| Key | Name(s) |
|---|
| Enter | {Enter}, {Return}, {CR} |
| Tab | {Tab} |
| Space | {Space} |
| Escape | {Escape}, {Esc} |
| Backspace | {Backspace}, {BS} |
| Delete | {Delete}, {Del} |
| Insert | {Insert}, {Ins} |
| Arrows | {Up}, {Down}, {Left}, {Right} |
| Page | {PgUp}, {PgDn}, {PageUp}, {PageDown} |
| Home/End | {Home}, {End} |
| Function | {F1} through {F12} |
| Ctrl+key | {Ctrl-a} through {Ctrl-z} |
Modifier combos — prefixes are combinable (Ctrl-, Shift-, Alt-, Super-):
| Combo | Example | Use case |
|---|
| Ctrl+Arrow | {Ctrl-Right} | Word jump in shells |
| Alt+letter | {Alt-a} | Alt shortcuts in TUIs |
| Shift+Tab | {Shift-Tab} | Reverse tab / backtab |
| Ctrl+Shift | {Ctrl-Shift-p} | Command palettes (CSI u) |
| Shift+F-key | {Shift-F5} | Modified function keys |
| Ctrl+Delete | {Ctrl-Delete} | Delete word forward |
C-style escapes (\r, \t, \xHH, \e) also work but named keys are preferred for clarity.
Navigating TUI Applications
When interacting with interactive programs (menus, prompts, fzf, editors, etc.):
- Read the screen first — use
attyx get-text -p <id> to see what's displayed
- Navigate with arrow keys —
{Up}, {Down} to move through lists/menus
- Select with Enter —
{Enter} to confirm a selection
- Type to filter — many TUIs support typing to search/filter
- Use Tab for completion —
{Tab} cycles through options in shells and some TUIs
- Cancel/back with Escape —
{Escape} to dismiss dialogs or go back
- Read again after each action — always
get-text to verify the result
Example: navigating a numbered list and selecting item 3:
attyx send-keys -p "$id" "3{Enter}"
Example: scrolling down in a TUI and selecting:
attyx send-keys -p "$id" "{Down}{Down}{Down}{Enter}"
output=$(attyx get-text -p "$id")
Example: searching in fzf-style interface:
attyx send-keys -p "$id" "search query"
sleep 0.5
attyx send-keys -p "$id" "{Enter}"
Example: vim/editor interaction:
attyx send-keys -p "$id" "ihello world{Escape}:wq{Enter}"
Reading Scrollback History — --lines / -n
By default get-text returns only the visible screen. To capture more (like tail -N over the pane's scrollback + screen), pass --lines N / -n N:
attyx get-text -n 100
attyx get-text -p 3 -n 500
attyx -s 1 get-text -p 5 -n 1000
The count is clamped to the pane's available scrollback depth. Use this when a long-running command's output has scrolled off-screen, or when you need to inspect history beyond the current viewport.
Incremental Capture — --since <cursor>
When babysitting a long-running pane (a build, a test loop, another agent), don't re-read the whole screen every poll. --since returns only the rows produced since your last read, so a quiet pane returns nothing. Each read prints the next cursor (an opaque token) to stderr; pass it back next time. An empty/omitted token (--since "") seeds: it returns the current screen and a starting cursor.
attyx get-text -p 3 --since "" 2>cur; cur=$(cut -d' ' -f2 <cur)
new=$(attyx get-text -p 3 --since "$cur" 2>c2); cur=$(cut -d' ' -f2 <c2)
The cleaner path for agents is --json, which returns everything in one object:
{ "cursor": "g3.l10581", "text": " CC parser.o\n", "truncated": false, "reset": false, "rows": 1 }
Feed cursor back as the next --since. truncated: true means output scrolled past the retained scrollback between reads (read more often, or raise --scrollback-lines). reset: true means the layout changed (resize, clear, or alt-screen) and text is a fresh baseline, not a delta. Semantics are append-only (new scrolled output) — for a full-screen TUI that redraws in place, use plain get-text instead. Cursors are per-pane; don't reuse one across panes.
Reading Output — Use --wait-stable
Instead of blind sleep N && attyx get-text, use --wait-stable to send keys and automatically wait for output to settle:
attyx send-keys --wait-stable "ls -la{Enter}"
attyx send-keys --wait-stable 500 "make build{Enter}"
attyx send-keys -p 3 --wait-stable "cargo test{Enter}"
--wait-stable [ms] sends the keys, then polls get-text every 50ms until screen content is unchanged for ms milliseconds (default 300). The final screen content is printed to stdout. Hard timeout at 30s.
For quick commands where you don't need the output, plain send-keys without --wait-stable is fine. Use --wait-stable when you need to read the result.
Pane Targeting (Preferred)
Almost all commands support --pane (-p) to target any pane by its stable ID:
attyx send-keys -p 3 "ls -la{Enter}"
attyx get-text -p 3
attyx get-text -p 3 -n 200
attyx split close -p 5
attyx split zoom -p 5
attyx split rotate -p 3
attyx tab close 3
attyx tab rename 2 "build logs"
Pane IDs are flat integers shown in attyx list output. This avoids focus juggling and is the recommended approach.
Focus Management (Legacy)
Without --pane, send-keys and get-text operate on the focused pane:
attyx focus <direction> to switch to it
- Do your
send-keys / get-text
- Focus back if needed
Tracking Agents — Status & Watching
Attyx tracks the run state of AI agents (Claude Code, Codex, etc.) running inside panes. An agent reports one of four states:
| State | Meaning |
|---|
idle | Parked, waiting for the next prompt |
working | Actively processing a request |
input | Blocked on you (a permission prompt or question) |
none | No agent running, or the agent's session ended |
Listing active agents — list agents
attyx list agents lists every pane currently running an agent (any state except none). Use --json for a machine-readable array:
attyx list agents
attyx list agents --json
Fields: pane_id (stable ID of the agent's pane — use for targeting), tab_id (stable ID of the agent's tab; in attyx a tab is identified by its focused pane's id — the same pane:N shown by attyx list — so for a single-pane tab tab_id == pane_id), session, pid (the agent's foreground process id; 0 when unknown, e.g. daemon-backed panes), state, message (the agent's latest status preview, may be empty), and usage (token/cost/context telemetry — see below). Default scope is the attached/local session.
usage object. Present on every record (possibly {} before the agent reports anything). Only known fields appear — an absent field means unknown, never zero, so don't treat a missing cost_usd as free. Fields: input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, reasoning_tokens (cumulative for the session), context_used / context_max (current context window), cost_usd, cost_is_estimate (true when attyx computed cost from a built-in price table because the agent didn't report one — Codex), and model. Coverage varies by agent (Claude/opencode/Pi report cost directly; Codex is estimated; Codex pre-Sep-2025 builds and some gaps report no usage at all). Without --json, list agents (and watch agents) print an aligned, human-readable table — columns PANE SESSION STATE MODEL IN OUT CTX COST MESSAGE, tokens humanized (1.2M), context as used/max, - for unknowns, with a colored ● status dot at a terminal. Color is automatic (plain when piped, so | grep stays clean); force with --color, disable with --no-color. Parse --json, not the table — the table is for humans and its layout/color may change.
A live table of the same data is available two ways: the in-window overlay (Cmd/Ctrl+Shift+A, or the agent_dashboard command — current window only), and the full-screen attyx dashboard CLI, which shows agents across all sessions and lets you jump to any of them. For a scriptable cross-session snapshot, attyx dashboard --once prints a plain-text table and exits. Add -s <id> to list agents to query any session's agents directly from the daemon — it works even when no window is attached to that session:
attyx -s 2 list agents
attyx -s 2 list agents --json
For per-session counts across all daemon sessions, use attyx list sessions.
Watching for changes — watch agents
attyx watch agents opens a long-lived stream: the live counterpart of list agents, emitting the same data as it changes. On connect it emits the current agents as a snapshot, then one update per change. It blocks until interrupted. Default output is the human table (like list agents); use --json for one NDJSON record per change — same shape as list agents --json, including the usage object — for scripting:
attyx watch agents
attyx watch agents --json | while read -r line; do
echo "$line" | grep -q '"state":"input"' && notify-send "Agent needs input"
done
Unlike list agents, the watch stream includes transitions to state:"none" so you can tell when an agent's session ends. Use watch agents instead of polling list agents in a loop — it's push-based and won't miss fast transitions.
Like list agents, the stream defaults to the attached/local session. Add -s <id> to watch a specific session straight from the daemon, regardless of which session a window is showing (or whether any window is attached):
attyx -s 2 watch agents
Watching a single agent — --pane / -p
To follow just one agent instead of all of them, pass its stable pane ID with -p. The snapshot and the live stream are both filtered to that pane:
attyx watch agents -p 3
attyx agent await -p 3 --state idle
The pane ID is the pane_id from attyx list agents (or the ID returned when you created the pane). 0/omitted means all agents.
Checking a single agent
To check one pane's agent without streaming, pass its stable pane ID:
attyx list agents -p 3
attyx list agents -p 3 --json
Driving another agent — agent send / agent await
To send a prompt to an agent in another pane and block until its turn finishes, use agent send --wait instead of hand-rolling send-keys + a watch loop + get-text. It pastes the prompt (multi-line safe), presses Enter, waits for the turn, and reports the outcome.
attyx agent send -p 3 "run the tests and fix any failures" --wait
attyx agent send -p 3 "summarize src/api" --wait --capture --json
attyx agent await -p 3 --state any
attyx agent read -p 3
attyx agent read -p 3 --offset 1
agent read returns an agent's message straight from its transcript file (structural, not a screen scrape) — use it to collect another agent's actual output instead of get-text. --offset n/-o n gives the n-th message back (0 = last). Works with -s <session> too. Only agents that report a transcript (Claude Code, Codex) are supported; others return a clear error. Over MCP it's the agent_read tool.
Outcomes (and exit codes): done (0) · needs_input (2) · timeout (3) · no_turn/ended (4). So attyx agent send -p 3 "build" --wait && attyx agent send -p 5 "deploy" --wait chains turns only on success. Add --tokens for the per-turn token/cost delta. Outcomes are honest: no_turn means the agent never started (wrong pane / it didn't accept the input), timeout means it's still working (the agent is never interrupted — we just stop waiting). Over MCP this is the agent_send tool. (Currently targets the attached session; -s background sessions are a follow-up.)
-p/--pane works on both list agents and watch agents; omit it for all agents.
Argument Handling
If the user provides arguments, interpret them as a natural language instruction. Remember to always use -s <session_id> (discovered via attyx list at start):
/attyx open a split with htop → attyx -s <sid> split v --cmd htop
/attyx send "hello" to the other pane → attyx -s <sid> send-keys -p <id> "hello{Enter}"
/attyx close the other pane → attyx -s <sid> split close -p <id>
/attyx what's on screen in the right pane → attyx -s <sid> get-text -p <id>
/attyx create a background session for ~/Projects/api → attyx session create ~/Projects/api -b
/attyx list sessions → attyx session list
/attyx create a tab in session 5 → attyx -s 5 tab create
/attyx which agents are running → attyx list agents
/attyx tell me when an agent needs input → attyx watch agents (filter for "state":"input")
/attyx watch the agent in pane 3 → attyx watch agents -p 3
If no arguments, ask the user what they'd like to do with the terminal.