-
Notifications
You must be signed in to change notification settings - Fork 0
features onboarding
Onboarding is the garnish init flow that takes a learner from an empty shell to a running, gated Pi session with Tutorial Island active. It installs the certified runtime into Garnish-owned storage, asks at most five questions, copies the core packs and assembles the quest graph, renders the locked L0 gate config, writes the tutor framing and pre-serialized state, bundles the extension, and launches the session under an isolation env. The whole path is dependency-injected so the same command core runs under hermetic tests with stubbed effects and recorded fixtures.
initCommand in src/cli/init.ts first calls ensureRuntime from src/adapter/runtime.ts. This installs the certified omp binary (v16.2.13) into Garnish-owned storage under the Garnish root (~/.garnish by default), computes the runtime paths, and runs the version handshake. If the handshake reports anything other than ok, init returns early with the doctor message. The learner's global omp is ignored; the certified binary is launched by absolute path.
Init asks at most five prompts through an injected Prompter:
-
Provider:
anthropic,openai, orother:<ENV_VAR>. Garnish stores only the env-var reference, never a raw key. The default mapsanthropictoANTHROPIC_API_KEYandopenaitoOPENAI_API_KEY. -
Speedrun mode:
n,all, or a level order. Choosing anything butnappendsunlockevents with reasonspeedrunfor the selected levels and their features, without awarding XP. -
Sandbox directory: defaults to
<garnish root>/sandbox. A disposable learning dir, never an existing project by default.
A QueuedPrompter supplies the same answers non-interactively for tests, and init throws if it ever exceeds five prompts.
Init copies each source pack directory into $PI_CODING_AGENT_DIR/garnish/packs/, loads each through loadPack (which parses frontmatter and validates against the Zod schemas), and assembles a ProgressionGraph from the combined levels, quests, and unlock edges. Speedrun unlock events (if any) are appended to events.jsonl at this point.
Init folds the event log (the speedrun unlocks, or an empty log) into a ProgressionState and calls renderGateConfig with the resulting unlock set. An empty log produces the locked L0 baseline: only the first level is active and only its baseline tools are enabled. writeGateConfig writes config.yml and mcp.json into the agent dir, preserving any non-owned keys.
Init parses the rendered config.yml, merges in a providers block mapping the chosen provider name to { apiKeyRef: <ENV_VAR> }, and rewrites the file with the generated header. The raw key never enters the file, only the env-var name.
writeTutorFraming from src/extension/tutor.ts appends the static tutor framing to APPEND_SYSTEM.md in the agent dir. This is an append, never a replace of the defaults, so the agent can answer "what's my quest?" from live quest state. See tutor bridge.
Init writes three JSON files into $PI_CODING_AGENT_DIR/garnish/:
-
graph.json: the assembledProgressionGraph. -
quests.json: the full quest list. -
state.json: a derived snapshot (activeLevel, pack IDs, certified runtime version, sandbox dir) consumed by the L0install-certified-picheck and the extension entry.
The bundled extension entry reads these synchronously at session start (readFileSync), because the LOO-118 spike showed extension module init must stay synchronous.
The injected installExtension callback bundles the extension with bun build --target node into $PI_CODING_AGENT_DIR/extensions/garnish/index.js, where the certified runtime autoloads it. See Pi extension.
createLaunchSpec builds the command that launches the certified binary with an isolation env: HOME (Garnish-owned home), PI_CODING_AGENT_DIR (the agent dir), and OMP_AUTH_BROKER_SNAPSHOT_CACHE (the auth snapshot). The garnish shim wraps the launch so the session runs fully isolated from the learner's global Pi state. Init then calls the injected launch callback with the spec and the sandbox dir as cwd.
The command core is fully dependency-injected (RuntimeEffects, GateConfigEffects, InitFsEffects, Prompter, installExtension, launch), so tests run init without touching the machine. GARNISH_OMP_SOURCE stubs the runtime install source, and recorded event fixtures stand in for live Pi events. The QueuedPrompter records asked questions so tests can assert the prompt budget. See CLI init wizard.
sequenceDiagram
participant U as User
participant C as garnish CLI
participant A as Adapter
participant L as Loader
participant P as Progression
participant G as Gate renderer
participant T as Tutor
participant F as FS effects
participant E as Extension bundler
participant Pi as Certified runtime
U->>C: garnish init
C->>A: ensureRuntime
A->>A: install + verify omp 16.2.13
A-->>C: RuntimeInfo (handshake ok)
C->>U: provider / speedrun / sandbox prompts
U-->>C: answers
C->>F: copy packs into agent dir
C->>L: loadPack each
L-->>C: QuestGraph[]
C->>P: foldEvents + assemble graph
C->>F: append speedrun unlocks (if any)
C->>G: renderGateConfig(unlockSet)
G-->>C: config.yml + mcp.json
C->>F: writeGateConfig + merge providers
C->>T: writeTutorFraming
C->>F: write graph.json, quests.json, state.json
C->>E: installExtension (bun build --target node)
C->>A: createLaunchSpec
A-->>C: LaunchSpec (HOME, PI_CODING_AGENT_DIR, OMP_AUTH_BROKER_SNAPSHOT_CACHE)
C->>Pi: launch (cwd = sandbox)
| Component | File | Role |
|---|---|---|
| Init command | src/cli/init.ts |
initCommand orchestrates the whole flow; queuedPrompter for non-interactive tests. |
| Adapter ensureRuntime | src/adapter/runtime.ts |
Certified runtime install, version handshake, createLaunchSpec. |
| Gate renderer | src/adapter/gates.ts |
renderGateConfig and writeGateConfig produce the locked L0 baseline. |
| Extension bundler | src/cli/real.ts |
bun build --target node into extensions/garnish/index.js (injected as installExtension). |
| Launch spec | src/adapter/runtime.ts |
createLaunchSpec builds the isolation env and command. |
| Tutor framing | src/extension/tutor.ts |
writeTutorFraming appends the static framing to APPEND_SYSTEM.md. |
This feature spans the CLI, adapter, and extension:
- CLI init wizard: the init command core and composition root.
-
Pi adapter:
ensureRuntime,renderGateConfig,writeGateConfig,createLaunchSpec. - Pi extension: the bundled extension that autoloads at session start.
- Tutor bridge: the static framing written during init.
- Curriculum: the packs that init copies and assembles.
- Capability gating: the locked L0 baseline init renders.
| File | Purpose |
|---|---|
src/cli/init.ts |
initCommand, queuedPrompter, the wizard and graph assembly. |
src/adapter/runtime.ts |
ensureRuntime, handshake, createLaunchSpec. |
src/adapter/gates.ts |
renderGateConfig, writeGateConfig. |
src/extension/tutor.ts |
writeTutorFraming. |
src/cli/real.ts |
Composition root binding effects to fs, child_process, and bun build. |