CodeVetter
← All unpacks
CodeVetter · Repo Unpack evidence

earendil-works/pi

Scanned commit 95fbc04997 dated 2026-09-22 — last upstream commit. Generated by codevetter 1.12.0 on 2026-09-22.

github.com/earendil-works/pi ↗ · 1822 files · 17.2 MB

New issues and PRs from new contributors are auto-closed by default.

Deep analysis by swe-2 via the devin CLI on 2026-09-22 (runtime not recorded) — every claim below links to its cited source files.

Overview

Pi is a TypeScript monorepo for the 'Pi agent harness', published as the `pi` CLI (@earendil-works/pi-coding-agent): a self-extensible terminal coding agent with read/bash/edit/write/grep/find/ls tools, JSONL session persistence under ~/.pi/agent, and a TypeScript extension system loaded via jiti. It is built on in-house libraries: pi-agent-core (event-sourced agent loop), pi-ai (unified LLM API with 41 built-in providers plus OAuth flows), pi-tui (differential-rendering terminal UI with native modules), plus an experimental distributed stack (chord composition runtime, durable runtime, CBOR protocol/client/server, sqlite session backend). Notably it deliberately ships no sandbox — security relies on project-trust gating of project-local resources and external containerization.

System map

npm-workspaces monorepo (packages/*, plus packages/session-backends/* and extension examples) built in dependency order by the root build script: chord → tui → telemetry → ai → durable → agent → session-backends/sqlite-node → protocol → client → server → coding-agent. The shippable product is packages/coding-agent whose bin `pi` runs dist/bundle/cli.js (bundled from src/cli.ts → src/main.ts) on Node >=22.19, with an alternative Bun-compiled binary path. The agent runtime lives in pi-agent-core, provider access in pi-ai, terminal rendering in pi-tui (with C native modules per platform), and an experimental RPC/session-server stack in protocol/client/server/durable. State lives in ~/.pi/agent (auth.json, settings.json, models.json, sessions/, themes/, prompts/, bin/).

All 15 system map claims →

Feature catalog

User-facing surface = the `pi` CLI plus in-session slash commands, extension hooks, and the RPC/JSON embedding protocols. CLI flags cover model/provider/thinking selection, session lifecycle (continue/resume/fork/session-id), tool scoping, resource paths (extensions, skills, prompt templates, themes), export, and offline mode. Interactive mode adds a full-screen TUI with 20+ built-in slash commands; headless modes expose the same session operations as JSON commands over stdin/stdout. Extensions add LLM tools, commands, providers, UI widgets, and event handlers.

All 15 feature catalog claims →

Data flow

A prompt enters via CLI args, piped stdin, or the TUI editor; AgentSession wraps it as a user AgentMessage and hands it to Agent.prompt → runAgentLoop. Per turn the loop transforms AgentMessage[] → LLM Message[] (convertToLlm), streams via the model's provider streamFn, executes toolCall content blocks through tools/extensions, and appends ToolResultMessages. AgentSession subscribes to agent events and persists each message_end to the JSONL session file via SessionManager, while the active mode renders events (TUI components, text, or JSON lines). Credentials come from auth.json (locked, 0600) resolved per-request by ModelRuntime; model catalogs come from generated data + models.json + a remote catalog refresh.

All 13 data flow claims →

Behavior traces

Three flows dominate. Startup: cli.ts → setupCli → main → auth/package/config short-circuits → parseArgs → runMigrations → SettingsManager → SessionManager (create/open/fork/resume) → createAgentSessionRuntime (settings+resourceLoader+modelRuntime+AgentSession) → theme init → mode dispatch. Prompt turn: session.prompt → Agent.prompt → runAgentLoop → streamAssistantResponse → executeToolCalls → agent_end → persisted + rendered. Persistence: every agent event message_end is appended to the session JSONL by AgentSession's subscriber.

All 13 behavior traces claims →

Testing signals

Vitest is the primary framework (packages/coding-agent/test ~297 files, agent+ai ~240 combined), plus node:test for packages/tui and scripts/*.test.mjs. A faux provider (pi-ai providers/faux.ts) enables deterministic agent-loop testing without API keys, and test/suite/harness.ts builds full AgentSession fixtures. ./test.sh runs the whole suite in a scrubbed environment (temp HOME, no API keys) because e2e tests activate when real endpoint/auth env vars exist. CI runs build → check → npm test on ubuntu; supply-chain checks (pinned deps, shrinkwrap, lockfile gate) run in npm run check and the husky pre-commit hook.

All 13 testing signals claims →

Risk map

The dominant risk is intentional: pi is an unsandboxed local agent whose bash/edit/write tools and jiti-loaded extensions run with full user privileges — the docs state this plainly and point to containerization instead. Concrete hotspots: auth.json holds plaintext credentials (mitigated by 0600 + locking); the extension/package system executes third-party code gated only by project trust for project-local sources; RPC/protocol layers have no peer authentication; and giant files (agent-session.ts 4023 lines, interactive-mode.ts 6851 lines, package-manager.ts 2699 lines) concentrate blast radius.

All 13 risk map claims →

Extension points

Pi's core is deliberately minimal — CONTRIBUTING.md says features that don't belong in core should be extensions. The main seam is the ExtensionAPI: TypeScript modules loaded by jiti from user/project dirs, CLI -e, settings, or npm/git packages, which can register tools, slash commands, providers, CLI flags, keybindings, UI widgets/renderers, and ~35 lifecycle event handlers. Lower-level seams: pluggable tool Operations (e.g. BashOperations for remote execution), Provider registration in pi-ai, Chord facets/services for the experimental stack, skills/prompt-templates/themes as data resources, and custom session entries for extension persistence.

All 13 extension points claims →

Contributor handoff

AGENTS.md is unusually prescriptive and must be read first: erasable-TypeScript-only syntax (no enums/namespaces/parameter properties — Node strip-only mode), no inline imports, top-level imports only, no `any` unless necessary, no hardcoded key checks (use DEFAULT_*_KEYBINDINGS). After code changes run `npm run check` fully; never run npm run build or npm test unless asked; use ./test.sh or targeted vitest/node --test. Never edit generated files (models.generated.ts); regenerate via scripts. Stage explicit paths only — concurrent pi sessions share the worktree.

All 13 contributor handoff claims →

Languages

LanguageFilesShare of source
TypeScript150696%
Markdown158docs/config
JSON48docs/config
JavaScript423%
YAML14docs/config
Shell111%
C81%
CSS1docs/config

Start reading here

Probable source entrypoint: packages/ — inferred from the directory tree and manifest, not the upstream docs.

Source roots

packages/ (1732 files)

Source layout — packages/

PathFiles
packages/coding-agent/238
packages/evals/30
packages/session-backends/33

Repository structure

Top-level pathFiles
packages/1732
scripts/40
.github/15
.pi/15
.husky/1

Docs found: AGENTS.mdCONTRIBUTING.mdREADME.md

Package

package.json — pi-monorepo v0.0.3, 9 declared dependencies.

@anthropic-ai/sandbox-runtime@biomejs/biome@types/node@typescript/native-previewesbuildhuskyshxtsxtypescript

CI & config entrypoints

Structural health signals

Average score 6.9/10 across 96 analyzed source files; 29 hotspots surfaced.

These are deterministic review leads — size, churn, and structural signals — not proof of a bug in this project.

Recent history