From 343f32033dc399000074a08d822d1e625d8ebec9 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Wed, 1 Apr 2026 12:00:01 -0500 Subject: [PATCH] feat: add Pi as first-class Mosaic runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Pi (pi-coding-agent) as a native runtime alongside Claude, Codex, and OpenCode in the Mosaic installation wizard and launcher. Monorepo changes (@mosaic/mosaic): - Add 'pi' to RuntimeName union type - Add Pi to runtime detector (command: pi, --version flag) - Add Pi label to runtime installer - Add configurePiMcp() for ~/.pi/agent/settings.json MCP config - Add 'pi' to wizard runtime scan list Local install (~/.config/mosaic/) changes applied separately: - runtime/pi/RUNTIME.md — Pi runtime contract - runtime/pi/mosaic-extension.ts — Pi extension (lifecycle hooks, mission detection, session lock, /mosaic-status command) - bin/mosaic — launch_pi(), yolo pi, coord --pi, prdy --pi - adapters/pi.md — Pi adapter documentation - AGENTS.md — Pi added to runtime load order - skills/ — symlinked monorepo skills for launcher discovery Pi integration notes: - mosaic pi and mosaic yolo pi are identical (Pi has no permission restrictions) - Runtime contract injected via --append-system-prompt (native flag) - Mosaic skills loaded via --skill flags (native Pi skill discovery) - Extension loaded via --extension for session lifecycle hooks - Pi native thinking levels replace sequential-thinking MCP gate - Model-agnostic: works with any provider configured in Pi settings --- packages/mosaic/src/runtime/detector.ts | 6 +++++ packages/mosaic/src/runtime/installer.ts | 1 + packages/mosaic/src/runtime/mcp-config.ts | 27 +++++++++++++++++++++ packages/mosaic/src/stages/runtime-setup.ts | 2 +- packages/mosaic/src/types.ts | 2 +- 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/mosaic/src/runtime/detector.ts b/packages/mosaic/src/runtime/detector.ts index ba5265d..c80167c 100644 --- a/packages/mosaic/src/runtime/detector.ts +++ b/packages/mosaic/src/runtime/detector.ts @@ -33,6 +33,12 @@ const RUNTIME_DEFS: Record< versionFlag: 'version', installHint: 'See https://opencode.ai for install instructions', }, + pi: { + label: 'Pi', + command: 'pi', + versionFlag: '--version', + installHint: 'npm install -g @mariozechner/pi-coding-agent', + }, }; export function detectRuntime(name: RuntimeName): RuntimeInfo { diff --git a/packages/mosaic/src/runtime/installer.ts b/packages/mosaic/src/runtime/installer.ts index 065497e..078a235 100644 --- a/packages/mosaic/src/runtime/installer.ts +++ b/packages/mosaic/src/runtime/installer.ts @@ -7,6 +7,7 @@ export function formatInstallInstructions(name: RuntimeName): string { claude: 'Claude Code', codex: 'Codex', opencode: 'OpenCode', + pi: 'Pi', }; return `To install ${labels[name]}:\n ${hint}`; } diff --git a/packages/mosaic/src/runtime/mcp-config.ts b/packages/mosaic/src/runtime/mcp-config.ts index 852767d..b014c36 100644 --- a/packages/mosaic/src/runtime/mcp-config.ts +++ b/packages/mosaic/src/runtime/mcp-config.ts @@ -16,6 +16,8 @@ export function configureMcpForRuntime(runtime: RuntimeName): void { return configureCodexMcp(); case 'opencode': return configureOpenCodeMcp(); + case 'pi': + return configurePiMcp(); } } @@ -69,6 +71,31 @@ function configureCodexMcp(): void { writeFileSync(configPath, content, 'utf-8'); } +function configurePiMcp(): void { + const settingsPath = join(homedir(), '.pi', 'agent', 'settings.json'); + ensureDir(settingsPath); + + let data: Record = {}; + if (existsSync(settingsPath)) { + try { + data = JSON.parse(readFileSync(settingsPath, 'utf-8')) as Record; + } catch { + // Start fresh if corrupt + } + } + + if ( + !data['mcpServers'] || + typeof data['mcpServers'] !== 'object' || + Array.isArray(data['mcpServers']) + ) { + data['mcpServers'] = {}; + } + (data['mcpServers'] as Record)['sequential-thinking'] = MCP_ENTRY; + + writeFileSync(settingsPath, JSON.stringify(data, null, 2) + '\n', 'utf-8'); +} + function configureOpenCodeMcp(): void { const configPath = join(homedir(), '.config', 'opencode', 'config.json'); ensureDir(configPath); diff --git a/packages/mosaic/src/stages/runtime-setup.ts b/packages/mosaic/src/stages/runtime-setup.ts index cd689fe..472cf0a 100644 --- a/packages/mosaic/src/stages/runtime-setup.ts +++ b/packages/mosaic/src/stages/runtime-setup.ts @@ -4,7 +4,7 @@ import { detectRuntime, type RuntimeInfo } from '../runtime/detector.js'; import { formatInstallInstructions } from '../runtime/installer.js'; import { configureMcpForRuntime } from '../runtime/mcp-config.js'; -const RUNTIME_NAMES: RuntimeName[] = ['claude', 'codex', 'opencode']; +const RUNTIME_NAMES: RuntimeName[] = ['claude', 'codex', 'opencode', 'pi']; export async function runtimeSetupStage(p: WizardPrompter, state: WizardState): Promise { p.separator(); diff --git a/packages/mosaic/src/types.ts b/packages/mosaic/src/types.ts index 0e494ee..e5c50ab 100644 --- a/packages/mosaic/src/types.ts +++ b/packages/mosaic/src/types.ts @@ -1,7 +1,7 @@ export type WizardMode = 'quick' | 'advanced'; export type InstallAction = 'fresh' | 'keep' | 'reconfigure' | 'reset'; export type CommunicationStyle = 'direct' | 'friendly' | 'formal'; -export type RuntimeName = 'claude' | 'codex' | 'opencode'; +export type RuntimeName = 'claude' | 'codex' | 'opencode' | 'pi'; export interface SoulConfig { agentName?: string; -- 2.49.1