From 3ff3f20b70476689a1f3005cd43bce7950eb5b78 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Fri, 5 Jun 2026 13:29:44 -0500 Subject: [PATCH] fix(pi): make skill loading token-lean by default --- README.md | 2 ++ packages/mosaic/src/commands/launch.spec.ts | 28 ++++++++++++++++++++- packages/mosaic/src/commands/launch.ts | 28 ++++++++++++++++++++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2784568..dca4667 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ mosaic yolo pi # Pi in yolo mode The launcher verifies your config, checks for `SOUL.md`, injects your `AGENTS.md` standards into the runtime, and forwards all arguments. +Pi launches default to a token-lean skill posture: `mosaic pi` passes `--no-skills` so Pi does not preload every global skill description into the system prompt. Use `MOSAIC_PI_SKILL_MODE=all mosaic pi` for the legacy all-skills catalog, or `MOSAIC_PI_SKILL_MODE=discover mosaic pi` to let Pi use its native settings/project skill discovery. + ### TUI & Gateway ```bash diff --git a/packages/mosaic/src/commands/launch.spec.ts b/packages/mosaic/src/commands/launch.spec.ts index e1846d2..5c7d1e9 100644 --- a/packages/mosaic/src/commands/launch.spec.ts +++ b/packages/mosaic/src/commands/launch.spec.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach, afterEach, type MockInstance } from 'vitest'; import { Command } from 'commander'; -import { registerRuntimeLaunchers, type RuntimeLaunchHandler } from './launch.js'; +import { buildPiSkillArgs, registerRuntimeLaunchers, type RuntimeLaunchHandler } from './launch.js'; /** * Tests for the commander wiring between `mosaic ` / `mosaic yolo ` @@ -22,6 +22,8 @@ function buildProgram(handler: RuntimeLaunchHandler): Command { return program; } +const fakeSkills = ['--skill', '/skills/test-driven-development', '--skill', '/skills/pdf']; + // `process.exit` returns `never`, so vi.spyOn demands a replacement with the // same signature. We throw from the mock to short-circuit into test-land. const exitThrows = (): never => { @@ -63,6 +65,30 @@ describe('registerRuntimeLaunchers — non-yolo subcommands', () => { }); }); +describe('buildPiSkillArgs', () => { + it('defaults to disabling Pi skill discovery to keep startup context small', () => { + expect(buildPiSkillArgs([], {}, fakeSkills)).toEqual(['--no-skills']); + }); + + it('keeps explicit user skills while disabling automatic discovery', () => { + expect(buildPiSkillArgs(['--skill', '/tmp/custom'], {}, fakeSkills)).toEqual(['--no-skills']); + }); + + it('supports legacy all-skills mode without double-loading settings skills', () => { + expect(buildPiSkillArgs([], { MOSAIC_PI_SKILL_MODE: 'all' }, fakeSkills)).toEqual([ + '--no-skills', + '--skill', + '/skills/test-driven-development', + '--skill', + '/skills/pdf', + ]); + }); + + it('supports native Pi discovery when explicitly requested', () => { + expect(buildPiSkillArgs([], { MOSAIC_PI_SKILL_MODE: 'discover' }, fakeSkills)).toEqual([]); + }); +}); + describe('registerRuntimeLaunchers — yolo ', () => { let mockExit: MockInstance; let mockError: MockInstance; diff --git a/packages/mosaic/src/commands/launch.ts b/packages/mosaic/src/commands/launch.ts index 76c1702..de8179f 100644 --- a/packages/mosaic/src/commands/launch.ts +++ b/packages/mosaic/src/commands/launch.ts @@ -447,6 +447,32 @@ function discoverPiSkills(): string[] { return args; } +type PiSkillMode = 'none' | 'all' | 'discover'; + +function normalizePiSkillMode(env: NodeJS.ProcessEnv): PiSkillMode { + const value = env['MOSAIC_PI_SKILL_MODE']?.trim().toLowerCase(); + if (value === 'all' || value === 'discover') return value; + return 'none'; +} + +export function buildPiSkillArgs( + _runtimeArgs: string[], + env: NodeJS.ProcessEnv = process.env, + discoveredSkillArgs: string[] = discoverPiSkills(), +): string[] { + const mode = normalizePiSkillMode(env); + + if (mode === 'discover') { + return []; + } + + if (mode === 'all') { + return ['--no-skills', ...discoveredSkillArgs]; + } + + return ['--no-skills']; +} + function discoverPiExtension(): string[] { const ext = join(MOSAIC_HOME, 'runtime', 'pi', 'mosaic-extension.ts'); return existsSync(ext) ? ['--extension', ext] : []; @@ -523,7 +549,7 @@ function launchRuntime(runtime: RuntimeName, args: string[], yolo: boolean): nev case 'pi': { const prompt = buildRuntimePrompt('pi'); const cliArgs = ['--append-system-prompt', prompt]; - cliArgs.push(...discoverPiSkills()); + cliArgs.push(...buildPiSkillArgs(args)); cliArgs.push(...discoverPiExtension()); if (hasMissionNoArgs) { cliArgs.push(missionPrompt);