ワンクリックで
addressing
Selectors, refs, and targeted writes — the DOM-lite addressing model for nodes inside a pane
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Selectors, refs, and targeted writes — the DOM-lite addressing model for nodes inside a pane
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
agent-tui usage — spawn, snapshot, wait, interact with PTY apps via @eN refs
Drive AI CLIs (opencode, pi, codex, claude-code, …) — auth, streaming, tool use, sessions
Drive common TUI apps — htop, less, lazygit, tig, fzf, nano — for engine-correctness coverage
Verbs grouped by what you're trying to do (ask/edit/watch/run), not by capability surface
Open files, edit, save, search in vim/nvim with adapter-aware state
Drive bash/zsh shell sessions; detect prompt vs. running command via OSC 133
| name | addressing |
| description | Selectors, refs, and targeted writes — the DOM-lite addressing model for nodes inside a pane |
| allowed-tools | Bash(agent-tui:*) |
agent-tui exposes a pane's content as a tree of outline nodes.
Each node has a stable ref (like a DOM id), a role (like a
DOM tag), and child nodes. You address nodes with selectors (a
CSS-subset) and route writes with press --to <selector>.
If you know CSS and the DOM, you already know this skill.
outline (tree)
└── @vim role=root
├── @vim.mode role=mode value=insert
├── @vim.statusline role=statusline
├── @vim.cmdline role=cmdline focused=true (during : /)
└── @vim.buffer role=buffer focused=true (otherwise)
@vim.buffer are durable: same ref every frame
for as long as the node exists. Old @e1/@e2/… per-snapshot
refs are gone.[role=cmdline][focused], @vim.statusline, @tmux pane[%2].press --to '@tmux.pane[%2]' 'iX<esc>' lets the adapter translate
into the actual byte sequence (tmux prefix-q-2, then the keys).| You want | Selector |
|---|---|
| The focused buffer, wherever it is | [role=buffer][focused] |
| Vim's statusline | @vim.statusline |
| Vim's cmdline only while it's focused | @vim.cmdline[focused] |
| Any status node whose name contains "written" | [role=status][name~=/written/] |
| The second tmux pane (by stable id) | @tmux.pane[%2] |
| A buffer inside that pane | @tmux.pane[%2] > [role=buffer] |
| Only durable-bound refs (skip transient nodes) | [durable] |
Combinators:
@tmux [role=buffer] matches any
buffer anywhere below @tmux.> = direct child: @tmux > [role=pane] matches a pane that
is an immediate child of @tmux.Predicate operators (inside […]):
attr=value — exact (role=buffer)attr~=/regex/ — Rust regex (name~=/written/)attr^=prefix — prefix (name^=/work)attr$=suffix — suffix (name$=.txt)Attributes: role, name, value. Plus [focused] /
[focused=false] and [durable].
wait --ref — block until a node matchesagent-tui spawn -- vim /work/notes.md
agent-tui wait --ref '@vim.buffer' # vim has rendered
agent-tui press '/' # open search
agent-tui wait --ref '@vim.cmdline[focused]' # cmdline is up
agent-tui type 'needle'
agent-tui press '<cr>'
agent-tui wait --ref '@vim.cmdline[focused]' --gone # cmdline closed
--gone inverts the match: fires when the selector matches no
node. Right answer for "wait for the confirm to dismiss" or "wait
for the search prompt to close."
Prefer --ref over --text when there's a structured node to
match — selectors don't false-fire on typed-but-not-yet-executed
text the way --text regex can.
snapshot --select — return only matching nodesagent-tui snapshot --select '@vim.statusline'
# → outline with just the statusline node + its anchor
agent-tui snapshot --select '[role=status]' --all
# → every status node in DFS pre-order
--select forces an outline even if you asked for --mode text or
--mode cells, so the response always carries something to interpret.
press --to / type --to — route writes to a sub-nodeWithout --to, keys go straight to the pane's PTY (the classic
behavior). With --to, the pane's attached adapter translates
(target, keys) into a sequence of bytes — useful for multiplexers
like tmux that need a <prefix> dance before sending the actual key.
# Routed (adapter-specific, when supported):
agent-tui press --to '@tmux.pane[%2]' 'iX<esc>'
# Identity routing (when the adapter doesn't override) just sends
# the keys to the PTY — exactly like `press` without `--to`:
agent-tui press --to '[role=buffer][focused]' ':w<cr>'
If the selector doesn't match any node, you get RoutingUnsupported
(error code 2004) rather than a silent write. Take the hint: run
snapshot --select '<your selector>' to inspect.
ref = "@" head ( "." segment )*
head = ident ; adapter root: tmux, vim, shell, …
segment = ident ; e.g. .buffer
| ident "[" key "]" ; e.g. .pane[%2]
key = ident ; named: [main]
| integer ; positional (NOT stable across frames)
| "%" integer ; durable adapter-assigned id
Use [%N] when you need the same logical object across frames.
The adapter stamps durable=true on these. Bare [N] keys are
positional and may shuffle if the adapter rearranges things.
| Goal | Use |
|---|---|
| Wait for vim to finish opening | wait --ref '@vim.buffer' |
Wait for a :write-saved status | wait --ref '[role=statusline][name~=/written/]' |
| Pull just the buffer text | snapshot --select '@vim.buffer' |
| Pull every match in the outline | snapshot --select <sel> --all |
| Write into a specific pane | press --to '<sel>' '<keys>' |
| Wait for a transient prompt to close | wait --ref '<sel>' --gone |
The daemon's error responses are designed to help you self-correct:
^-pointer at the offending byte:
selector parse error at byte 6: unknown attribute "bogus"
[bogus=x]
^
--to <selector>: error.hint lists up to 20
available refs from the current outline — copy one and retry.snapshot --select: the response succeeds with
empty outline.nodes, plus a warning with code
selector_no_match whose message lists available refs.Common loop: snapshot first with no --select to discover refs,
then refine. Or — when in doubt — run snapshot --select '*' to
see every node.
@eN
refs no longer exist.)wait --text when wait --ref is right. --text is regex
over the rendered grid; it can match the typed prefix of a
command before vim executes it. --ref doesn't false-fire.--to into nested layouts. Without --to,
keys go to the outer PTY. Inside tmux that means everything
targets the tmux prefix logic, not the inner app.--gone. Waiting for a confirm to appear and
waiting for it to dismiss are different selectors only by
--gone.The selector grammar covers most cases but not all:
buffer node with everything
inside — wait --text 'regex' is fine here.--mode cells.@shell.prompt[focused] based on alt-screen mode; richer
prompt-vs-running distinctions ride on the OSC 133 parser.agent-tui skills get addressing --full
See also: docs/design/addressing-rfc.md for the design rationale and the
formal grammar.