Expand description
Prefix mode: agentmux-bashwrap '<script>' as Claude Code’s
CLAUDE_CODE_SHELL_PREFIX.
The CLI runs every Bash tool command as <prefix> '<its script>' when the
variable is set, and leaves the tool call itself alone: its permission
rules, labels and checks see the model’s own command. The PreToolUse
hook records each call here (register) instead of rewriting it; the
prefix process takes the model’s command back out of the CLI’s script,
claims the matching record for the call’s tool_use_id, and runs the
whole script the way exec runs a command (bash_wrap.rs).
docs/specs/SPEC_BASH_STREAMING_VIA_SHELL_PREFIX_2026_10_10.md §2.
Structs§
- Call
Record - One Bash call, as the hook saw it.
Constants§
- CALLS_
DIR_ 🔒OVERRIDE_ ENV - Overrides where records are kept (tests).
- MAX_
DESCRIPTION_ 🔒CHARS - The longest description reported for a call.
- RECORD_
MAX_ 🔒AGE - Records older than this are deleted on each claim: a call the CLI never ran (denied, interrupted) leaves its record behind.
- SESSION_
ID_ ENV - The CLI’s session id, as the prefix process sees it. Equal to the
session_idin the hook’s payload. - SHELL_
PREFIX_ ENV - The CLI’s environment variable naming the prefix.
- SUBCOMMANDS 🔒
- The subcommands, which a lone argument must not be mistaken for.
Functions§
- calls_
root 🔒 - claim
- Claim the record of the call this script runs: the newest one for the
session whose command is
command; failing that, the session’s only record. Newest, because the hook records a call just before the CLI runs it, while a call the CLI never ran (a deny rule, a refused prompt) leaves an older record behind that a retry of the same command must not take. A claim renames the record away, so two prefix processes never claim the same call.Nonewhen there is nothing to claim: the script then runs unlinked. Only a Bash call’s script, one with a command in itseval, ever claims (run). - extract_
command - The model’s command inside the CLI’s script, and where its quoted form
sits in the script: the shell word after the CLI’s
eval, which the CLI quotes with single quotes (an embedded'becomes'"'"').Nonewhen the script doesn’t have one, e.g. after a change to the CLI’s format. - is_
bashwrap_ 🔒path - new_
record - A record for a call the hook just saw.
- prefix_
active - Whether this process runs under a CLI whose shell prefix is AgentMux’s wrapper, so the hook records calls instead of rewriting them.
- prefix_
script - The script, when this process was started as the CLI’s shell prefix: exactly one argument, which is neither a subcommand nor a flag.
- read_
records 🔒 - The session’s unclaimed records, deleting any past their age.
- read_
shell_ 🔒word - Read one shell word starting at
start: single-quoted, double-quoted and backslash-escaped parts, up to unquoted whitespace or the end. Returns the word’s value and the byte offset after it. - register
- Record a call for the prefix process to claim. Written to a temporary
name and renamed, so a claim never reads half a record. Then other
sessions’ leftovers are swept (
sweep_other_sessions). - replace_
command - The script with the command at
rangereplaced bycommand. - report_
call 🔒 - Tell srv which call this process runs, once per linked call, so srv can say which tool call a process tree is (Tower’s “started by”): this wrapper’s pid, the call and what it does. srv keeps it and does not forward it to the pane, which would take an unknown op for output. SPEC_TOWER_AGENT_CENTRIC_VIEWS_2026_10_08.md §5.3. Best effort.
- run
- Run the CLI’s whole
scriptfor the Bash call it belongs to, streaming it exactly asexecstreams a command. The call is the record the hook left for this session’s command. A script that can’t be linked to a call (aclauderun by hand or nested inside an agent, whose session has no records, or the CLI’s own shell calls) runs as plain bash, as if there were no prefix: no live output, nothing else changed. docs/specs/SPEC_BASH_STREAMING_VIA_SHELL_PREFIX_2026_10_10.md §2.2, §2.3. - run_
passthrough 🔒 - Run a hook command or an MCP server’s command line on this process’s own stdio, untouched: an MCP server speaks JSON-RPC on it, so one added byte breaks it. A lone word is a program, started directly (no shell to mangle a Windows path, nothing to locate first); anything else is a command line, which the CLI joined unquoted, so bash runs it. Except on Windows when the program is a Windows path: bash would strip its backslashes, and only an MCP server’s line can have one (the CLI makes a hook’s paths POSIX), so it is split back into words, as the CLI joined it.
- run_
plain 🔒 - Run
scriptwith bash on this process’s own stdio, for its exit code. - run_
program 🔒 - Become the program, so the CLI’s signals and pid reach it. Returns only when it can’t be started.
- sanitize 🔒
- session_
dir 🔒 - single_
quote sas one single-quoted shell word, the way the CLI quotes it.- sweep_
other_ 🔒sessions - Every other session’s directory: its stale records deleted, and the directory itself removed once nothing is left in it. Sessions end without telling anyone, and a call the CLI never ran (denied) leaves its record; without this both would stay forever.