The tool is named codemode again and scripts configure it with a first-line // @options: {...} instead of the // @exec: pragma. yield_time_ms is gone; max_output_tokens and timeout_ms remain. Comments, docs, and tests no longer describe the tool in terms of another agent.
pi mcp list connects to every enabled server and reports its state, tools, and errors, exiting with 1 when anything fails, so agents can verify an mcp.json they wrote. pi mcp login runs the OAuth sign-in through the browser, and pi mcp logout deletes stored credentials. Running sessions reconnect servers waiting for a sign-in at the next turn when their credentials changed.
The system prompt points MCP questions to docs/mcp.md, which now covers setting up servers: which file to edit, rules that are easy to get wrong, converting entries from other clients, and verifying with pi mcp list.
The agent loop is back to main's tool execution: it only exports runToolCall(), honors isError results, and passes structuredContent through afterToolCall. Nested calls (ctx.executeTool, ids, events with parentToolCallId, the nestedCalls record) live in coding-agent and start on the first call.
AgentSession no longer knows exec or tool_search. Tools adjust the declared loadout through a generic prepareLoadout hook, and codemode and tool_search use it like any other tool.
exec and tool_search move to built-in extensions under src/extensions/ and register inactive (defaultActive: false). The CLI loads them with MCP; SDK sessions add createCodemodeExtension(), createToolSearchExtension(), and createMcpExtension(). Extensions gain pi.getSettings() and model catalog and classifier access on ModelRegistry.
- structuredContent after tool_result/afterToolCall: providing it replaces it; replacing content without it drops it. No more key-presence checks.
- Tools run outside a session get a ToolContext (loop services plus optional extension fields) instead of a context typed as a full ExtensionToolContext.
- Document that nested calls get synthesized <parent>/<n> tool call ids that never appear in the transcript.
- The exec description no longer mentions yield_time_ms, which is accepted and ignored.
- The sandbox abort test waits for the tool call instead of a fixed delay.
While exec is active, codemode.mode on (default) appends the exec declaration to declared tools that scripts can call and lists only non-direct tools in the exec description. codemode.mode only lists every callable tool in the exec description and hides active direct tools from requests. The hiding is a request projection, so the transcript still declares the active set and /tree and resume keep it.
The exec listing depends on exposure, not on the active set, so tool_search loads do not redeclare exec.
- The exec description spends at most codemode.inlineBudget (default 3000) estimated tokens on tool declarations, filled round-robin across namespaces, cheapest first. Every namespace is listed with its tool count, and the listing says COMPLETE or PARTIAL.
- Scripts find omitted and deferred tools with searchTools(query, { limit, namespace }) and describeTool(name).
- tool_search, an optional built-in modeled on Codex, searches codemode and deferred tools and declares the matches for the next model call through the active tool set, so loads are recorded on the branch.
- Both use a BM25 ranker over Codex's search text (name, description, schema properties, namespace) behind a ToolRanker interface.
The codemode tool is now exec and follows the exec tool of OpenAI Codex, so scripts written for Codex run unchanged:
- // @exec: pragma with yield_time_ms, max_output_tokens (default 10000 tokens) and the pi addition timeout_ms; Codex's grammar and error messages
- text(), image() (data URLs, { image_url }, MCP ImageContent), exit(), ALL_TOOLS, tools under normalized identifiers; console and return values append text
- Results start with Script completed/failed and the wall time; failed scripts return an error result that keeps partial output and appends Script error
- Output over the token budget keeps its start and end like Codex; the full text is spilled to a temp file
- MCP tools resolve to their CallToolResult (isError resolves) and are declared as CallToolResult<T>; bash resolves to { output, exit_code, wall_time_seconds }, also for non-zero exits
- The description uses Codex's layout: helper list, deferred-tool guidance, shared MCP types, one section per tool grouped by namespace (MCP servers, with their instructions)
Like bash output, a codemode result over 50KB or 2000 lines keeps its head in the tool result and writes the full return value as JSON to a pi-codemode-<id>.json temp file, referenced in the output and in details.fullOutputPath.
Scripts get models.getModelsOfType/getAvailableOfType/getModelOfType/classify, mirroring ModelRuntime. The host resolves models by provider and id so scripts cannot redirect credentials, strips headers from listed models, and runs at most four classifications per script at once. pi-codemode gains namespaced globals, spread arguments, and explicit signatures.
Codemode input is now the script itself, optionally starting with a // @options {"timeout": N} line, and the tool declares a Lark grammar so capable models write raw JavaScript. Scripts can keep JSON values with store()/load(); successful writes are appended as codemode-store custom entries and read back from the current branch.
Adds a built-in, opt-in codemode tool that runs model-written JavaScript in the codemode sandbox. Scripts call the other active tools as tools.<name>(args), including concurrently with Promise.all; only the return value, console output, and images attached with image() reach the model.
Nested calls run through the agent loop via a new AgentToolContext (5th execute argument, ctx.executeTool for extension tools), so argument validation and the beforeToolCall/afterToolCall hooks apply. Hooks and tool_call/tool_result events carry the parent call id.
Tools can declare outputSchema and return structuredContent; codemode passes that to scripts and falls back to text content otherwise. The codemode package gains globals, declaration rendering from JSON Schema, and optional deadlines.