Skip to content

Agent command system

The built-in Wuu engine uses bash to run commands and control background work in the session’s selected execution environment. Ordinary commands deliver their exit result; the optional Monitor extension observes ongoing changes in CI, APIs and logs. External engines have their own command implementations; this page describes Wuu’s tools.

The main agent carries authorized work through implementation, appropriate verification and a report of the outcome. It uses authorization already given in the conversation, resolves routine choices independently, and preserves the active objective when the user supplies a correction or asks for status. Reviews and planning requests alone do not authorize implementation; commits and remote writes still follow the session’s authorization boundaries.

General collaboration guidance is stable across model requests. Available tools, permissions and optional extension behavior come from the runtime rather than assumptions in the base prompt. Tool-specific recovery belongs in the tool’s result or description. Completed observations remain in order; new results and context changes are appended. Provider-native response items are retained for continuation, including after a session restart. Cache hits still depend on the provider and are measured from returned usage.

Code Mode is enabled by default. tools.bash exposes the same run and control actions as the direct tool. Await the background start before returning from a program; save its handle with store if another program needs it. Use searchTools("monitor") and describeTool(name) to discover the extension’s exact names and schemas, then call tools[name](args). The extension owns the accepted watcher after the program returns. Disabled extensions contribute neither tools nor guidance.

Inside run_code, tools return producer data for filtering and computation. Printing a tool result emits its structured_content, or its content when structured data is absent; it does not substitute the direct tool’s compact display. Set max_output_tokens in the first-line // @run_code: options to bound the combined text sent to the model. Output beyond that budget is saved with a recovery reference. Completed observations remain unchanged on replay.

Producer limits still apply: file/search pagination, process read ranges, command stream transport limits, and media size limits are separate from the model’s text budget. Follow the returned continuation or full-log reference when a producer reports omitted data.

bash defaults to action=run and takes command, timeout_seconds, cwd, run_in_background, completion_mode, purpose, and scope:

{
"command": "go test ./internal/process",
"timeout_seconds": 300,
"purpose": "Check process lifecycle behavior",
"scope": "targeted"
}

The model receives the command’s output as a terminal would show it: stdout, then stderr. A successful run adds nothing else. The model sees extra lines only when they change the next step: Exit code N for a failure, the full-log path when a stream was cut, a timeout hand-off, or a sandbox denial. Each stream keeps its head and tail, so a test runner’s summary survives even when the middle is cut. Terminal color codes and progress-bar redraws are removed from this view. Recognized test, build, lint, and type-check commands also record verification metadata; the model sees the failure summary only when the output was cut, without injecting an additional failure summary into later requests or blocking a retry at the same workspace revision. scope describes the intended coverage (targeted, affected, or full) and does not change which tests run. purpose is kept in the audit log only.

Clients and durable records keep the full JSON envelope: exit code, duration, both excerpts, byte counts, classification, workspace revision, the full-log reference and hash, and verification details. The desktop terminal panel renders from that envelope.

Commands must be non-interactive: do not depend on an editor, pager, or terminal prompt. timeout_seconds defaults to 300, with a range of 1–3600. When background handoff is available and early handoff is enabled, Wuu ends the foreground wait after 10 seconds or the requested timeout, whichever comes first. The same process keeps running, with its output and ownership preserved; the result includes its process ID and completion is delivered to the owning conversation. Independent tools can proceed after the handoff. Work that depends on the command must await its completion. A process ID is not a successful verification or proof that the command stopped. Early handoff leaves timed_out false and exit_code at -1; promoted_process_id identifies pending work. If early transfer fails, the original foreground wait continues until the requested timeout; if transfer is still unavailable then, Wuu stops the process. Cancelling the calling turn stops a foreground command rather than promoting it. Side conversations keep the requested foreground wait because they do not resume from background completion. These wait limits do not impose a background process lifetime.

Start a server, watcher, or interactive command with run_in_background rather than appending &:

{
"command": "npm run dev",
"run_in_background": true
}

The call returns the process ID immediately. Background commands run in a pseudo-terminal so the desktop can take them over; macOS and Linux support PTYs, while Windows falls back to pipes. A natural exit is delivered at the next model step when the owning conversation is active; otherwise it starts a continuation, which wuu exec waits for. Results already read by the model do not trigger another delivery. Successful consumption is persisted with the answer so restart recovery does not repeat an acknowledged result. For a long-lived service whose exit should not resume or hold open the task, set completion_mode=detached at background launch or with bash action=update.

If a completion continuation fails or is interrupted, its notification stays pending. Provider retries use the existing bounded backoff policy; reaching a terminal failure does not start another automatic turn. Reopening the conversation or receiving another process event does not retry the failed notification. A later human message permits recovery. Paused notifications do not keep unrelated successful work waiting for an automatic continuation.

