Stage 9

The Ecosystem Matures

2026-01-26 — 2026-03-04 v0.50.0 → v0.56.0 546 commits 62 contributors
agent-runtime tui devex extension-api llm-providers

Zeitgeist

The period from January 26 to March 3, 2026, saw pi's community shift from "people who submit bug reports" to "people who build features." With 546 commits across v0.50.0 to v0.56.0 -- the highest commit count of any stage -- and contributions from over 30 distinct authors, this was the moment pi became a genuinely community-driven project. Contributors like @aliou, @Perlence, @haoqixu, @ferologics, @dannote, @mcollina, and @markusylisiurunen were not just fixing typos; they were landing multi-file features that touched the AI provider layer, the TUI rendering engine, and the extension API simultaneously.

The stage coincided with two major model releases: Claude Opus 4.6 and GPT-5.3 Codex. Pi updated its default models to these within days of release (v0.52.0-v0.52.2), added adaptive thinking support for Opus 4.6, and introduced xhigh thinking levels for GPT-5.3. The speed of model catalog updates demonstrated that the generated model system (introduced in Stage 3) was paying dividends: adding a new model was a script run plus a PR, not an architecture change.

An "OSS vacation" was introduced in mid-February, temporarily clearing the approved contributors list and auto-closing PRs from non-maintainers. This was not hostility toward the community but a pressure valve: the volume of incoming contributions had exceeded what could be reviewed safely. The vacation mechanism itself -- a scripts/oss-weekend.mjs script that toggles GitHub Actions workflows -- was codified in AGENTS.md with explicit instructions, turning maintainer burnout management into a documented process.

Key Developments

Model Catalog and Thinking Evolution

