Development
Architecture
How the VS Code extension host, PI SDK, Svelte webview, message bridge, trust gate, and configuration files fit together.
Browse the wiki
PiLot Studio is a VS Code extension with two runtimes: the Node-based extension host and a sandboxed Chromium webview. The host owns PI, the filesystem, credentials, and child processes. The webview owns only the interface. They communicate through VS Code's postMessage bridge.
This page is based on CodeWiki's AST analysis of the PiLot 3.0.0 source (569 components, 84 leaf nodes) plus a review of the host modules.
The two runtimes
| Runtime | What runs there | What it can access |
|---|---|---|
| Extension host | loader.cjs, the bundled extension, the PI SDK, session files, provider credentials, MCP child processes, voice helpers, Git. |
VS Code APIs, Node, the filesystem, the network. |
| Webview | Svelte 5 components, the transcript, the composer, dialogs. | The DOM and acquireVsCodeApi(); no Node, no direct filesystem. |
The host is a single Node process per VS Code window. A PiAgentProvider instance owns one active PI session at a time; switching sessions replaces the session object, not the whole extension.
Activation
- VS Code reads the extension's
main, which isdist/loader.cjs. - The loader finds a globally installed
@earendil-works/pi-coding-agentpackage. It checks explicit locations first (pi-agent.binaryPath,PI_HOME,PI_AGENT_DIR), then package-manager locations, and picks the newest readable version. - The loader refuses a PI SDK older than 1.4.0 with an update prompt.
- The loader hooks Node's module resolution so the extension bundle can
requirethe ESM-only SDK, then loads the extension. activate()checks that the extension host runs Node 22.19+. VS Code only reaches that floor at 1.105.- It reads the
pi-agent.*configuration, bridgesagentDirintoPI_CODING_AGENT_DIR, creates the provider, registers thepiAgentChatwebview view, registers commands, starts the update checker, and installs a configuration listener.
The loader does not bundle the PI SDK. That keeps the extension smaller and ensures PiLot Studio uses the same PI installation, packages, and credentials as the CLI.
Host modules
The CodeWiki component index groups the host into these responsibilities:
| Module | Main files | Responsibility |
|---|---|---|
| Extension host and agent lifecycle | extension.ts, pi-agent-provider.ts, message-handler.ts, pi-settings.ts, session-manager.ts, session-resources.ts, project-trust.ts, footer-manager.ts, message-serializer.ts, protocol/types.ts |
Activation, the active PI session, webview messages, config, trust, session list, context and mentions, status line. |
| Model and provider registry | model-registry-handler.ts, provider-migration.ts |
Model catalog, provider auth state, offline/online refresh, provider renames. |
| MCP and codemode | mcp-manager.ts |
Parse and validate mcp.json, delegate add/remove/login/logout to the CLI, list servers and tools, codemode settings. |
| Packages, skills, and resources | package-manager.ts, session-resources.ts |
pi list/install/remove/update, package resource enrichment, skill and prompt discovery, mention resolution. |
| Voice dictation | voice-manager.ts |
Model download/cache, native helper lifecycle, transcription messages, platform errors. |
| Git and source control | git-commit-message.ts, git-extension.ts |
Staged-diff collection, commit-message drafting, writing to the SCM input box. |
| Runtime, updates, diagnostics | pi-binary.ts, binary-service.ts, loader.cjs, loader-version.cjs, runtime-guard.ts, update-checker.ts, utils/native-addons.ts, utils/shell.ts, commands/diagnostics.ts, commands/index.ts |
Binary resolution, version floors, shell execution, update checks, native-addon rebuild, diagnostics, command registration. |
| Webview bridge | webview/mcp-display.ts, webview/messages.ts, webview/types/index.ts, webview/app.d.ts |
Message envelope validation, shared types, MCP display normalization. |
| Build and release | package.json, tsconfig*.json, .github/workflows/* |
esbuild bundle, Vite webview build, type checks, tests, CI. |
pi-agent-provider.ts is the largest module (171 components). It owns the session, webview, model registry, MCP manager, package manager, voice manager, update state, and most command handlers. The other host modules are deliberately narrower and receive dependencies through constructors, which is what makes them testable without a full VS Code window.
Prompt flow
ChatPanel
→ postMessage({ type: "prompt", data })
→ MessageHandler validates the envelope
→ PiAgentProvider.prompt()
→ SessionResources.resolveMentions() + getProjectContext()
→ PI AgentSession.prompt()
→ provider endpoint
→ PI events
→ notifyWebview()
→ App.svelte updates state
→ transcript components render
Mentions are resolved before the SDK call. The host reads each mentioned file, enforces the 10 MB and 50 KB limits, and builds a file-context block. Built-in slash commands are intercepted before the SDK call; skill and template commands are passed through so PI can expand them.
Auto Context adds a short Project Root / Project Name / Project Version preamble. It is not a general file-context system; @ mentions are the explicit file mechanism.
Session lifecycle
PiAgentProvider.createSession()resolves the workspace root, trust decision, agent directory, and session directory.- It constructs a PI
ResourceLoaderwith settings, additional skill/extension/template paths, and discovery flags. - It creates an
AgentSessionthrough the PI SDK and opens or creates the session file. - It binds an
ExtensionUIContextso extensionsetStatus()calls andsession_starthandlers reach the webview. - It sends the serialized transcript, resource counts, model state, and footer data to the webview.
- Streaming events, tool calls, usage updates, and errors are forwarded as typed messages.
Forking creates a new session file, copies the path up to the selected entry, records the parent session, and swaps the provider to the fork. The original file is untouched.
The webview
The webview is a Svelte 5 application built by Vite. It uses runes for state and is served from dist/webview with a per-load CSP nonce.
- CSP:
default-src 'self';script-srclimited to self plus a per-load nonce;connect-srclimited to self and the npm registry;img-srclimited to self anddata:;object-src 'none';base-uri 'self';form-action 'self'. - No Node: the webview cannot read files, spawn processes, or access credentials.
- Message validation:
parseHostMessage()and shared type guards reject malformed or hostile payloads. The host also validates incoming webview messages. - Rendering: markdown is rendered with escaping; code blocks, Mermaid, tables, and tool results have dedicated components. The message renderer avoids inline event handlers so the CSP does not need
unsafe-inline. - State:
App.svelteholds the active tab, transcript, model, providers, streaming state, resources, and update badges. Child panels request data from the host and listen for typed replies.
The same webview bundle is used in the sidebar and in editor tabs (pi-agent.openCurrentSessionInEditor, pi-agent.newChatInEditor).
Trust and security boundaries
PI 1.4 gates project-local resources behind trust. PiLot Studio resolves that decision before creating a session:
- The probe only runs when the workspace contains project-local
.pisettings, MCP servers, packages, or extensions. - A stored decision in PI's
trust.jsonis reused. - A prompt can persist or apply only to the current window.
- Cancellation and probe errors fail closed (untrusted).
- The decision is shared with the CLI, so the two do not disagree.
Other boundaries:
- Binary path:
pi-agent.binaryPathcan come from workspace settings, so values containing shell metacharacters are refused. Bare names are resolved with a PATH scan, not a shell. - Shell arguments: package and Git commands use argv arrays or quoted arguments; repository content goes over stdin where a shell cannot reinterpret it.
- Mentions: paths are resolved inside the workspace; binary extensions are skipped.
- Credentials: keys are written to
auth.jsonatomically with owner-only permissions; an unparseable file is left untouched. - Webview: CSP plus message validation, with no direct host access.
Storage map
| Path | Owner | Contents |
|---|---|---|
<agentDir>/auth.json |
PI | Provider keys and OAuth credentials. |
<agentDir>/models.json |
PI | Custom providers and models. |
<agentDir>/settings.json |
PI | Runtime settings, including codemode. |
<agentDir>/mcp.json |
PI | Global MCP servers and autoEnableCodemode. |
<agentDir>/trust.json |
PI | Project trust decisions. |
<agentDir>/sessions/ |
PI | Session files. |
<agentDir>/voice-models/ |
PiLot | Cached whisper models. |
<workspace>/.pi/settings.json |
Project | Trusted project codemode and runtime overrides. |
<workspace>/.pi/mcp.json |
Project | Trusted project MCP servers. |
agentDir defaults to ~/.pi/agent. sessionDir adds an optional subdirectory under it.
Network use
PiLot Studio itself contacts:
pi.dev/api/latest-versionfor PI release checks (skipped when offline orPI_SKIP_VERSION_CHECKis set);- the npm registry for the Packages marketplace and package updates;
- Hugging Face for the first voice-model download;
- MCP servers you configure.
Model requests go directly to the provider endpoint selected in PI. PiLot Studio has no proxy or telemetry service. Diagnostics are local and off by default.
Design constraints
- PI owns the agent. PiLot Studio does not fork PI's prompt loop or session format; it mirrors PI state and uses PI's own extension factories.
- The CLI is the compatibility target. Packages, MCP, trust, auth, models, and sessions must remain usable from
pi. - The webview is untrusted. Every message is validated; every file operation happens in the host.
- Version floors are explicit. Node 22.19, VS Code 1.105, PI 1.4.0. Failing early with a readable message is preferred to a module-load crash.
Documentation provenance
The module map and component counts on this page come from CodeWiki's AST analysis of the PiLot repository at version 3.0.0 (569 components, 84 leaf nodes). The behavior descriptions were then checked against the source files and the 3.0.0 changelog. If the source and this page disagree, the source is authoritative; please open an issue with the page title.
Something inaccurate or missing? Open an issue with the page title.