Built-in tools

Contracts and implementation notes for the first-party tool surface.

TUI rendering

The TUI keeps tool-heavy transcripts compact by rendering built-in tool calls as short status rows, for example tool> run read README.md:1-20 or tool> run $ make test. When the result arrives, the call/result pair folds into a single console-friendly row such as tool> ok read README.md (42 lines, 3.1KB) or tool> err read missing.txt (1 line, 24B). Use /expand or ctrl-o in the TUI to toggle expanded tool-result body previews under the paired summary row. Expanded previews are capped by the presenter preview limit so very large outputs do not flood the transcript.

Tool-result sanitation

Fen sanitizes provider-visible tool-result text before new results are emitted and stored in the JSONL transcript; those sanitized stored results are then safe to replay to later provider calls. Raw NUL bytes, invalid UTF-8 bytes, and control bytes other than tab/newline/carriage-return are escaped as visible ASCII such as \\x00. Each text block in a tool result is also capped by bytes (FEN_TOOL_RESULT_MAX_BYTES, default 65536), and Fen appends an explicit marker when output was sanitized or truncated. This is a final safety net against provider 400s and wedged sessions; tools should still summarize or truncate domain-specific output themselves when possible. The sanitizer preserves the required one-result-per-tool-call pairing rather than dropping unsafe results. Structured details payloads are preserved for presenters/replay and are not sent to providers. Already-written legacy sessions are repaired separately at provider replay/session-doctor boundaries.

Tools

Built-ins are registered by the first-party builtin_tools extension and their implementations live under extensions/behaviors/kernel/builtin-tools/. They mirror pi-mono's bash, read, write, ls, edit, grep, find. POSIX-only stance:

What's deliberately not ported from pi-mono (per the "balanced" port decision): file-mutation queue, bash streaming/onUpdate, syntax-highlight cache, image MIME detection, edit's fuzzy match + diff library, fd/rg backends.

Cooperative execution

Tool executors may receive an optional cooperative yield callback from the agent loop. Long local work should call it between chunks, scans, pipe reads, and writes so the TUI can repaint and observe cancellation. The callback may raise to cancel the operation. Tools that open files, pipes, subprocesses, or spill outputs must close those resources before rethrowing cancellation or other errors. This callback is an implementation detail of the runtime and is backward-compatible with tools that ignore the extra argument.

The first-party todo companion extension separately registers todo_write. It lets the model overwrite a structured session todo list. It stores the snapshot in the tool-result details payload for replay. It exposes /todos, a TUI panel, a status item, and introspection.