Skip to content

Latest commit

 

History

History
122 lines (93 loc) · 5.7 KB

File metadata and controls

122 lines (93 loc) · 5.7 KB

Development Guide

Prerequisites

Requirement Version Notes
Node.js ≥ 22.19.0 hard requirement inherited from Pi; CI/dev machines tested with 22.22.x
npm ≥ 9
git ≥ 2.40
BitBake / Yocto optional absent on dev machines is fine — tools must degrade to structured "not available" reports
STM32 hardware optional never required for development or evaluation (fixtures only)

Environment note: development currently happens in WSL against a Windows drive (/mnt/d/...). File I/O is slower there; keep heavy build fixtures out of the repo.

Dependency policy

  • Pi core packages (@earendil-works/pi-ai, @earendil-works/pi-agent-core, @earendil-works/pi-coding-agent) and typebox are declared as peerDependencies (per Pi's package rules — Pi injects its own copies into extensions at load time) and pinned in devDependencies for typechecking.
  • Current pin: 0.84.4 everywhere, matching the local Pi source tree used as the API reference (pi-0.84.4/). When upgrading, re-read docs/pi-architecture.md and update the version notes below.
  • Never bundle Pi core packages into our dist.

Workflow (per project charter)

Inspect → Understand → Plan → Implement → Test → Review → Document
  • TypeScript strict mode; erasable syntax only (no enums/namespaces/parameter properties) — Pi loads extensions with jiti and Node runs TS as strip-only.
  • Tool parameters always get TypeBox schemas; string enums use StringEnum from @earendil-works/pi-ai (not Type.Union(Type.Literal(...)) — breaks Google's API).
  • Every external command gets a timeout; every subprocess exit code is handled; errors are thrown (never encoded in content) per the Pi tool convention.
  • Dangerous operations only through the Safety Layer; never rely on prompt wording alone.
  • Honest status reporting: unimplemented features are labeled "Not implemented"; fixture-only testing is labeled as such.

Switching models and providers

In an interactive session:

Command Effect
/model Model picker; press Ctrl+S inside the picker to save it as the startup default
/thinking Thinking level picker (Ctrl+S to save)
Ctrl+P Cycle between scoped models (/scoped-models edits the list)
/login, /logout Provider auth: subscriptions (Claude Pro/Max, ChatGPT, Copilot, xAI, OpenRouter, …) or API keys

At startup (pilot forwards runtime flags):

pilot --model glm-5.3                          # pick another model from the same provider
pilot --provider openai --model gpt-5          # pick a different provider
pilot --api-key sk-...                         # one-off key (otherwise: env vars / /login)
pilot --list-models                            # see everything currently available
pilot --models opencode-go/glm-5.3,anthropic/claude-sonnet-4-5   # Ctrl+P cycling list

Adding a new provider:

  1. Built-in providers (anthropic, openai, google, openrouter, xai, …): export the env var (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, …) or run /login once. Their model catalogs ship with pi.
  2. Any OpenAI-compatible gateway: add an entry to ~/.pi/agent/models.json (see below). The file reloads every time /model opens — no restart needed.
  3. Startup defaults live in ~/.pi/agent/settings.json (defaultProvider / defaultModel) or are saved from the /model picker with Ctrl+S.

Using a custom LLM provider

Pi reads ~/.pi/agent/models.json (outside this repo, never commit keys). Example for an OpenAI-compatible gateway:

{
	"providers": {
		"<provider-id>": {
			"name": "My Gateway",
			"baseUrl": "https://gateway.example.com/v1",
			"api": "openai-completions",
			"apiKey": "<literal key or $ENV_VAR>",
			"models": [
				{
					"id": "my-model",
					"name": "My Model",
					"reasoning": false,
					"input": ["text"],
					"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
					"contextWindow": 128000,
					"maxTokens": 8192
				}
			]
		}
	}
}

Then run the e2e checks with node scripts/verify-agent-run.mjs <provider-id> <model-id>.

Commands

npm run typecheck          # tsc --noEmit (strict)
npm run verify:extension   # loads src/extension/index.ts via jiti exactly like Pi does
npm run cli -- --version   # run the CLI stub
npm link                   # exposes the `embedded-pilot` bin locally
pi -e ./src/extension/index.ts   # run the extension inside an interactive pi session

Node TypeScript support note

Some distro Node builds (including the current WSL one) are compiled without native TS stripping (ERR_NO_TYPESCRIPT). We therefore do not rely on Node's type stripping anywhere: the bin/embedded-pilot.mjs launcher and scripts/verify-extension-load.mjs are plain JS and load the TypeScript sources through jiti — the exact loader Pi uses for extensions. This works on any Node ≥ 22.19 build.

API version notes

Date Pi version Notes
2026-09-04 0.84.4 Baseline. Extension factory (pi: ExtensionAPI) => void; tools via pi.registerTool(defineTool(...)) with TypeBox schemas; blocking via pi.on("tool_call") → { block, reason }; SDK via createAgentSession(). Package manifest: "pi": { "extensions": [...] }. Details with file/line references in pi-architecture.md.

Legacy scope @mariozechner/pi-* seen in older articles is not current — the 0.84.x line uses @earendil-works/pi-*.

Commit conventions

Conventional commits reflecting the real development sequence, e.g.:

feat: initialize embeddedpilot package
feat: add project detection
feat: add safety policy
test: add evaluation fixtures
docs: add architecture documentation