Skip to main content
Glama
KevinBuettner

docent-terminal-mcp

docent-terminal-mcp

An MCP server that gives an AI model interactive terminal sessions that a human can watch and type into at the same time. Sessions are tmux panes. Every byte of output is logged, split into per-command regions, and saved to disk. Regions may be searched, either with tools provided by this MCP server or by standard filesystem tools favored by the AI model. Output may scroll off the screen a human is watching, but the log keeps it all. The AI model reads back just the lines it needs, so bulk output never has to enter its context.

It is equally a way to give a model a terminal of its own for software development and debugging, watched or not. There the server acts as a docent: each reply carries the output that matters -- the exit status, a build's errors, the end of a long run -- together with advice on using the tool at hand, given as it is being used: that a program is waiting at a prompt, for example, or that gdb is still there and needs no relaunching, or that the | tail is unnecessary. A model meeting an unfamiliar tool is guided through it. With a human in the session as well, either one may act as docent to the other, as the situation calls for.

The command is docent-terminal-mcp, or dtmcp for short. The examples register the server under the name terminal (for Hermes Agent, dtmcp; see below): a client shows its tools under that name (mcp__terminal__run in Claude Code, terminal_run in Open WebUI with the ID terminal), and the tools' own names are short and unprefixed (session_create, run, read, ...).

Use

Requires Linux (parts of the process inspection read /proc). Install beforehand: tmux (developed and tested with 3.7b), bash 4.4 or newer or zsh for the shell integration, ssh for docent-terminal-mcp ssh, and uv. uv provides the rest. uv sync installs the Python dependencies into the checkout's .venv, and downloads Python 3.14 first if the system has none.

In a clone of this repository, once:

uv sync

Then register the server with the agent's harness, which starts it as a command and talks to it over stdio. (To let several agents share sessions, run one server for all of them instead: see below.)

Claude Code:

claude mcp add -s user terminal -- uv run --project "$PWD" docent-terminal-mcp

(-s user makes it available in every directory; without it, Claude Code registers it for the current one only, here the clone.)

Codex:

codex mcp add terminal -- uv run --project "$PWD" docent-terminal-mcp

Hermes Agent, in ~/.hermes/config.yaml:

mcp_servers:
  dtmcp:
    command: uv
    args: [run, --project, /path/to/docent-terminal-mcp, docent-terminal-mcp]

Here the name is dtmcp, not terminal. Hermes has a built-in toolset called terminal, and an MCP server of the same name is merged into it: enabling or disabling terminal would then switch Hermes's own terminal and this server together. As dtmcp, the tools are mcp__dtmcp__run, ... in a toolset of their own.

Open WebUI cannot start a command. It reaches a shared server over HTTP (docent-terminal-mcp serve --tcp, below).

Related MCP server: Terminal MCP Server

One server for several agents

docent-terminal-mcp with no arguments serves one client over stdio. To let several agents -- Claude Code sessions, an assistant's gateway, ... -- share sessions (and each other's work), run one shared server instead:

uv run docent-terminal-mcp serve            # or install contrib/docent-terminal-mcp.service (systemd --user)
claude mcp add -s user terminal -- uv run --project /path/to/docent-terminal-mcp \
    docent-terminal-mcp connect --actor claude-code

The server listens on a Unix socket, $XDG_RUNTIME_DIR/docent-terminal-mcp/server.sock (/run/user/<uid>/...). DOCENT_TERMINAL_MCP_SOCKET_PATH or docent-terminal-mcp serve --socket overrides it. The directory is 0700 and the socket 0600, so only that user (and root) can reach it. No token, no port numbers to hand out, and any number of users on a host need no configuration -- each one's server is found by path. The socket lives in the runtime directory, not the state directory, which may be on NFS.