Claude Opus 4.6 landed in v0.52.0 with adaptive thinking support that lets the model decide its own thinking budget. GPT-5.3 Codex followed with xhigh thinking level support. The ModelRegistry.getApiKeyForProvider() method was added for cleaner provider-level key lookup (#1062). Per-model overrides in models.json (#1332) let users customize context windows, costs, and capabilities without forking the generated catalog. The Antigravity provider replaced Claude Opus 4.5 with 4.6 (#1345). Bedrock got EU cross-region inference profiles (#685) and improved cache pricing metadata. The constant churn of model definitions -- 15+ catalog updates in this stage alone -- validated the generated-models approach: manual maintenance would have been impossible.

Dynamic Tool Registration

A critical extension API gap was closed in v0.55.4: tools registered via pi.registerTool() after startup now applied immediately (#1720). Previously, late-registered tools sat in a pending queue and required /reload to activate. The fix also added promptSnippet and promptGuidelines fields to ToolDefinition, letting extension tools inject themselves into the system prompt's "Available tools" and "Guidelines" sections. This meant extension tools could be as well-described to the LLM as built-in tools, not just listed by name. Custom tool renderers gained the ability to suppress transcript output (#1719), preventing empty blocks from appearing when a tool intentionally produces no visible output.

Cost Tracking and Usage Transparency

Context usage tracking was reworked so that ContextUsage.tokens and ContextUsage.percent return null after compaction, acknowledging the honest truth that token counts are unknown until the next LLM response (#1382 by @ferologics). The cacheRetention stream option was added to control prompt cache TTLs. Input token preservation in the Anthropic provider fixed undercounting caused by dropping message_start usage data. Service tier pricing (#675) was applied correctly. The cumulative effect was that cost information in the footer became trustworthy rather than approximate.

Provider Hardening and Browser Safety

The AI package underwent a major push to become browser-safe. Node-only OAuth runtime exports were moved from the top-level @mariozechner/pi-ai entry to a dedicated @mariozechner/pi-ai/oauth subpath (#1814), preventing bundlers from pulling in Node http modules when importing the core package. Google OAuth guards were added for browser bundlers (#1330). The Bedrock provider module was preloaded in compiled Bun binaries (#1814). Copilot Claude was routed through the Anthropic Messages API for better compatibility (#1384). The OpenCode Go provider was added (#1757). Groq Qwen3 reasoning effort mapping was fixed (#1745). Each fix addressed a specific user report from a specific runtime environment.

Session and Compaction Robustness

Overflow auto-compaction cascades -- where a single context overflow triggered repeated compaction loops -- were finally stopped. Compaction summaries for non-reasoning models were fixed to avoid requesting reasoning output (#1793). The session event handling was serialized to preserve message ordering (#1717), preventing tool results from being written before their corresponding assistant messages when extension handlers were async. Branch summarization queue handling was fixed so messages typed during summarization were processed correctly (#1803). These fixes were not glamorous, but they eliminated the class of bugs where pi would get stuck in a loop or lose messages during long sessions.

Offline Mode and Platform Resilience

The --offline flag and PI_OFFLINE environment variable (#1631, by @mcollina) added startup network timeouts and disabled network-dependent operations, addressing users in airgapped or restricted environments. The koffi module was made fully optional (#1603) for environments where native modules cannot be loaded. Windows VT input initialization was fixed for ESM (#1627). GNU screen terminal detection was added (#1809). These changes reflect a user base that included corporate environments with proxy servers, mobile devices running Termux, and SSH sessions through multiple hops.

Philosophy Shifts

AGENTS.md evolved significantly. The test command was changed from npm test -- test/specific.test.ts to npx tsx ../../node_modules/vitest/dist/cli.js --run test/specific.test.ts, reflecting a move to running tests from the package root rather than the repo root. The instruction "If you create or modify a test file, you MUST run that test file and iterate until it passes" was added -- an acknowledgment that AI-assisted development sometimes produces tests that do not actually pass. The OSS Weekend section codified maintainer boundaries: "If the user says 'enable OSS weekend mode until X', run node scripts/oss-weekend.mjs --mode=close --end-date=YYYY-MM-DD --git."

Resource precedence was explicitly changed so project resources (.pi/) take priority over global resources (~/.pi/agent/). This broke existing setups where global resources intentionally overrode project ones, but aligned with the principle that project-specific configuration should always win -- the same principle behind .gitignore and .editorconfig. Extension registration conflicts no longer unloaded the entire later extension; instead, conflicting names were resolved by first-registration order, keeping all extensions loaded.

Looking Forward

Dynamic tool registration and promptSnippet/promptGuidelines laid the groundwork for extensions that could fully participate in the system prompt construction. The browser-safe AI package refactoring enabled the web UI maturation that continued in Stage 10. The OSS vacation mechanism would be used repeatedly, eventually evolving into the "OSS weekend" pattern with automated gating workflows. And the per-model overrides in models.json would prove essential as the number of supported models grew past what any single generated catalog could cover perfectly.

Key changes

Added OpenCode Go provider support with `opencode-go` model defaults and `OPENCO

llm-providers cli

Added OpenCode Go provider support with `opencode-go` model defaults and `OPENCODE_API_KEY` environment variable support ([docs/providers.md](docs/providers.md), [#1757](https://github.com/badlogic/pi-mono/issues/1757)).

packages/ai/scripts/generate-models.ts L1362–1376
export const MODELS = {
`;

	// Generate provider sections (sorted for deterministic output)
	const sortedProviderIds = Object.keys(providers).sort();
	for (const providerId of sortedProviderIds) {
		const models = providers[providerId];
		output += `\t${JSON.stringify(providerId)}: {\n`;

		const sortedModelIds = Object.keys(models).sort();
		for (const modelId of sortedModelIds) {
			const model = models[modelId];
			output += `\t\t"${model.id}": {\n`;
			output += `\t\t\tid: "${model.id}",\n`;
			output += `\t\t\tname: "${model.name}",\n`;
definition in generate-models.ts
packages/ai/src/env-api-keys.ts L56–57
export function getEnvApiKey(provider: KnownProvider): string | undefined;
export function getEnvApiKey(provider: string): string | undefined;
definition in env-api-keys.ts

Added `branchSummary.skipPrompt` setting to skip branch summarization prompts du

Added `branchSummary.skipPrompt` setting to skip branch summarization prompts during tree navigation ([docs/settings.md](docs/settings.md), [#1792](https://github.com/badlogic/pi-mono/issues/1792)).

packages/coding-agent/src/core/settings-manager.ts L7–11
export interface CompactionSettings {
	enabled?: boolean; // default: true
	reserveTokens?: number; // default: 16384
	keepRecentTokens?: number; // default: 20000
}
definition in settings-manager.ts
packages/coding-agent/src/modes/interactive/interactive-mode.ts L134–147
export interface InteractiveModeOptions {
	/** Providers that were migrated to auth.json (shows warning) */
	migratedProviders?: string[];
	/** Warning message if session model couldn't be restored */
	modelFallbackMessage?: string;
	/** Initial message to send on startup (can include @file content) */
	initialMessage?: string;
	/** Images to attach to the initial message */
	initialImages?: ImageContent[];
	/** Additional messages to send after the initial message */
	initialMessages?: string[];
	/** Force verbose startup (overrides quietStartup setting) */
	verbose?: boolean;
}
definition in interactive-mode.ts

Added `gemini-3.1-flash-lite-preview` fallback model availability for Google pro

Added `gemini-3.1-flash-lite-preview` fallback model availability for Google provider catalogs when upstream model metadata lags ([README.md](README.md), [#1785](https://github.com/badlogic/pi-mono/issues/1785)).

Changed scoped model thinking semantics

Scoped entries without an explicit `:<thinking>` suffix now inherit the current session thinking level when selected, instead of applying a startup-captured default.

From the changelog

Changed scoped model thinking semantics. Scoped entries without an explicit `:<thinking>` suffix now inherit the current session thinking level when selected, instead of applying a startup-captured default.

Moved Node OAuth runtime exports off the top-level `@mariozechner/pi-ai` entry

OAuth login and refresh must be imported from `@mariozechner/pi-ai/oauth` ([#1814](https://github.com/badlogic/pi-mono/issues/1814)).

From the changelog

Moved Node OAuth runtime exports off the top-level `@mariozechner/pi-ai` entry. OAuth login and refresh must be imported from `@mariozechner/pi-ai/oauth` ([#1814](https://github.com/badlogic/pi-mono/issues/1814)).

packages/ai/src/env-api-keys.ts L63–64
export function getEnvApiKey(provider: KnownProvider): string | undefined;
export function getEnvApiKey(provider: string): string | undefined;
definition in env-api-keys.ts
packages/ai/src/providers/openai-codex-responses.ts L56–60
export interface OpenAICodexResponsesOptions extends StreamOptions {
	reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
	reasoningSummary?: "auto" | "concise" | "detailed" | "off" | "on" | null;
	textVerbosity?: "low" | "medium" | "high";
}
definition in openai-codex-responses.ts

Added `branchSummary.skipPrompt` setting to skip the summary prompt when navigat

Added `branchSummary.skipPrompt` setting to skip the summary prompt when navigating branches ([#1792](https://github.com/badlogic/pi-mono/issues/1792)).

packages/coding-agent/src/core/settings-manager.ts L7–11
export interface CompactionSettings {
	enabled?: boolean; // default: true
	reserveTokens?: number; // default: 16384
	keepRecentTokens?: number; // default: 20000
}
definition in settings-manager.ts
packages/coding-agent/src/modes/interactive/interactive-mode.ts L134–147
export interface InteractiveModeOptions {
	/** Providers that were migrated to auth.json (shows warning) */
	migratedProviders?: string[];
	/** Warning message if session model couldn't be restored */
	modelFallbackMessage?: string;
	/** Initial message to send on startup (can include @file content) */
	initialMessage?: string;
	/** Images to attach to the initial message */
	initialImages?: ImageContent[];
	/** Additional messages to send after the initial message */
	initialMessages?: string[];
	/** Force verbose startup (overrides quietStartup setting) */
	verbose?: boolean;
}
definition in interactive-mode.ts

Added OpenCode Go provider support with `opencode-go` model defaults and `OPENCO

llm-providers cli

Added OpenCode Go provider support with `opencode-go` model defaults and `OPENCODE_API_KEY` environment variable support ([#1757](https://github.com/badlogic/pi-mono/issues/1757)).

packages/ai/scripts/generate-models.ts L1362–1376
export const MODELS = {
`;

	// Generate provider sections (sorted for deterministic output)
	const sortedProviderIds = Object.keys(providers).sort();
	for (const providerId of sortedProviderIds) {
		const models = providers[providerId];
		output += `\t${JSON.stringify(providerId)}: {\n`;

		const sortedModelIds = Object.keys(models).sort();
		for (const modelId of sortedModelIds) {
			const model = models[modelId];
			output += `\t\t"${model.id}": {\n`;
			output += `\t\t\tid: "${model.id}",\n`;
			output += `\t\t\tname: "${model.name}",\n`;
definition in generate-models.ts
packages/ai/src/env-api-keys.ts L56–57
export function getEnvApiKey(provider: KnownProvider): string | undefined;
export function getEnvApiKey(provider: string): string | undefined;
definition in env-api-keys.ts

Added `gemini-3.1-flash-lite-preview` fallback model availability in provider ca

Added `gemini-3.1-flash-lite-preview` fallback model availability in provider catalogs when upstream catalogs lag ([#1785](https://github.com/badlogic/pi-mono/issues/1785)).

Issues closed (10)