Move the codemode script reference, including the models API, into
docs/codemode.md and keep only one line per global in the tool
description. Declared tools get a one-line note on how scripts call them,
and the codemode system prompt guidance and MCP server section are shorter.
With the default tools a GPT-5.6 request drops from about 5,300 to 3,300
tokens.
Errors now point the way back: unknown tools and models members name close
matches, models.classify() and models.generateImages() validate their
arguments, unknown or mistyped models point to getAvailableOfType(),
store() overflow explains the store, and unshown generated images get a note.
Scripts run image models with the session's credentials, like
models.classify(). Results are base64 image blocks that image() attaches
to the codemode result; usage counts toward the session cost.
The top-level /login menu offers Sign in with Radius with its status,
with an animated shimmer on the Radius row and a short Radius intro.
After a Radius sign-in it offers to configure the Radius MCP server in
the global mcp.json with auth.provider and reloads. Cancelling a login
returns to the menu it was started from. OAuth sign-ins without a
subscription are labeled as accounts.
Co-authored-by: niloc <5925270+colindaymond@users.noreply.github.com>
Session workers now host a durable Harness over a per-session sqlite storage.
The server keeps each session in <sessionDir>/<id>/ with meta.json and
session.sqlite and never opens the storage itself. Workers hold retirement
while the Harness task graph has live tasks and resume interrupted work on
open.
Transcript serves the root conversation's durable view directly, Models
follows the conversation's agent document, and AgentController maps prompt,
steer, follow-up, queue cancellation, abort, and compaction onto the root
conversation, plus waitForPrompt. navigate, nextRun, and resume are dropped
(see experimental/services/README.md TODO). The durable TUI and the worker
share harness-setup.ts.
pi-server exports its own SessionMetadata and no longer depends on
pi-agent-core. Chord accepts readonly JSON types in service contracts without
walking them, which recursive JSON types like pi-ai's made too deep.
pi-agent-core now contains only Agent, the agent loop, the proxy stream, and
their types. Removed the harness, sessions and session storage, pico3, harness
tools, compaction, skills, prompt templates, telemetry schemas, search types,
and the uuidv7 and pi-telemetry re-exports, plus the ./node, ./harness/* and
./experimental/pico3 subpath exports. Durable sessions live in
@earendil-works/pi-durable.
Also removed packages/session-backends and the experimental mini and micro
coding-agent frontends, with their scripts and build configuration.
Palette colors now keep the bell-curve falloff and are
also capped at the palette color's OKLCH chroma times that falloff.
Lightness and hue are unchanged, so contrast is unchanged.
closes#10255
The session restored its tool loadout before MCP servers reconnected, so deferred tools that tool_search had loaded were dropped. Restored tools that are not registered yet now stay pending and are activated when they register, until a setActiveTools() call deactivates a tool or the next prompt starts.
The user message's Markdown pads and colors its own background instead of
sitting in a Box that kept a second full-width copy of every line. The output
is identical.
Markdown holds its parsed tokens weakly: a token tree is about ten times its
source, and every transcript message keeps a Markdown component. The tokens
still survive bursts of re-renders such as theme previews. Markdown, Text, and
Box flatten their cached lines, which V8 otherwise keeps as trees of the
concatenated parts. A long assistant message keeps about a fifth of the heap.
Runs the pinned @modelcontextprotocol/conformance client scenarios for 2025-03-26, 2025-06-18, and 2025-11-25 against pi's MCP connection and OAuth sign-in, and fails on regressions against a committed check-level baseline.
A step-up sign-in requested only the scopes of the insufficient_scope challenge, so the new token lost the scopes granted before and other requests asked for sign-in again. Tokens now record their granted scope and step-up requests the union (SEP-2350).
--provider without --model was ignored and the default model from
another provider ran instead. It now fails with an error. Also fixes
the outdated "(default: google)" in the --help text.
closes#10236
A small local agent in src/experimental/durable: pi's model runtime, settings,
system prompt, theme, and interactive components over a durable Harness with
SQLite storage. Streaming, tools, steer and follow-up, abort, model and
thinking selection, compaction, --continue with recovery of interrupted turns,
a subagent tool with /agents to switch to and talk to subagents, and a live
/tasks panel from the task graph view. The tsconfig path for
@earendil-works/pi-durable/* resolves subpaths to source.
Package 22: runtime.now() and report() throw after the invocation ended; a
migration-only commit is published; a failed Harness.open closes without the
caller's context and rethrows the open error; ConversationWatch alias. Tests
for close joining non-cooperative code, cancelled close, queued operations at
the seal, progress calls and viewers on a paused Harness, the Chord guide, and
the spec's usage examples.
Package 23: Harness.taskGraph() and watchTaskGraph() mount every live task with
its owner edge, committed status, flags, and owned conversations, advanced from
commit publications. Example 24 prints the checkout's tree.
Close ends states and watches at its seal, joins non-cooperative code, and a
cancelled close cancels only its wait. Conversation.abort() starts scheduling.
New section 9.5 specifies Harness.taskGraph() and watchTaskGraph(). The Chord
guide uses real imports and documents shutdown order.
Empty or null optional fields in OAuth token and registration responses
(scope, refresh_token, id_token, client_secret) failed sign-in, and
expires_in: null marked tokens as expired. Also fall back to the server
origin when resource metadata has invalid URLs, skip empty scopes when
selecting the requested scope, and end pagination at an empty or null
nextCursor.
closes#10266
- Registry of named extensions (tools, sections, hooks, wraps, tasks) with install/uninstall;
defineExtension, defineTool, section, hook, wrapTool, wrapSection
- pi.agent document (model, thinking level, extensions, tools filter, instructions, cwd),
configure(), Conversation.agent()/configure(), agent option on root/createConversation/fork,
task-owned conversations copy their owner's agent
- Harness-wide HarnessSettings read at every use; env function built per use
- Hooks and the agent resolved per task phase; tool calls resolved with the tools filter applied
- ToolRegistration<TParameters, TDetails> types execute() args from parameters
- HarnessOptions.conversationCreated; Tx.submissionByRequest() and Tx.createSubmission()
- FileSystem.id; edit/write serialize per file system id and canonical path
- CodingTools extension (read, write, edit, bash)
- Examples 06-31 on the new API, README and CHANGELOG
Extensions installed by name, the rewindable pi.agent document with configure(),
Harness-wide live settings, env built per use, typed tool args with defineTool(),
HarnessOptions.conversationCreated, Tx submission methods, FileSystem.id for
edit/write serialization, and tool resolution with the tools filter applied.
The configured metadata document replaces discovery and is trusted as
configured. Authorization codes are only exchanged when the response's
iss parameter names the flow's authorization server.
closes#10172
Claude Code's OAuth client also accepts https://platform.claude.com/oauth/code/callback
as redirect_uri. That page shows the authorization code to copy, which works when
the browser runs on another machine than pi, where the localhost callback cannot load.
Anthropic login now asks for a method like OpenAI Codex login: browser (default)
or copy code (headless).
- drop AsyncLocalStorage misuse guards from the Node adapter
- run calls immediately when the queue is idle; transactions publish their barrier before the callback starts
- SqliteStorage.close() waits for admitted multi-query reads and shares one close promise
Adds Anthropic workload identity federation from the SDK env vars
(ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
ANTHROPIC_IDENTITY_TOKEN_FILE, optional ANTHROPIC_SERVICE_ACCOUNT_ID and
ANTHROPIC_WORKSPACE_ID). Keys and ANTHROPIC_AUTH_TOKEN keep precedence.
The federation client is reused across requests so the SDK's token cache
avoids a token exchange per request, and the SDK's own credential chain is
disabled so pi's auth resolver stays the only source of credentials.
closes#10177
Replace prepare/SqliteStatement with run/get/all(sql, ...params) on the database and transaction handles. The Node adapter caches prepared statements per connection, so transactions reuse them instead of preparing again on every commit.
Read documents in one transaction so a concurrent commit cannot replace the base between the record and revision queries.
HTTP MCP servers can set "auth": { "provider": "<provider>" } to send the provider's current /login token as the bearer token instead of using MCP OAuth. The token is read on every request, so provider refreshes apply and nothing is copied to mcp-auth.json. Only allowed in the global mcp.json and from extensions, and requires https except on loopback hosts.
MCP tool and namespace names now replace - with _ like Codex, so the
pi tool name is also the codemode identifier. Tools of a server whose
names collide all get a hash suffix, and server names that differ only
in - and _ are rejected.
closes#10239
Manual compact(), background and blocking threshold compaction, and overflow
compaction with one retry. Summaries are headed pi.compaction entries placed
through the inbox, or appended by a compaction the generation waits on; the
stale rule decides between concurrent summaries.
When the session's initial tools come from defaultTools, /reload activates
names added to the resolved selection. Removals do not deactivate tools, and
explicit --tools/--no-tools/--no-builtin-tools keep overriding the setting.
closes#10245
In codemode.mode "only", tools whose declarations codemode hides were still
listed in the <tools> section. Drop their snippets so the list matches the
declared tools.
closes#10192
The first prompt waits only for servers with direct tools. Other servers
connect in the background; codemode scripts, tool_search, and the
resource tools wait for the servers they need. codemode and tool_search
are activated from the config.
Tool declarations no longer depend on connected servers: the codemode
description leaves out deferred tools, and the tool_search description
no longer lists sources. Servers are listed in an mcp_servers system
prompt section instead, set in before_agent_start from the config and
connected state, so changes are appended to the conversation.
describeNamespace() and searchTools() accept mcp__dev-radius,
mcp__dev_radius, dev-radius, and dev_radius.
closes#10212