bash also controls running commands:

ActionUse
readRead output using process_id; pass the returned next offset as offset_bytes for incremental reads
writeSend input to a process with a live input handle; include a newline when needed
stopStop the process tree
listInspect the session’s managed processes
updateChange completion_mode (resume or detached)

Reads return up to 32 KiB by default. Without wait_ms, a read is a snapshot. With it, the call waits for new output or exit, up to 300,000 ms. Continuously arriving output is paced rather than returning on every byte. Control results reach the model as short plain text, while clients keep the JSON envelope.

Command completion is event-driven; there are no timed model rechecks. Use Monitor for ongoing observation. Its script owns polling intervals, filtering, transient retries and stop conditions. Complete stdout lines produce events; stderr retains diagnostics without waking the model.

Historical process and legacy bash records remain renderable. New calls use bash control actions; the standalone process tool is no longer registered.

cwd defaults to the workspace root and must resolve to an existing, permitted directory. Worktree-bound workers execute in their assigned checkout. Each bash call starts a new shell; cd, aliases, and temporary environment changes do not persist between calls.

Wuu resolves Bash through its shell launcher, including Git Bash on Windows. Foreground and background commands use the shared environment preparation: inherited build-time GOROOT is removed and non-interactive defaults are applied. PTY startup restores terminal-oriented settings where needed.

Command classification helps with permission checks and scheduling, but is not the filesystem sandbox. In confined modes, foreground and background commands use the configured filesystem process sandbox. A missing enforcement provider causes launch failure rather than silently running unconfined. The built-in backend uses Seatbelt on macOS and Landlock on Linux. Linux requires a kernel with Landlock ABI 3 or later enabled and available to the process; an unavailable backend fails closed. Network isolation is outside this contract. See permissions for modes and platform limits.

A denied write is not an invitation to retry through another shell command. Add an authorized workspace root or explicitly change the session mode when the task requires access outside its boundary. Wuu does not offer per-command approval prompts.

All built-in model profiles use read_file for file evidence, edit_file for targeted changes, and write_file for new files or complete rewrites. Switching models or starting a worker keeps these editing tools. Local models retain their existing restriction on command execution.

After reading a file, call edit_file with text copied from the current contents:

{
"path": "example.txt",
"old_text": "hello",
"new_text": "hello world"
}

A missing or ambiguous match leaves the file unchanged and returns candidate locations for recovery. Read the relevant range and retry with enough exact context; use replace_all=true only when every occurrence should change. For a new file, call write_file with path, content, and optionally create_only=true to reject an existing target. Existing files larger than 32 KiB retain the overwrite policy requirement. Both editing tools retain path and permission checks and publish file changes with structured diffs.

Run validation separately with bash when command execution is available:

{
"command": "test -f example.txt",
"timeout_seconds": 30,
"purpose": "Check the new file exists"
}

A failed command leaves completed edits in place. If validation moves to the background, wait for its terminal result before treating it as passed. Retry validation without repeating successful edits.

Wuu no longer executes the built-in apply_patch tool or its dry_run and then_run options. Historical patch records remain readable and visible when a conversation resumes; new edits use the tools above. Tools managed by the external Codex engine are unchanged.

With Code Mode enabled, read_file, write_file, edit_file, bash, and process remain directly callable. Use run_code for composition or computation; basic operations need no JavaScript wrapper. Explicit rereads return the requested content. Nested results retain canonical data; only emitted output is budgeted and archived for recovery, without rewriting earlier conversation history.

Normal command output and its saved full log are redacted before being returned or persisted as a tool log. Background process records and merged stdout/stderr logs can contain raw text on disk; redaction happens when the tool returns them. Keep secrets out of arguments and output, and review logs before sharing them.

Live background logs can grow. Finished logs are compacted to an 8 MiB tail, and startup maintenance expires terminal records and logs after 30 days when no completion remains undelivered. A returned byte offset may therefore precede retained output; use the returned offsets rather than assuming the whole log remains available. Foreground commands also buffer output in memory while running, so unusually noisy commands can consume substantial memory.

The default lifecycle=session participates in runtime cleanup; managed skips that session-lifecycle cleanup. Neither is an operating-system service manager. Restarting Wuu cannot restore a lost PTY or stdin handle, and a recovered process may lack a reliable exit code. Stop unneeded processes explicitly instead of relying on a conversation tab’s lifetime. Before stopping, Wuu checks process identity to avoid targeting a reused PID, then requests a graceful stop before escalating to the process tree.

Desktop process controls and the model’s tools use the same manager. App-server process methods check thread ownership; clients cannot operate on another thread’s process simply by guessing its ID. For embedding details, see the app-server protocol.