docent-terminal-mcp connect [--actor NAME] is a stdio bridge to the socket, for clients that start an MCP server as a command (Claude Code and Codex above, Hermes's mcp_servers with a command:). One light process per client session. When the service restarts, the bridge reconnects by itself -- a new MCP session with the client's own initialize parameters -- and answers the call that was in flight; the client notices nothing. Only if no server comes back within 30 s does it exit.

docent-terminal-mcp serve --tcp [PORT] also listens on a TCP port (default 8766) for a client that can only be given a URL. It binds to loopback unless --host says otherwise; --host 0.0.0.0 lets Open WebUI on another machine reach it, with http://HOST:8766/mcp and connection type MCP. Requests need the bearer token from $DOCENT_TERMINAL_MCP_HOME/token (mode 0600, created on first use; docent-terminal-mcp token prints it). A port is open to every user who can reach it; the token file is not.

claude mcp add -s user --transport http terminal http://127.0.0.1:8766/mcp \
    --header "Authorization: Bearer $(uv run --project /path/to/docent-terminal-mcp docent-terminal-mcp token)" \
    --header "X-Terminal-Actor: claude-code"

Each client is an agent. X-Terminal-Actor (connect --actor) names it, stably across reconnects; without it the client's own name is used, made unique per connection (claude-code#2). Regions another agent started name it. Its unsubmitted text is protected like a human's, and per-agent state is kept apart: own half-typed text, "finished since your last call", screen diffs. calls.log records the agent of every call.

One server per state directory: a second (stdio or shared) refuses to start while one runs, naming the host that runs it. A home on NFS is shared by every host the user logs in on, and so is the enabled unit in ~/.config/systemd/user. contrib/docent-terminal-mcp.service therefore gives each host its own state directory and venv (%l, the short host name: ~/.local/state/docent-terminal-mcp-HOST, ~/.local/share/docent-terminal-mcp-venv-HOST). One service per host just works, and no host rebuilds the checkout's .venv for its own Python. A second server on the same socket path refuses too.

Besides MCP at /mcp, the server answers GET /health (no token: {"service": "docent-terminal-mcp", "host", "user", "instance"}) and GET /api/sessions (every session's state; on the socket without a token, on the port with it). /health tells you what a port is before sending a token. instance is new at every start, so the bridge sees a restart before it sends a call. /api/sessions reports the exit status, command, cwd, size, the agent that started it, attached humans, last output time, log directory, the tmux argv to attach to it, the pane (pane_id, window, parent, index, active, adopted, integrated; place, the host and user its next line runs on when not this one), and presence: agents_typed (agent to epoch seconds of its last typing call), human_input (an attached client's last input, from tmux), typing_now (the agent and tool holding the session). For example:

curl --unix-socket $XDG_RUNTIME_DIR/docent-terminal-mcp/server.sock http://x/api/sessions

After updating the checkout (a git pull, say), restart the service: a running server keeps the code it started with.

systemctl --user restart docent-terminal-mcp

Clients on the connect bridge reconnect by themselves. A call in flight comes back with a note; a run is never typed twice. Claude Code sees tools added by the new code only after /mcp. Sessions and logs are unaffected: under systemd the tmux server holding the sessions runs in a transient scope of its own (docent-terminal-mcp-tmux-<socket>.scope), outside the service's control group, which a restart or stop would otherwise kill.

Watching, logs and environment

Watch or join a session the model started:

tmux -L docent-terminal-mcp ls                # the sessions
tmux -L docent-terminal-mcp attach -t t1      # watch or join one

The model gets the same attach command in the replies of session_create and session_list. The tool descriptions and the skill ask it to pass the command on to the user when it starts a session; whether it does is up to the model.

Every tool call is recorded in $DOCENT_TERMINAL_MCP_HOME/calls.log (JSON lines: time, tool, session, duration, ok/error). Never its input or output. So a slow or missing reply can be pinned on the server or the client.

Environment variables

  • DOCENT_TERMINAL_MCP_ATTACH_PREFIX -- words put before the attach command in replies and /api/sessions, for a server that runs where a person cannot run tmux directly: openshell sandbox exec -n NAME --tty --, podman exec -it NAME, ssh -t HOST.

  • DOCENT_TERMINAL_MCP_HOME -- default ~/.local/state/docent-terminal-mcp.

  • DOCENT_TERMINAL_MCP_SOCKET -- tmux socket name, default docent-terminal-mcp.

  • DOCENT_TERMINAL_MCP_SOCKET_PATH -- the shared server's Unix socket, default $XDG_RUNTIME_DIR/docent-terminal-mcp/server.sock.

Tools

tool

purpose

session_create

bash with shell integration (default, or command="bash"), zsh with it (command="zsh"), or any command

run

type a line + Enter; wait for the command to exit, the program's next prompt, a full-screen program's first screen, or until (a regex in the output); several lines go one at a time; show (a regex, with show_after lines after each match) and last_lines shape the reply, save_to copies the output to a file; typing types it as a person would (speed, pauses, corrected mistakes, a seed) for a human watching

expect

optionally type a line (several go one at a time, as with run), then answer prompts by rules ({pattern, line/text/keys/stop}) until the command finishes, the program's prompt, until, a stop rule, or an unanswered question

send

type text, then press keys (ctrl+c, up, tab, q, ...); returns what appeared, or the screen (screen="full", "changes", "cursor"); names a job still in the foreground after ctrl+c; signal="TERM"/"KILL" ends a foreground job that ignores keys

wait

keep waiting for a running command (e.g. after run timed out); until, show, show_after, last_lines, save_to as for run

read

view="cooked" (log/region, line numbers), "screen" (literal rows, size, cursor), "raw" (escape codes spelled out)

search

regex over the log or a region: total count, hits with context and region ids

regions

list recent commands/inputs with status, exit code, lines, file

shell_integrate

add the shell integration to a bash or zsh that could not inherit it (ssh, su -, sudo -i): asks which shell is at the prompt, then types one line that reads the integration file (on another host: the one docent-terminal-mcp install HOST put there); types nothing where the shell is already integrated

session_resize

set the pane size and pin it against attaching clients, or let it follow them again

session_split

a new pane in a session's window, a session of its own (<window>+N), logged and integrated from its first prompt; a pane split any other way is adopted as one

session_logs

keep a session's logs for good, put them back under the usual rule, delete them when the session closes, or delete a closed session's logs now (see Retention)

session_list, session_close

per session: what runs, which host it is on (over ssh), pane id, window, parent, index, active, and presence (age, last output, who typed when, who is typing); session_close window=true closes every pane of the window; it will not close a terminal someone is using (a person attached, or another's command running) -- a person closes those with docent-terminal-mcp close --force NAME or POST /api/sessions/NAME/close {"force": true} (a client's Close button)

guide

longer usage guidance by topic: patterns (shell habits and their interactive form), programs, output, fullscreen, sharing

A clipped reply leads with the output's summary lines when the clipped middle holds them: FAIL lines and a DejaGnu run's final summary, pytest, cargo, go test, ctest and TAP results, compiler errors, make giving up (summary.py; DOCENT_TERMINAL_MCP_SUMMARY=0 turns it off, for an A/B).

What the model is told, and the skill

Three channels carry the guidance. All are sized for Claude Code's limits: it cuts a server's instructions, and each tool's description, at 2048 characters -- CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH -- silently for the model.

  • the server instructions (under 2048 characters, guide.py): the rule for choosing a session over a one-shot shell call, "open one at the start of a task", and the five things that go wrong most;

  • each tool description (under 2048) and every parameter's description in the schema: use cases, the one-shot habit each tool replaces, the gotchas;

  • the guide tool (topics patterns, programs, fullscreen, output, sharing) for the long form. Every tool is marked anthropic/alwaysLoad so Claude Code never defers it behind its tool search, and the read-only tools carry readOnlyHint.

The same long form is also a Claude Code skill, which loads on demand without any cap and stays in context once loaded:

uv run docent-terminal-mcp skill ~/.claude/skills          # or a project's .claude/skills
uv run docent-terminal-mcp skill /path/to/plugin --plugin  # a plugin: .mcp.json starts the server, skills/ holds the skill

This writes terminal-sessions/SKILL.md (the instructions' two parts and the patterns) with one reference file per other topic. Both are generated from guide.py, so the skill and the server say the same thing.

How it works

Capture: tmux pipe-pane -O appends the pane's raw output to raw.log. The pane blocks on a tmux channel until the pipe is attached, so nothing is lost. Input is never logged; text reaches the log only if the program echoes it, so no-echo password entry leaves no trace.

Cooked view (cooked.py): the raw stream interpreted into unbounded lines. A line break is always a real one, never a wrap. Carriage returns, backspace, erase and cursor motion are applied, so readline edits and progress bars read as a human saw them. Columns are screen cells, so wide (CJK, emoji) characters edit correctly. Full-screen programs -- on the alternate screen (vim, less), or painting the normal one by re-homing the cursor (top, redraw loops) -- become a placeholder line; read them with view="screen".

Regions: in an integrated shell, from the markers the shell prints (see Shell integration): exact command boundaries and exit codes. In a plain shell, and for lines sent to a program, from prompt matching.

Where a session is: the process chain from the foreground job to the session's shell (an ssh's command line, a shell of another user after sudo -i) and the markers of integrated shells. A reply says when it changes, and regions that ran elsewhere are tagged ยท on HOST. Lines sent to a foreground program (gdb, python) become input regions ending at the next prompt (regex), when output settles, or at a timeout.

Waiting for input: whether the foreground job waits on the terminal (at a prompt, or a question) or works. First from where each of its processes sleeps (ps's wait channel: a terminal read, poll, select, epoll, or something else), then, on x86_64 and aarch64, from the file descriptors the call it waits in watches (/proc/PID/task/TID/syscall and the process's memory), so that a job waiting on other things -- a make check whose expect polls its gdb's pty, a connect() -- is not taken for one at a prompt. Reading those needs ptrace access, and the session's programs are not the server's descendants (the tmux server detaches). With Yama's ptrace_scope at 1, the default on Ubuntu, only root has it: elsewhere the server goes by the wait channel alone, and such a job may be called "waiting for input". sysctl kernel.yama.ptrace_scope=0 gives it back, at a price: any process may then trace any other of the same user.

Memory: rows that can no longer change live only in session.txt, read back through a byte-offset table. 3 million lines (a 25 MB log) peak at about 150 MB for the whole server process.

Recovery: session state is rebuilt from raw.log + regions.jsonl, so a new server process picks up sessions a previous one started, including anything typed while no server was running.

On disk, per session: meta.json, raw.log, session.txt (cooked whole session; its line numbers are the ones tools report), regions.jsonl (the index, one line per change), regions/NNNN.txt (the 8 most recently used regions; any other is a line range of session.txt, and read region=N writes its file again), state.json (per agent: the prompt text it left unsubmitted, so a restarted server can tell it from a human's, what finished since its last reply, notes already given, where it was last told the session is).

A region holds only output. Its command -- for bash, the command line; for a program, its prompt plus the input -- labels the region instead.

Shell integration

What it is, and why it is needed

A terminal gives a program nothing but a stream of bytes. Nothing in it says where one command's output ends and the next prompt begins, or whether the command succeeded. A person sees that at a glance. A program reading the stream has to guess. The shell integration removes the guessing: a short script loaded into the session's bash or zsh that makes the shell mark those points with invisible escape sequences -- the OSC 133 "semantic prompt" markers that terminals such as iTerm2, kitty and WezTerm use for the same purpose:

  • prompt start (and continuation prompts, such as inside a heredoc or an unclosed quote);

  • end of the prompt, where the typed command starts;

  • start of the command's output;

  • command finished, with its exit status (and, for a pipeline, every stage's).

Each marker also carries the shell's pid, so nested shells are told apart; the host and user, so the server knows when a command runs over ssh or after su; and the session's nonce, a random value known only to the session's shell. Markers without it -- some program's output, another session's raw log catted, say -- are ignored.

What it gives

  • run returns the moment the command finishes, with its exit status (exit 1; a pipeline's statuses too), never early and never by guess.

  • Each command's output is a region of its own with exact boundaries: neither the prompt nor the echoed command line is mixed into it.

  • A continuation prompt is known for what it is, not taken for the command having finished.

  • Shells inside shells: a bash started in a session inherits the integration, so its commands get regions and statuses too, and the outer command closes with its own status when it exits. Across ssh (with the integration brought along, below), replies say which host a session is on and tag the regions that ran there.

Without it

A shell without the integration -- one reached by a plain ssh, su - or sudo -i, a bash --norc, a shell other than bash or zsh -- still works. Its output is logged, cooked and searchable like that of any other shell. send, expect, read, the screen view and a human attaching are unaffected. What is lost is knowing where commands begin and end. The server falls back to prompt matching, as it does for programs like gdb or python:

  • No exit statuses. A reply cannot say whether a command succeeded; the model has to check (echo $?) itself.

  • Boundaries are inferred. A command counts as finished when the last line looks like a prompt: it ends in $ , # , % or > , or matches the session's prompt_pattern. An output line that happens to look like one can end a region early. A prompt that does not (a customised PS1) leaves run waiting until the output has been quiet for a while, or until its timeout; prompt_pattern fixes that.

  • Further hops are not seen. An ssh started from a plain shell on another host is invisible to the server, which inspects only its own host's processes, so the host a reply names can be out of date.

Replies say when a session is at a plain shell, and how to integrate it there (shell_integrate, or docent-terminal-mcp ssh).

What it changes in the shell

  • bash is started with shell/bashrc. It first reads the same startup files a login shell would (as a normal tmux pane does), then loads shell/integration.bash. zsh gets shell/integration.zsh through a ZDOTDIR of docent-terminal-mcp's (shell/zsh/), whose files read the user's own.

  • PROMPT_COMMAND becomes a single hook that runs the shell's own prompt commands. PS1, PS2 and PS0 get the markers wrapped around them (and again if a prompt framework rebuilds them). The hook functions and the __DTMCP_* variables are exported, so a bash started inside inherits them -- and programs run there can see them in their environment.

  • Markers are printed only when the prompt goes to the session's own terminal: a program that runs a shell on a pty of its own (expect, pexpect, GDB's testsuite) sees its prompts unchanged.

Getting it into a shell

A session started with no command (or bash) is an integrated bash. command="zsh" is an integrated zsh, and a zsh started inside it is integrated too. A shell reached over ssh, su - or sudo -i does not inherit it. There shell_integrate first asks which shell is at the prompt and then types one readable line: . DIR/integration.bash && export __DTMCP_NONCE=... (.zsh for zsh). DIR is the server's own shell/ directory on its host (when the user at the prompt can read it), and ~/.local/share/docent-terminal-mcp/vN anywhere else -- see docent-terminal-mcp install below. The server never copies the integration to a host by itself.

Remote hosts. A plain ssh is left as it is: its shell works by prompt matching. docent-terminal-mcp ssh [ssh options] [user@]host, run in a session in place of ssh, connects with the integration. Like kitty's kitten ssh, it passes a small POSIX sh script as ssh's remote command. The script unpacks the integration into a temporary directory, starts the user's shell (zsh if that is their login shell, else bash) with it, and removes the directory (bash once loaded, zsh when it exits). Nothing is typed at a prompt and nothing stays on the host; running it is the choice to do this. docent-terminal-mcp ssh --print host shows the ssh command and the script. Sessions have the command on their PATH (a shim in $DOCENT_TERMINAL_MCP_HOME/bin). Replies say which host a session is on, and when that changes.

DOCENT_TERMINAL_MCP_SSH_ENV, a list of variable names set in the session (by the client that created it, through session_create's env), has those variables set on the far side too -- an editor's ADJUTANT_EDITOR, say, so a program over there still knows which editor it runs in. The list itself goes along, for the next hop. docent-terminal-mcp into carries them the same way.

docent-terminal-mcp install [ssh options] [user@]host is for the shells docent-terminal-mcp ssh cannot reach -- a plain ssh that is already open, sudo -i there (install for root@host), a second hop. The user runs it, once per host and user. It copies integration.bash and integration.zsh to ~/.local/share/docent-terminal-mcp/vN on the host (a tar archive on the stdin of one ssh; older versions' directories are removed), and from then on shell_integrate works there. --print shows the ssh command, the script and the files without running anything; --remove takes the files away again. N is the integration's version (remote.INTEGRATION_VERSION). After an upgrade that changes it, a host reads as not installed until the command is run again. On a host without the files shell_integrate types the same line, the shell says the file is not there, and the reply names the install command for the user. That answer is remembered for the host, server-wide, for 12 hours ($DOCENT_TERMINAL_MCP_HOME/integration-missing.json; a later success clears it).

docent-terminal-mcp into COMMAND... is the same for anything that opens a shell somewhere else with a terminal -- a container, a sandbox: docent-terminal-mcp into podman exec -it box, docent-terminal-mcp into openshell sandbox exec -n box --tty --, docent-terminal-mcp into bwrap ... --. The bootstrap goes as the program COMMAND runs. Use it as a session's own program (session_create command="docent-terminal-mcp into ...") when the point is confinement: typed into a host shell, a failed entry leaves the next lines running on the host. openshell is treated as ssh is: a carrier whose own processes say nothing about the program at the other end. So are podman, docker, nerdctl and kubectl when their command line holds a terminal on a container (exec -it, run -it, attach).

Not yet: fish (shell_integrate names it and leaves it alone; it works as a plain shell).

Retention

A closed session's directory is deleted once all of these hold. It is closed (no tmux pane, so no person attached either; an exited pane still kept is not closed). Nothing in it was written or read for DOCENT_TERMINAL_MCP_KEEP_CLOSED_DAYS days (docent-terminal-mcp serve --keep-closed-days; default 3, 0 keeps everything) -- reading changes no file, so read, search and regions, which work on a closed session's logs too, touch last-used there. And it is not pinned. No reference counting: clients forget to let go, as people do, so the dates decide. Archived generations (NAME.N) follow the same rule. The sweep runs at start-up and hourly; sessions marked delete-on-close, every minute. Each candidate is checked again just before it goes, and each deletion is one line in the server's log and one in removed.jsonl (a tombstone, kept 30 days), so that a later request for it says when and why it went.

Marker files in a session's directory, which anyone may set: keep (pinned) and delete-on-close (its logs go the moment it closes; session_create delete_logs_on_close=true sets it before the first byte is logged). The session_logs tool, POST /api/sessions/NAME/logs ({"action": "keep" | "default" | "delete_on_close" | "delete"}) and docent-terminal-mcp logs keep|default|delete-on-close|delete NAME set and clear them, or delete a closed session's logs now. docent-terminal-mcp logs due (POST /api/sweep?dry_run=1) lists what the next sweep would delete; docent-terminal-mcp logs sweep runs it. session_list says until when a closed session's logs are kept. /api/sessions has keep, delete_on_close and expires.

Only the server that made a session may call it closed: meta.json records the host, the tmux socket and its path. A home on NFS is seen from every host, and a server under another TMUX_TMPDIR cannot see this one's tmux; such sessions are left alone. With no tmux server answering, only sessions made on this very socket path count as closed.

Security

docent-terminal-mcp has no security boundary of its own: what a model types runs with the rights of the user who started the server. The intended answer is a sandbox made for the purpose, with docent-terminal-mcp as the terminal in or in front of it:

  • the session's shell alone in a sandbox: docent-terminal-mcp into COMMAND... runs the shell integration through the command that enters the sandbox (podman exec -it ..., bwrap ...), so the server stays outside and keeps seeing the processes;

  • or the whole server inside one, reached through its Unix socket in a mounted directory.

Recipes for rootless podman (with a seccomp profile that lets gdb trace), bubblewrap and NVIDIA OpenShell have been tried; they will be added to contrib/ once re-verified.

Tests

uv run pytest -rs

The end-to-end tests drive real tmux sessions on private sockets; some attach real tmux clients from Python ptys to stand in for a human. They need only tmux and bash. A test that needs anything else is skipped where it is missing, and -rs lists what each skipped test needed (tests/needs.py checks). For the full run:

  • the programs the tests drive: gdb, a C compiler (cc, gcc), python3, ipython3, less, vi, nano, top, make, zsh, fish, node, sqlite3, guile and kermit. On Fedora: dnf install gdb gcc python3-ipython less vim-minimal nano procps-ng make zsh fish nodejs sqlite guile ckermit; on Debian and Ubuntu: apt install gdb gcc python3 ipython3 less vim-tiny nano procps make zsh fish nodejs sqlite3 guile-3.0 ckermit.

  • ssh localhost logging in with no password and no host key question (an ssh server, and a key in ~/.ssh/authorized_keys).

  • the server able to read a session program's /proc/PID/syscall (see How it works): Yama's kernel.yama.ptrace_scope 0, or the tests run as root.

License

MIT; see LICENSE. Written by Kevin Buettner with Claude (Anthropic's Claude Code).

Available Tools

15 tools
expectA

Script predictable interactions in one call: optionally type input (+ Enter), then answer each prompt that matches a respond rule, in whatever order the prompts appear. The interactive form of yes |, echo y |, gdb's -batch and an expect script: the program gets a real terminal, and only the questions you foresaw are answered. Rules that never match are fine -- use them for questions only sometimes asked.

Ends when the command finishes (bash), the program is back at its prompt (prompt_pattern, default as for run), until (a regex) matches, a stop rule matches, or -- the important case -- output stops at a question no rule answers: that returns at once as "unanswered" instead of waiting for the timeout, so a surprise comes back to you rather than being guessed at.

Example, gdb's optional questions: input="gdb -q -ex 'break lib_fn' -ex run ./prog", respond=[{"pattern": "Make breakpoint pending", "line": "y"}, {"pattern": "Enable debuginfod", "line": "n"}] Example, ssh, handing any password prompt to the human: input="ssh host", respond=[{"pattern": "continue connecting", "line": "yes"}, {"pattern": "[Pp]assword:", "stop": true}] Without input, the rules apply to a question already waiting at the cursor (one a run came back "waiting" at).

Returns a transcript (what matched, what was sent), rules that never fired, and the resulting region(s) as run does.

ParametersJSON Schema
NameRequiredDescriptionDefault
forceNotype even over someone else's unsubmitted line at the prompt, discarding it first; only for a line you know is stale
inputNoa line to type first (Enter added), e.g. the command that will ask the questions; without it the rules are applied to a question already waiting at the cursor
untilNoregex: return as soon as the output matches it, the command still running (status "until"; `wait` resumes); not a prompt pattern
respondYesthe rules: each fires when its `pattern` appears, doing its one action (line, text, keys or stop); a question no rule covers ends the call as "unanswered"
sessionYesthe session's name (from session_create or session_list)
max_linesNolines of output shown in the reply; longer output is clipped in the middle, led by its summary lines (test results, compiler errors, make's failure) when the middle holds them; all of it stays readable with `read`/`search`
timeout_sNoseconds to wait before giving up (the command keeps running; `wait` resumes); at most 1500
prompt_patternNoregex that marks the program's prompt at the end of the cursor line; rarely needed, the default knows shell, gdb, pdb, lldb and python prompts and any ending in $ # % >; pass one only after a reply came back "waiting" at a prompt it did not know (it offers the pattern); make it cover a part that changes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden and does so thoroughly: it explains termination conditions (command finishes, prompt, `until`, `stop`, or unanswered question), the immediate `unanswered` return, timeout behavior, transcript output, secret masking, and `force` discarding stale input. It also warns about password prompts and handing control back to the human.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Despite being longer than average, the description is front-loaded and every paragraph earns its place: purpose first, then termination behavior, then examples, then the no-`input` case, then return details. The examples and edge-case notes are dense but directly useful for invoking such a complex tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity, lack of annotations, and rich output schema, the description is complete enough for correct selection and invocation. It covers purpose, alternatives, termination, return shape, rule behavior, and edge cases without needing to re-explain return fields that the output schema already documents.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema establishes a strong baseline, but the description adds meaningful usage semantics through concrete examples for `input` and `respond`, clarifying how rule order works and how `stop` combines with an answer. It is not fully redundant, though much of the per-parameter detail already lives in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: scripting predictable interactions in one call, with optional input and rule-based prompt answering. It clearly contrasts this with related operations such as `run`, `send`, and `wait`, making its unique role identifiable without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit when-to-use context: the interactive form of `yes |`, `echo y |`, gdb's `-batch`, and an expect script, and explains that rules can cover questions only sometimes asked. It also explains the no-`input` case, where rules apply to a question already waiting from a `run`, directly routing the agent between siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

guideA
Read-only

Usage guidance, worth one call before the first real use. Topics: patterns (one-shot shell habits -- pipes, redirects, -batch, sleep-and- poll, nohup -- and their interactive form, plus the gotchas), programs (gdb, python, REPLs, prompts, questions), fullscreen (vim, less, send order, screen view), output (timeouts, large output, views, the log files), sharing (working alongside a human or another agent).

ParametersJSON Schema
NameRequiredDescriptionDefault
topicNoone of patterns, programs, output, fullscreen, sharing; none lists them

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation already communicates that this is a safe read operation. The description adds useful behavioral context by framing the tool as one-shot orientation material and by describing that topics include gotchas and interactive forms. Return behavior is left to the output schema, which exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description front-loads its purpose and usage timing, then enumerates topics compactly. The parenthetical examples are dense but each maps to a listed topic, and there is no filler text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only guide tool with one optional parameter and an output schema, the description covers purpose, timing, and topic scope. Safety is handled by annotations and return details by the output schema, leaving no critical gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the topic parameter is already documented as one of patterns, programs, output, fullscreen, sharing, with 'none' listing them. The description adds meaningful detail by expanding each topic with concrete examples such as pipes, gdb, vim, and timeouts.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool provides usage guidance and names five topics it covers. It distinguishes itself from action-oriented siblings like run and send by positioning itself as something to call 'before the first real use,' though it does not name any sibling explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear timing guidance: 'worth one call before the first real use.' That is a usable when-to-use signal. However, it does not mention when not to use it or explicitly compare it with the many action-oriented siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

readA
Read-only

Read session output: the log or one region, by line number -- what tail -n, sed -n or head would do on a log file you had redirected to, except that nothing had to be redirected. A reply's "[... N lines omitted (lines A-B) ...]" marker gives the range to read.

view="cooked" (default): the whole-session log as plain text with line numbers, real line breaks only. With region, reads that region; start is a line number (1-based, as shown) to page from. Without start, shows the last limit lines. view="screen": what the terminal shows right now, row by row as tmux renders it (a long line wraps onto several rows), with the size and cursor position. start/limit select screen rows. The view to use for full-screen programs. Note that such programs clip long lines at the window edge; check file contents another way. view="raw": the bytes the program wrote, escape codes included, with control characters spelled out (\e, \r, \xNN). For debugging odd rendering. start is a byte offset; max_bytes bounds the result. With region, reads that region's bytes (bounds may include a little output from either side).

ParametersJSON Schema
NameRequiredDescriptionDefault
viewNo"cooked" (the log as a plain-text file, one entry per real line), "screen" (the terminal as displayed now, rows as tmux renders them; for full-screen programs), or "raw" (the bytes written, escape codes spelled out)cooked
limitNolines (or screen rows) to return; without `start`, the last that many
startNocooked: the line number to start from (1-based, the numbers replies and `search` show; the same in a region and in the log); screen: the first row; raw: the byte offset
regionNoread only this region (its id from a reply header or `regions`); default: the whole session log
sessionYesthe session's name (from session_create or session_list)
max_bytesNoraw view only: the most bytes to return

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, and the description adds real behavioral context beyond that: per-view return shapes, that screen view clips long lines at the window edge, and that region bounds 'may include a little output from either side'. No error/auth/limit behavior is described, but for a read tool this is a meaningful addition over the annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core purpose and then organizes the three views into clearly separated blocks, so it scans well. It is on the long side, but most sentences carry distinct, actionable information rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values needn't be spelled out, yet the description still covers view selection, parameter interactions, caveats, and the upstream workflow with search/regions. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so parameters (view, limit, start, region, max_bytes) are already documented. The description largely restates those semantics (start as line/row/byte-offset per view, max_bytes raw-only) with only marginal added nuance, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource+scope ('Read session output: the log or one region, by line number') and grounds it in familiar Unix analogies (tail/sed/head). It also positions itself against siblings by referencing the `search` omitted-lines marker and `regions` ids as inputs, so an agent knows where read fits.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear when-to-use guidance per view ('The view to use for full-screen programs' for screen, 'For debugging odd rendering' for raw) and shows how a search reply's marker routes into the tool. It stops short of explicit when-not or direct comparison to siblings like session_logs/search for the same content.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

regionsA
Read-only

List the most recent regions: each command or program input with its status (running, done, waiting at a question, ...), exit status, line range and file. The session's history at a glance: to find a region id for read/search, to check on a command left running without waiting for it, or to see what a human or another agent ran.

ParametersJSON Schema
NameRequiredDescriptionDefault
lastNohow many of the most recent regions to list
sessionYesthe session's name (from session_create or session_list)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

readOnlyHint=true already declares the safety profile, but the description adds what the listing surfaces (status values like running/done/waiting, exit status, line range, file) โ€” useful behavioral context beyond the annotation. No pagination or ordering caveats beyond the implied 'most recent', which is minor.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core action, followed by purpose-driven use cases. No filler; every clause conveys a distinct piece of information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value detail is not required, and the description still sketches the region fields well enough for selection. Combined with the safety annotation and full schema coverage, nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters (last, session) are already documented in the schema. The description implies recency and session scoping but adds no format or edge-case detail beyond that. Baseline 3 is appropriate when the schema carries the parameter burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (regions), then defines exactly what a region is: command/program input with status, exit status, line range, and file. This gives an agent a clear mental model distinct from the session/command siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly enumerates three concrete when-to-use scenarios: finding a region id for read/search, checking on a running command without waiting, and seeing what a human or another agent ran. This routes the agent to correct usage rather than leaving it to infer.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

runA

Type a line into the session, press Enter, and wait for the result: the session's form of a shell tool call, and of a line typed at gdb's or python's prompt.

At a bash prompt (shell integration) it waits for the command to exit and returns its output with the exit status (pipestatus for a pipeline; no ; echo $? needed); for a build or a testsuite give timeout_s the whole run (up to 1500 s) and get the exit status in one reply. Inside a program (gdb, python, psql, ...) it waits for the program's next prompt; starting one from bash returns at its first prompt, or its first screen (vim, less; continue with send). The session persists: cwd, variables and a running program stay between calls.

Output longer than max_lines keeps its first and last lines with a marker naming what was left out; nothing is lost: read pages it, search finds lines in it. So no | tail, | head, 2>&1 > log -- and never a pipe or redirect on an interactive program (gdb without -batch, python): it then waits at a prompt you cannot see. To watch for particular lines as they come, show=REGEX replies with the matching lines and the last few while the command runs unfiltered, exit status its own.

At timeout_s -- a short one gives your turn back soon -- the command keeps running and its region stays open: wait keeps waiting, send keys=["ctrl+c"] interrupts, send signal="TERM" if it survives. until=REGEX returns as soon as the output matches.

Several lines go one at a time, each once the previous is back at the prompt; a line that asks a question or times out stops the rest. Into Python or IPython they go as one paste (an exception drops the lines after it). Predictable questions: expect. Keystrokes (ctrl+c, tab, arrows) are send's keys, not an argument here.

prompt_pattern is rarely needed: never pass one to start a program (shell, gdb, pdb, lldb, python and any prompt ending in $ # % > are known); only after a reply came back "waiting" at a prompt it did not know, which then offers the pattern.

ParametersJSON Schema
NameRequiredDescriptionDefault
showNoregex: reply with only the output lines matching it, in order, plus the last few (like `| grep`, but the command runs unfiltered and the log keeps everything), e.g. "error:|warning:|^FAIL" for a build -- or a program's answer: gdb's `step` under `set debug infrun 1`
forceNotype even over someone else's unsubmitted line at the prompt, discarding it first; only for a line you know is stale
inputYesthe line to type (Enter is added); several lines are sent one at a time, each after the previous is back at a prompt
untilNoregex: return as soon as the output matches it, the command still running (status "until"; `wait` resumes); not a prompt pattern
typingNotype the input as a person would, for a human watching: {wps, mistakes, seed}
save_toNoa file to copy the command's output into, as `> FILE 2>&1` would, while the command itself runs unredirected (the reply and the log are as usual): written at once, kept up to date while it runs, written in full when it ends. A relative path is in the session's current directory; the file is on the machine this server runs on, even for a session over ssh. For a later diff or grep by other tools; `read` and `search` need no file
sessionYesthe session's name (from session_create or session_list)
max_linesNolines of output shown in the reply; longer output is clipped in the middle, led by its summary lines (test results, compiler errors, make's failure) when the middle holds them; all of it stays readable with `read`/`search`
settle_msNointo a program with no recognised prompt: return once output has been quiet this long and nothing is visibly working (default 3000)
timeout_sNoseconds to wait before giving up (the command keeps running; `wait` resumes); at most 1500
last_linesNoreply with only the last N lines of the output (like `| tail -N`, but the command runs unfiltered and the log keeps everything; the reply says where the rest is); with `show`, how many last lines follow the matches (default 3)
show_afterNowith `show`: also this many lines after each match (like `grep -A N`); a match is numbered "N:", a line after one "N-"
prompt_patternNoregex that marks the program's prompt at the end of the cursor line; rarely needed, the default knows shell, gdb, pdb, lldb and python prompts and any ending in $ # % >; pass one only after a reply came back "waiting" at a prompt it did not know (it offers the pattern); make it cover a part that changes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so well: it discloses session persistence (cwd, variables, running program survive), timeout semantics (command keeps running, region stays open, interruptible via `send signal=TERM`), output clipping with first/last lines retained, and exit-status/pipestatus return behavior. These are exactly the behavioral traits an agent needs and cannot get from the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first sentence and every subsequent paragraph maps to a capability or parameter, so little is pure filler. However, it is a dense ~380-word wall of prose with heavy parentheticals and em-dash asides that could be tightened without losing content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 13-parameter tool with an output schema, this covers the ground: it explains exit status/return shape, output retention and paging via siblings, timeout/resume flow, and multi-line input behavior. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the prose adds real meaning beyond the schema text: it explains *when* to set a short `timeout_s` ('gives your turn back soon'), that `show` is like grep over an unfiltered run, that `until` is 'not a prompt pattern', and how `max_lines` clipping interacts with `read`/`search`. It stops short of covering every parameter's interaction, but clearly exceeds the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a concrete verb and resource: 'Type a line into the session, press Enter, and wait for the result', and explicitly frames it as 'the session's form of a shell tool call'. It is immediately distinguishable from siblings like `send` (keystrokes) and `wait` (resuming), which the text also names.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use and when-not-to-use guidance throughout: use `show` to watch for lines, `until` to return early, `wait` to resume after a timeout, `send keys` for keystrokes, and 'never a pipe or redirect on an interactive program'. It also states that `prompt_pattern` is 'rarely needed' and the precise condition under which to pass one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

sendA

Send keystrokes without waiting for a command's result (that is run). ORDER: all of text is typed first (literally; a newline in it is Enter), THEN the keys are pressed in list order. To press a key before typing (escape, then an ex command), make two calls.

For: interrupting (ctrl+c; ctrl+d ends input, or gdb/python at their prompt; q leaves a pager), answering a one-character prompt, tab completion, history and arrows in a REPL, and driving full-screen programs (vim, less, top). Command lines go through run, which waits for their result; send only waits until output pauses for settle_ms (at most wait_ms) and returns what appeared -- or, while a full-screen program runs, the rendered screen with the cursor position: screen= "full" (every row), "changes" (only rows changed since the screen last returned: cheapest for editing), or "cursor" (the rows around the cursor). With nothing to send, it just reads what is new.

Keys are names such as ctrl+c, ctrl+d, enter, tab, escape, backspace, up, down, left, right, home, end, pageup, pagedown, f1-f12, alt+x, or any single character. Shell commands that finish during the call are reported with their exit status. Refuses, like run, to type over a human's unsubmitted line unless force. When nothing new appears, or a program is still in the foreground after ctrl+c, the reply names what is running there.

signal ("TERM", "KILL", "INT", "HUP", "QUIT"), instead of text and keys, sends that signal to the terminal's foreground job -- never the session's own shell or program: for a job that ignores ctrl+c and ctrl+d. TERM first; KILL if it survives. Prefer it to pkill from outside, which can hit the session's own shell.

ParametersJSON Schema
NameRequiredDescriptionDefault
keysNokey names pressed after the text, in order: ctrl+c, ctrl+d, enter, tab, escape, backspace, up, down, left, right, home, end, pageup, pagedown, f1-f12, alt+x, or a single character
textNotyped literally, first; a newline in it is Enter
forceNotype even over someone else's unsubmitted line at the prompt, discarding it first (only for a line you know is stale); with `signal`: send it although the foreground job is ssh, which it would end
screenNowith a full-screen program: "full" (every row), "changes" (rows changed since the last screen you saw; cheapest when editing), or "cursor" (the rows around the cursor)full
signalNoinstead of text and keys: "TERM", "KILL", "INT", "HUP" or "QUIT", sent to the foreground job (never the session's own shell or program) when ctrl+c and ctrl+d fail; TERM first
sessionYesthe session's name (from session_create or session_list)
wait_msNothe most to wait for output to settle before replying (milliseconds)
max_linesNolines of output, or rows of the screen, shown in the reply
settle_msNoreply once output has paused this long (milliseconds)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations, so the description carries the full burden and does so richly: it explains the text-then-keys ordering, that output is returned once it pauses for settle_ms (capped by wait_ms), the screen render modes, the refusal to type over a human's unsubmitted line unless `force`, and that `signal` never targets the session's own shell. It even recommends `signal` over `pkill`, covering side effects and safety.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Long but front-loaded, with the core distinction (`run` vs `send`) in the first sentence and dense but non-redundant detail after. It is closer to thorough than bloated, though a few clauses could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has an output schema, so return format need not be re-explained, and the description still covers timing, ordering, safety overrides, and signal behavior. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: the ORDER of `text` vs `keys`, the semantics of the three `screen` modes, when to prefer `signal` over pkill, and the `force` override for stale lines. Minor edge cases (e.g., max_lines interaction) remain to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Send keystrokes without waiting for a command's result') and immediately distinguishes itself from the sibling `run` in parentheses. An agent can tell the two apart without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit use cases (interrupting, one-character prompts, tab completion, REPL history/arrows, full-screen programs) and explicitly routes command lines to `run`. The when/when-not distinction is spelled out rather than implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

session_closeA

Kill a session and whatever runs in it. Its logs and region files are kept on disk for a few days (session_logs keeps them for good, or deletes them). Refused for a session a person is attached to, and for another's while a command runs there: leave those to their owners, or ask the user to close it. Close what you are done with; a session another agent or a human started is theirs to close. A session that shares a window with others (a split) closes its own pane only; window closes them all.

ParametersJSON Schema
NameRequiredDescriptionDefault
windowNoclose every session sharing this session's window (its split panes) too, not only this one
sessionYesthe session's name (from session_create or session_list)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so: it discloses retention behavior (logs and region files kept a few days, session_logs keeps or deletes them), refusal conditions, ownership constraints, and the split-pane vs whole-window destruction scope. This is exactly the context annotations would otherwise supply.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then layered with retention, refusal, ownership, and scope details. Dense and mostly waste-free, though the parenthetical about session_logs and the repeated ownership sentences could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation. Given the tool's mutation semantics and the absence of annotations, the description covers everything an agent needs: what is destroyed, what is retained, who may call it, and how splits behave.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents both parameters and the baseline is 3. The description adds practical meaning to `window` by framing the pane-vs-window distinction in usage terms ('closes its own pane only; window closes them all'), which goes slightly beyond the schema's mechanical wording.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Kill a session and whatever runs in it') and immediately differentiates from siblings by naming `session_logs` and the `window` flag. An agent can distinguish it from session_create/session_list/session_split without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use ('Close what you are done with'), when-not (refused for attached sessions and for another's while a command runs), and alternatives ('leave those to their owners, or ask the user to close it'). Ownership rules are spelled out rather than left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

session_createA

Start a terminal session: a tmux pane a human can watch or type into, whose output is logged in full and kept as numbered regions. Use one instead of a one-shot shell call for anything that runs a program with a prompt (gdb, python, ssh, any REPL), takes more than a few seconds (a build, a testsuite), prints more than a reply holds, may ask a question (y/n), or that the user may want to watch or take over; a one-shot call stays right for reading and editing files and for quick commands whose whole output you want. Open one at the start of a task and do the task's shell work in it with the run tool: sessions are cheap, keep running between calls and across your own restarts (session_list finds them), and keep their cwd, environment and running programs -- cd once, start gdb once.

With no command (or "bash"), the session is bash with shell integration: exact command boundaries and exit statuses, and programs are started from it with the run tool (make, gdb, python, ssh, ...). command runs another program as the session itself instead, e.g. "gdb -q -ex 'break main' -ex run ./prog" or "ssh host"; when it exits the session is over. One session per job is the usual shape: a shell for the build and the tests, a second one for gdb while the first is busy.

Tell the user the session's name and attach command (in the reply) on a line of its own, so they can watch or step in. First time here: load the terminal-sessions skill if one is listed, else guide.

By default the pane follows the window of a human who attaches, so cols/rows apply only until then; fixed_size keeps them (the human then sees the pane clipped or padded). session_resize changes either later.

ParametersJSON Schema
NameRequiredDescriptionDefault
cwdNoworking directory (default: the server process's own)
envNoenvironment variables set in the session, on top of the server's environment
colsNoterminal width in columns
nameNoa name for the session (default: t1, t2, ...); the name of a closed session archives its old logs
rowsNoterminal height in rows
commandNothe program to run instead of bash with shell integration, e.g. "gdb -q ./prog" or "ssh host"; "bash" or "zsh" (with -i/-l) is that shell with the integration, "bash --norc" or "zsh -f" a plain one
fixed_sizeNokeep cols x rows even when a human attaches (the default lets the pane follow their window)
prompt_patternNothe session's default prompt regex for `run`/`expect` into a program; not for bash, and rarely needed (see `run`)
delete_logs_on_closeNodelete the session's logs when it closes, for one that may show something sensitive (see session_logs)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so: sessions are cheap, persist between calls and across agent restarts, retain cwd/environment/running programs, and are discoverable via `session_list`. It also discloses non-obvious behavior such as the pane following the human's window unless `fixed_size` is set, and that a `command` session ends when the program exits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and the use/don't-use rule before the mechanics. It is long and dense with parentheticals, but nearly every sentence carries operational information for a genuinely complex tool; there is little outright padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation, and all 9 parameters are covered by the schema. The description supplies the surrounding context an agent needs โ€” lifecycle, persistence, human-attach behavior, and pointers to sibling tools (`run`, `session_list`, `session_resize`, `session_logs`, `guide`).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: `command` semantics (bash/zsh with integration vs plain vs arbitrary program, and that session ends on exit), `cols`/`rows` applying only until a human attaches, and `name` defaults plus the archiving behavior of reused names. It stops short of explaining `env`, `prompt_pattern`, or `delete_logs_on_close` beyond what the schema already says.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Start a terminal session') and immediately defines the resource as a tmux pane a human can watch or type into, with full logging and numbered regions. It explicitly distinguishes itself from a one-shot shell call, so an agent can tell it apart from `run`/`shell_integrate` without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use criteria (programs with a prompt like gdb/python/ssh/REPLs, long-running builds or testsuites, output larger than a reply, may ask y/n, user may want to watch) and explicit when-not (one-shot calls stay right for reading/editing files and quick commands). It also prescribes the workflow: open one at task start, do shell work via `run`, one session per job.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

session_listA
Read-only

List terminal sessions: state, what is running, size, who started each (you, a human, another agent), humans attached, the attach command, and presence: how old each session is, its last output, which agents typed into it and when, a human terminal's last input, a typing call in progress -- to judge whether a session you find is in use. Sessions started by earlier servers or by others are used by name like your own; a closed session's logs stay on disk for a few days (the listing says until when; session_logs keeps them). Worth a call at the start of a conversation: a session from an earlier one may still be running, its log intact.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only carry readOnlyHint=true, so the description adds real value: it discloses that sessions from earlier servers/agents are addressed by name like your own, and that a closed session's logs persist on disk for a few days with an expiry shown in the listing. It does not mention pagination or result limits, keeping it below 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the value of the listing, then usage, then persistence behavior โ€” every clause carries information. The multi-line run-on enumeration of presence fields is dense but does not waste sentences; slightly awkward phrasing keeps it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless, read-only listing tool with an output schema, the description covers purpose, when to invoke, cross-session addressing, and log retention. The agent has everything needed to decide to call it and how to interpret what it gets back.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing to disambiguate and no compensating burden on the description. Baseline of 4 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (list terminal sessions) and then enumerates the exact facets returned: state, running process, size, originator, attached humans, attach command, presence. It also distinguishes itself from sibling session_logs by noting logs persist after close. An agent can pick this over session_logs or session_create without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context ('worth a call at the start of a conversation' because an earlier session may still be running) and routes to the related tool session_logs. It stops short of an explicit when-not-to-use clause or a named competing call, so it lands just below a full 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

session_logsA

Keep or delete a session's logs (its log directory: the full output, regions, raw bytes). The usual rule: a closed session's logs are deleted once they have been neither written nor read for a few days (DOCENT_TERMINAL_MCP_KEEP_CLOSED_DAYS, default 3). Reading a closed session's logs needs none of this -- and counts as use: the read, search and regions tools work on them as they are. Change how a session's logs are kept only when the user asks: "keep" exempts a session they want to refer back to; "delete_on_close" and "delete" are for logs that showed something sensitive. Deleting cannot be undone: ask the user first, and never delete another agent's or a human's logs unasked.

ParametersJSON Schema
NameRequiredDescriptionDefault
actionYes"keep": never delete them (when the user asks for that); "default": back to the usual rule; "delete_on_close": delete them when the session closes (at once if it is closed); "delete": delete them now (closed sessions only)
sessionYesthe session's name, live or closed (an earlier session of a reused name is NAME.N, as session_list shows)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses the default retention rule and env var (DOCENT_TERMINAL_MCP_KEEP_CLOSED_DAYS, default 3), that reading counts as use, that deletion is irreversible, and a social/auth constraint about not deleting other agents' or humans' logs unasked.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core verb and resource, then retention rule, then guidance. Mostly tight, though the retention and irreversibility points could be trimmed slightly without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need no explanation, and the description fully covers the one non-obvious thing an agent needs: the retention semantics behind each action and the irreversibility of delete. Nothing material is missing for a 2-parameter mutating tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the enum values are already documented in the schema, so baseline is 3. The description adds real meaning on top by tying actions to intent (keep = exempt a session the user refers back to; delete_on_close/delete = logs that showed something sensitive), which helps action selection beyond the schema's literal phrasing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb pair (keep/delete) and a specific resource (a session's log directory: full output, regions, raw bytes). It is clearly distinguishable from siblings like read/search/regions, which it explicitly contrasts itself against.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use (only when the user asks to change retention), when-not-to-use ('Reading a closed session's logs needs none of this'), and names the alternatives (read, search, regions) plus the conditions selecting each action ('keep' for refer-back, 'delete_on_close'/'delete' for sensitive logs).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

session_resizeB

Set the pane size and pin it (fixed, the default: attaching humans no longer resize it), or with fixed=false let it follow the attached human's window again.

ParametersJSON Schema
NameRequiredDescriptionDefault
colsNonew width in columns (default: unchanged)
rowsNonew height in rows (default: unchanged)
fixedNotrue pins the size against attaching humans; false lets it follow their window again
sessionYesthe session's name (from session_create or session_list)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are supplied, so the description must carry the behavioral burden. It does disclose a real behavioral trait โ€” that attaching humans stop resizing a pinned pane, and regain that ability with fixed=false โ€” but says nothing about persistence, error cases, or what happens when cols/rows are omitted. Partial disclosure for an unannotated mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence leads with the core action, then qualifies it with the default and the alternative. The nested parenthetical makes it slightly more convoluted than necessary, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be explained. The description covers the resize/pin behavior adequately, but for a session-mutating tool with no annotations it omits the effect of omitted cols/rows and any failure modes or session-state requirements.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents cols, rows, fixed, and session in detail. The description largely restates the `fixed` semantics already present in the schema, adding no syntax or format detail beyond it. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Set the pane size') and immediately explains the pinning semantics of the `fixed` flag. It is clearly distinct from siblings like session_split or session_create, though it never explicitly names or contrasts a sibling. A clear but not sibling-differentiating definition.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied through the two modes described (pin vs. follow the attached human's window), which tells the agent the effect of each choice. However, there is no explicit when-to-use guidance, no prerequisites, and no routing to alternatives such as session_split for layout changes.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

session_splitA

Split a session's window: a new pane beside it, shown together to a human attached to that window, and a session of its own -- logged from its first byte, with shell integration (exact exit statuses) by default. Use it instead of typing tmux split-window, whose pane has neither until the server adopts it. For two things to watch at once: a testsuite running in one pane, gdb in the other. Both panes are addressed by session name; typing never follows the active pane.

ParametersJSON Schema
NameRequiredDescriptionDefault
envNoenvironment variables set in the new pane
nameNoa name for the new session (default: <window>+1, +2, ...)
sizeNothe new pane's size: rows (below) or columns (right), or a percentage such as "50%"; default half
belowNotrue: the new pane goes below; false: to the right
commandNothe program to run instead of bash with shell integration, as for session_create
sessionYesthe session whose window to split (its pane is the one split)
prompt_patternNothe new session's default prompt regex, as for session_create; rarely needed

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and largely does so: it discloses that the new session is logged from its first byte, that shell integration yields exact exit statuses by default, and that both panes are addressed by session name with typing never following the active pane. It still omits failure modes (e.g., behavior when the session is missing) and permission requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and differentiation are front-loaded in the opening clause, and the remaining sentences each add distinct value (the tmux comparison, the concrete use case, the addressing rule) without restating structured fields. Size is appropriate for a 7-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, and the description covers the key behavioral traits an agent needs (logging, shell integration, addressing). It is slightly short on error behavior and on routing versus the sibling session_create.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter is already documented in the schema, making a baseline of 3 appropriate. The description adds only the general framing of pane addressing and does not clarify parameter syntax or interactions beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb (split) and resource (a session's window) and explains the resulting artifact: a new pane shown beside the original plus a session of its own. It clearly distinguishes itself from raw `tmux split-window`, but does not explicitly differentiate from siblings like session_create, which also creates sessions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear when-to-use ('Use it instead of typing `tmux split-window`, whose pane has neither [logging nor shell integration]') and an illustrative scenario ('a testsuite running in one pane, gdb in the other'). What is missing is explicit when-not guidance relative to the sibling tool session_create.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

shell_integrateA

Add shell integration to the bash now waiting at the prompt: exact command boundaries and exit statuses for run there.

Sessions started without a command have it already, and so does any bash started inside them. A shell that could not inherit it -- one reached through ssh or su - -- falls back to prompt matching, with no exit statuses; call this at its prompt, typically right after run ssh host came back at the remote prompt. Types one short line that reads the integration file: this server's own on this host; on another host the copy the user installed there with docent-terminal-mcp install HOST (without it the reply says so; docent-terminal-mcp ssh HOST needs none). For bash and zsh, and only at a prompt.

ParametersJSON Schema
NameRequiredDescriptionDefault
forceNotype even over someone else's unsubmitted line, and without checking that the cursor is at a shell prompt
sessionYesthe session's name (from session_create or session_list)
timeout_sNoseconds to wait for the integrated prompt to appear

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses that it 'types one short line that reads the integration file', distinguishes the server's own file from a user-installed copy on another host, and warns when the reply will say the file is missing. It does not state permission requirements or what happens on partial failure, but the operational behavior is unusually well disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then conditions; every sentence carries real information. It is dense and slightly meandering with parentheticals, but no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need not be described, and the description covers prerequisites, host/file selection, and shell constraints thoroughly. Minor gaps around failure modes and permissions remain, but nothing essential for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents `force`, `session`, and `timeout_s`. The prose explains the prompt-context around `force` and the host/file distinction relevant to invocation, but adds no syntax or format detail beyond the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Add shell integration to the bash now waiting at the prompt', and clarifies what it enables ('exact command boundaries and exit statuses for `run`'). An agent can tell what the tool does, but it never explicitly differentiates itself from siblings like `run`, `expect`, or `guide` by name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly covers when it is NOT needed ('Sessions started without a `command` have it already'), when it IS needed (ssh/`su -` fallback to prompt matching), and where to call it ('call this at its prompt, typically right after `run ssh host`'). Names the prerequisite installer command and the alternative that needs no setup.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

waitA

Keep waiting for what is running in the session -- what your last call left running (a run that timed out, settled, or returned at until), or else a command a human or another agent started -- and return its region: only the lines not shown before. The interactive form of sleep 30; tail log: call it as often as needed, with timeout_s up to the client's patience; each reply is new output only, and the command's exit status when it ends. Commands of others that finished since your last call are reported at once (regions lists the session without waiting). When a human's (or another agent's) unsubmitted text holds the prompt, waits for it to be erased or submitted, and says which. After a run into a program (gdb, python), waits for the program's prompt; after a shell command, for it to finish. show filters the lines as for run; until returns at a pattern, last_lines and save_to work as for run.

ParametersJSON Schema
NameRequiredDescriptionDefault
showNoregex: reply with only the output lines matching it, in order, plus the last few (like `| grep`, but the command runs unfiltered and the log keeps everything), e.g. "error:|warning:|^FAIL" for a build -- or a program's answer: gdb's `step` under `set debug infrun 1`
untilNoregex: return as soon as output not shown to you before matches it, the command still running (as for `run`); one that never matches is a plain wait
save_toNoa file to copy the command's output into, as `> FILE 2>&1` would, while the command itself runs unredirected (the reply and the log are as usual): written at once, kept up to date while it runs, written in full when it ends. A relative path is in the session's current directory; the file is on the machine this server runs on, even for a session over ssh. For a later diff or grep by other tools; `read` and `search` need no file
sessionYesthe session's name (from session_create or session_list)
max_linesNolines of output shown in the reply; longer output is clipped in the middle, led by its summary lines (test results, compiler errors, make's failure) when the middle holds them; all of it stays readable with `read`/`search`
timeout_sNoseconds to keep waiting (the command keeps running after; `wait` again); at most 1500
last_linesNoreply with only the last N lines of the output (like `| tail -N`, but the command runs unfiltered and the log keeps everything; the reply says where the rest is); with `show`, how many last lines follow the matches (default 3)
show_afterNowith `show`: also this many lines after each match (like `grep -A N`); a match is numbered "N:", a line after one "N-"

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses that only not-shown lines are returned, that the command keeps running after timeout and needs another wait, that exit status is returned on completion, and how it behaves when a human's unsubmitted text holds the prompt. It omits error/failure modes but covers the core runtime behavior thoroughly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded, but the body is a dense paragraph of em-dash and parenthetical clauses that is harder to parse than necessary. Given the tool's complexity the length is defensible, yet several clauses could be tightened without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained. For an 8-parameter interactive wait with rich per-parameter docs, the description covers the key scenarios (program prompt vs. shell completion, human-held prompt, repeated polling) well; only error/edge handling is thin.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and each parameter already has a rich description, so the baseline is 3. The description's references to `show`, `until`, `last_lines` and `save_to` mostly defer to 'as for `run`' rather than adding meaning beyond the schema, so it neither compensates nor detracts.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening states a specific verb (keep waiting) and resource (what is running in the session), then narrows the scope to two cases: your last `run` that timed out/settled/returned-at-until, or a command a human/other agent started. It explicitly distinguishes itself from siblings, noting `regions` lists the session without waiting and that `read`/`search` need no file, so an agent can route without opening another schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context: call repeatedly with `timeout_s` up to the client's patience, after a `run` into a program wait for the prompt, after a shell command wait for it to finish. Alternatives are named (`regions` for a non-blocking listing, `read`/`search` for reading logs), though it stops short of an explicit 'when not to use'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 15 tool updatesv0.1.0
    • First observedexpect
    • First observedguide
    • First observedread
    • First observedregions
    • First observedrun
    • First observedsearch
    • First observedsend
    • First observedsession_close
    • First observedsession_create
    • First observedsession_list
    • First observedsession_logs
    • First observedsession_resize
    • First observedsession_split
    • First observedshell_integrate
    • First observedwait

TDQS

A4.1/5.0

Scored across 15 tools

Disambiguation4/5

Each tool has a distinct role: session lifecycle tools (session_create, session_split, session_list, session_resize, session_close, session_logs) are clearly separated, and interactive tools (run, send, wait, expect) are differentiated by whether they wait for completion, type keystrokes, or script prompts. Minor conceptual overlap between run/send/wait exists, but the detailed descriptions resolve it.

Naming Consistency4/5

All tools use lower_snake_case, and session management tools share a consistent session_ prefix (session_create, session_split, session_list, etc.). However, non-session tools are a mix of plain verbs (run, send, wait, read, search, expect) and noun_verb (shell_integrate), and 'regions' is a bare noun, so the pattern is not uniformly verb_noun.

Tool Count5/5

15 tools map cleanly to the domain's needs: 6 session lifecycle operations, 5 interaction tools, 3 output inspection tools, plus a guide. Each tool earns its place and no tool appears redundant or trivial for terminal session management.

Completeness5/5

The surface covers the full terminal session lifecycle: creating, splitting, listing, resizing, closing, and retaining logs, plus rich interaction (run, send, expect, wait, shell_integrate) and output analysis (read, search, regions). No obvious gaps for the stated purpose of managing and interacting with terminal sessions.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables AI assistants to execute shell commands and manage long-running processes within persistent tmux sessions across isolated workspaces. It features a dual-window architecture to separate raw command execution from interactive terminal output.
    8
    9 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to execute commands in a shared tmux session that is simultaneously visible to a human via a web-based terminal UI.
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables agents to interact with CLI applications like vim, htop, and gdb by sending key inputs and capturing terminal output through tmux sessions.
    6
    MIT