SpecPi Chat guide

September 20, 2026 · View on GitHub

For a quick start, see the overview. This guide covers the controls, limits, and troubleshooting in more detail. Build, test, and publishing instructions are in the development guide.

Set up

  1. Install Node.js 22.19 or newer and Pi 0.84.4 for the reviewed default base on the machine running your VS Code workspace. SpecPi provides /scope, the harness improvement loop, and the seven default packages. Follow the SpecPi setup guide. Confirm Pi works in the intended folder. You can configure a provider through Pi in a terminal beforehand, or use Sign in to a provider in Chat once connected.
  2. Use VS Code 1.96 or newer. Open and trust a filesystem workspace.
  3. Download SpecPi Chat 0.14.0. In VS Code, run Extensions: Install from VSIX… and select the downloaded file.
  4. Open SpecPi in the Activity Bar, or press Ctrl+Alt+S (Cmd+Alt+S on macOS). Choose Connect Pi.

To install a package built from this repository instead, run:

npm --prefix vscode run package
code --install-extension .specpi-test/vscode/specpi-chat-0.14.0.vsix

You can also run Extensions: Install from VSIX… in VS Code and select that file.

If Pi cannot be found, open SpecPi: Chat Settings and set specpi.chat.piPath to its absolute executable or JavaScript CLI path. For JavaScript entry points, specpi.chat.nodePath can select your external Node.js executable. Empty settings discover Pi and Node on PATH. These are application settings; repository settings cannot choose an executable. Supply a path, with no additional command arguments.

On Windows, ordinary npm Pi launchers are resolved to their adjacent JavaScript entry point. Custom PowerShell launchers and arbitrary shell commands are unsupported. If automatic resolution fails, choose the installed Pi package's CLI JavaScript file explicitly.

For SSH, WSL, or containers, install the extension in the remote workspace and configure Pi and Node on that host. Browser-only VS Code and virtual filesystems are unsupported.

Work in the sidebar

Use SpecPi 0.29.0 with SpecPi Chat 0.14.0. Browser QA replaces BetterWright in the default base; unchanged SpecPi-added BetterWright entries retire, while original entries and user edits are preserved. No browser profile data or Bun installation is migrated or removed. Run the confirmed SpecPi install/update separately and restart Pi in each Chat connection. Normal managed updates remove unchanged pi-lens entries originally added by SpecPi; pre-existing or modified entries and downloaded files remain. --skip-package-install preserves the old base. Independently retained Lens installs require separate user management. Installing a VSIX does not install or update the harness packages. Legacy startup dialogs are cancelled without approval; update older harness resources if a connection waits for a startup dialog to expire.

  • Send a message: use Enter to send and Shift+Enter for a new line. Search the model picker by model or provider, and choose a thinking level with its description before sending. With a chat connected, the pin button next to the picker saves the current model as Pi's startup model, or the current thinking level as the global startup level. You can also pin the thinking level to this model alone, which Pi then applies whenever that model is selected, in every chat, not only at startup. Each save confirms first, edits only those keys in Pi's global settings, and backs the file up. Restart Pi or reconnect to pick the change up.
  • Add context: the active editor selection appears above the composer as a chip and attaches with your next message (click the chip to hide it), or select code and use SpecPi: Attach Selection to Chat, press Alt+K to insert an @file#Lx-Ly mention, choose a file through the attachment controls, type @ to find a workspace file or folder, or drop a workspace file reference into the composer. A file suggestion lists files and matching folders; selecting one attaches its validated contents or a bounded folder listing. Review or remove attachments before sending.
  • Follow the work: replies stream into the transcript. Thinking and tool blocks start expanded, including tool results and images. Manual collapse/expand choices are preserved during streaming and completion. Stop interrupts the current response. During a response, choose whether your next message should steer the current work or follow afterward.
  • Add images: choose PNG, JPEG, GIF, or WebP files with the image picker, paste a screenshot, or drop image files into the composer. The image picker can read explicitly selected images outside the workspace. Choose a model with image support, then send a normal message with or without text. Images stay attached when model validation fails. Pi slash commands reject image attachments because those commands do not consume them.
  • Attach folders: selecting a folder in @ suggestions, an @folder/ mention, or Attach File on an Explorer folder attaches a bounded directory-listing snapshot (at most 200 entries / 16 KiB, with an explicit truncation notice) instead of reading every file. Sensitive directories and credentials are never listed. Pi can still read files inside the folder with its own tools. Suggestions and folder listings respect files.exclude, search.exclude, and the workspace-root .gitignore (following search.useIgnoreFiles); explicitly attaching an ignored file or folder remains available.
  • Sign in to a provider: Chat shows a sign-in panel when a connected Pi reports no usable provider (an empty model picker), or when a message fails because the selected provider has no credential. Sign in to a provider starts your configured Pi executable in a VS Code terminal named SpecPi Chat · Pi sign-in, in the chat's workspace folder and without RPC flags, so you can run Pi's own /login and /logout there. Close that terminal when you are done and Chat reloads Pi, which is required: Pi resolves its model catalogue at startup and cannot pick a new credential up while running. Reload Pi does the same on demand, and a busy conversation is left alone with a notice instead. The same flow is available as SpecPi: Sign In to a Provider. Chat never reads, stores, types, or transmits the credential, and it does not prompt for API keys itself.
  • Edit permissions: click Permissions or run SpecPi: Edit Permission Settings while Chat is idle. Choose global or project scope and Load scope / discard draft. Edit YOLO, logging, timeout/display controls, and JSON rule maps, shell aliases, read-path exceptions, and authorizer chains. Full configuration JSON includes all supported fields. Blank fields inherit/default; {} removes this scope's overrides, not inherited rules. Form edits reformat JSON and remove comments; the full JSON editor preserves comments. Save settings… validates the draft and asks for native VS Code confirmation before writing. It never sends the configuration to the model. Restart Pi reloads the selected chat and clears its session approvals; other chats may reload policy independently. Show effective policy / discard draft explicitly discards the editor draft and runs /permission-system show; saved values are not proof of the active runtime mode. The button appears only when Pi advertises the package command. YOLO on the badge reports only upstream status, while the separate Guard saved badge reflects the saved global configuration and is not proof of active enforcement.
  • Global Destructive guard preset: load Global scope and choose Use Destructive guard. This replaces the entire draft, including old rules and options; it does not merge with the existing configuration. The complete replacement is previewed and remains editable. It asks by default, denies common destructive commands, disables YOLO and logging, and clears the authorizer chain. Undo preset restores the previous draft. Nothing is written until Save settings… and native confirmation; the existing global file is backed up. Restart Pi afterward. Project and agent files are neither inspected nor modified. Their runtime overrides still follow Permission System behavior. The case-sensitive deny patterns also block some benign operations and are not a sandbox or exhaustive command detector. While the saved global configuration matches this preset, the composer badge shows Guard saved with a dashed outline instead of Permissions, and Guard saved · YOLO when Pi also reports YOLO. The badge updates on connect, when settings open or save, and on manual refresh; an unreadable configuration leaves the ordinary badge.
  • Configure an installed package: click Package settings or run SpecPi: Edit Package Settings while Chat is idle. The dialog offers only the packages the connected session actually reports, and each one names a single file Chat is allowed to write. Web access edits the provider configuration; stored credentials are never displayed, copied or logged, and a value you do not retype is written back from the file unchanged. Jev layer edits the advisor's settings: one switch for the layer, its seven systems, the per-session call budgets, and what a stuck verdict may do. Everything in that layer ships off. Turning the layer on here turns on every system that is off, because a layer with no systems on runs and does nothing — the boxes tick in the form before you save, so you can turn any back off first, and turning the last one off switches the layer off rather than ticking them all back on. The panel also reports where the layer's API key comes from: it resolves one the way every other Pi provider is resolved, from the openrouter entry /login openrouter writes to Pi's auth.json and then from OPENROUTER_API_KEY in the environment Pi was started with. Chat checks whether each source holds a key and never reads, stores or displays the value, so add or change one with /login openrouter in Pi rather than here. The command guard is the separate pinned specpi-jev-guard package. It is not part of this layer and is not configured here or by /jev, but it resolves the same credential in the same order, so this one key serves both. It is the only thing SpecPi installs that can refuse a tool call, and it fails closed: with no key, no network, or an answer it cannot parse, the call does not go through. SpecPi installs it switched off; /jev-guard setup in Pi turns it on, and /jev-guard reports its state. While it is gating, the session footer shows its counter beside the token and cache readouts — classifier calls this session, turning amber once it has blocked something, with the package's full line in the tooltip. It is a readout, not a control: the guard is configured in Pi, not here. Saving validates the draft, asks for native VS Code confirmation, backs the file up, and writes atomically; a refused draft never reaches disk. Restart Pi afterwards so the package reloads it.
  • See what the Jev layer has spent: the Jev panel shows the advisor's call count beside each budget — the total and one row per system, with how many of those calls changed anything, and whether the session those counts belong to is still running. The numbers come from the advisor's own usage.json, which holds counts and nothing else: no session state, no questions, no answers. Chat reads that file and never writes it, and reloads it whenever you load or save these settings. Like the settings themselves it belongs to the agent directory rather than to one chat, so with several Pi sessions sharing a directory the counts describe whichever wrote last; the panel dates them so you can tell. The advisor only starts writing the file once the layer is on, so a layer you have never enabled shows no calls, and a session that ends abruptly leaves its last count marked as still running.
  • Use Pi commands: commands exposed by your installed Pi extensions appear in the command picker. /help shows local help without connecting, /new creates a conversation, and /compact asks Pi to compact the current context.
  • Follow delegated agents: Chat supports the specpi-delegation package included in SpecPi's base. The agent panel above the composer shows queued and running workers with their mode, task, elapsed time, model calls and tool calls, and each worker has a Stop button that sends the package's own /delegate cancel-worker command. delegate tool results render the returned report; saved conversations restore it. The live list is observational: disappearance is not proof of success, and a delegated report is advisory evidence rather than verification. Delegation ships off; /delegate on enables it for a session and /delegate startup on saves that choice. Chat reads the package's published widget and registers no tools or commands of its own.
  • Manage conversations: open Chat History to search conversations in the selected workspace, see which are running or waiting for input, and rename or archive a row directly. The Archived tab lets you restore conversations. Switching chats preserves their Pi processes, drafts, attachments, and scroll position; responses continue in the background. New Chat opens a blank draft and starts Pi when you connect or send.
  • Branch or edit a prompt: Branch Conversation clones the current conversation. Edit an Earlier Prompt creates a branch before the selected user message and restores its exact text and images to the composer for review. Neither action sends the draft automatically or rolls back code files.
  • Find, copy, or export: use Ctrl+F (Cmd+F on macOS) to search the displayed conversation. Copy Conversation copies its visible Markdown; Export Conversation opens an unsaved Markdown document in VS Code. Images appear as placeholders, and truncated earlier content is not reconstructed.
  • Inspect usage: The footer shows Pi's reported conversation cost in USD beside context/token usage. It updates after completed turns and when switching conversations; hover for the detailed amount or click for Session Usage, including input/output and cache tokens. Cache hit is always visible by default: reported cache read tokens divided by input + cache read + cache write tokens, rounded to a whole percent. It follows Pi's latest usage report (current response while streaming, conversation totals after refresh). It shows until input usage is available; output tokens are excluded. Missing costs remain hidden rather than displaying zero. Context usage remains unavailable when Pi has no fresh measurement after compaction.
  • Provider limits: a compact Limits row shows reports from the base's @sreetej510/pi-usage package, including Anthropic, with keyboard-expandable details and source labels. These are package-reported subscription/rate-limit budgets, separate from conversation cost. Used percentages, loading, errors, unavailable values, cached ages, and resets remain as reported upstream. Send /usage or /usage --refresh in the composer for its reports. The sidebar does not query providers, read authentication or usage-cache files, automatically consume banked resets, or reproduce terminal-only custom footers. Updates belong to their live conversation and are cleared on disconnect/reconnect. The VSIX does not install packages.
  • Review edits: Review Changes lists working-tree, staged, untracked, and conflicted files through VS Code's Git integration and opens the selected change in the native editor or diff view. It does not stage, commit, or restore files.
  • Open code references: click a file reference such as src/app.ts:12:3 or src/app.ts#L12-L18 to reveal that location in the editor. Markdown links and inline code references work; plain file-and-line references are also detected. Targets must be regular, non-sensitive files inside the selected workspace. References inside fenced code examples remain copyable source text.
  • Switch folders: use SpecPi: Choose Chat Workspace in a multi-folder workspace. Each folder has its own history; changing folders preserves the conversations already running elsewhere.
  • Disconnect: use SpecPi: Disconnect Pi to stop the selected conversation's process. Other conversations keep running. Reconnect to continue; closing the VS Code extension host stops all its Pi processes.
  • Restart: click Restart Pi in the Chat title bar or run SpecPi: Restart Pi from the Command Palette to stop and reconnect the selected chat's Pi process, reloading its extensions and resuming its saved conversation. This interrupts any active response and clears queued sends and pending approval dialogs. Unsent composer text and attachments stay in the chat; other conversations keep running.

Pi extensions can request confirmation, selection, or text input through the sidebar. Responses go back to the requesting conversation's Pi process. A background conversation appears as needing input in history; open it to respond. Switching away does not approve or cancel the request. A cancelled or timed-out dialog does not silently grant approval.

Stop clears queued work before aborting the active response. Pi returns only the text of cleared queue entries. Chat retains image snapshots for accepted queued prompts, with at most eight images / 20 MiB across pending and recovered drafts, and offers an explicit restore action when a returned entry matches exactly. It does not guess when text was transformed or a match is ambiguous; the sidebar explains when an image draft cannot be recovered. Restoring does not send it, and a later unrelated message does not inherit those images.

Default package support

Chat uses the packages installed in Pi; it never installs copies. Permission settings change only through the explicit editor/save flow. Restart Pi after installing/updating the base. Type / to discover commands advertised by the connected runtime. Tools retain their upstream execution behavior.

PackageChat support
pi-web-accessSearch/fetch tool text and links; upstream configuration stays in Pi.
specpi-browser-qaQA tool progress, results, and returned image blocks. Its tools ship withdrawn: /browser on offers them for a session, /browser startup on saves it. Confirmed SpecPi install/update sets up Chromium with Node; use specpi doctor to check readiness. Chat does not install browsers.
specpi-delegationLive worker activity with mode, task, elapsed time and call counts, per-worker Stop, and rendered delegate reports. Ships off: /delegate on for a session, /delegate startup on to save it. Budgets and timeouts use its own commands.
specpi-experiments/experiment command discovery and its editor, confirmation and notification dialogs. Experiment worktrees are opened in a separate Pi session, not inside Chat.
pi-goal-xGoal commands, visible progress/completion messages, status widgets, and RPC questionnaire dialogs. Terminal-only custom settings views are not rendered.
@sreetej510/pi-usagePublished provider-usage status in Limits and /usage reports. Chat does not read credentials or perform its own provider refreshes.
@gotgenes/pi-permission-systemExact approval replies and an editable global/project configuration UI, reviewed against 32.0.2. Rules use ordered JSON maps; unknown or invalid fields block saving rather than being discarded. Show effective policy uses the upstream command. Per-agent frontmatter remains upstream and can override saved scope settings.

Visible package messages and generic widgets render as bounded text. Messages explicitly marked hidden stay hidden. Package-specific terminal renderers and custom footers are not reproduced in the sidebar. The full base is checked with Pi 0.84.4; Pi Goal X currently declares >=0.83.0 <0.85.0 support.

Supported content and controls

CapabilitySupport in this preview
Text, Markdown, code blocks, tables, HTTP(S) linksYes; model output is rendered without executing HTML.
Text/code attachments and editor selectionsUTF-8 text, 64 KiB per attachment, inside the selected workspace; up to eight attachments total, including images. The active editor selection is also offered above the composer and attaches on send unless hidden by clicking the chip. It counts toward the eight; a message already holding eight attachments asks you to hide the chip or remove one.
Folder references and listingsSelecting a folder in @ suggestions, an @folder/ mention, or an Explorer Attach File attaches one bounded directory listing (200 entries / 16 KiB) as a single attachment; contents are never read automatically. Sensitive paths are skipped.
File and folder suggestion filteringSuggestions respect files.exclude, search.exclude, and the workspace-root .gitignore (search.useIgnoreFiles); explicit attachment of ignored paths stays available.
File, line, column, and line-range referencesYes; click to open the validated workspace file in VS Code.
Image attachments, pasted screenshots, and image drag-and-dropPNG, JPEG, GIF, and WebP; image-only or mixed messages; an image-capable Pi model is required.
Inline images and Markdown image previewsValidated Pi image blocks render inline. Click a local image reference, ordinary Markdown link, or inline PNG/JPEG/GIF/WebP filename to preview a validated workspace image rather than open it as text. External image URLs open through the browser link action; Chat does not fetch them.
Models and thinking levelsPi's available options, including max when supported by the selected model.
Streaming, tools, approvals, Stop, steering, and follow-upsYes, through the local Pi runtime.
Chat history, branching, and earlier-prompt editingSearchable extension-owned conversations, rename, archive/restore, and independent live processes. Editing restores a draft on a new conversation branch and leaves code files as they are.
Search, copy, export, and usageSearch the visible transcript, copy/export visible Markdown, and see Pi's reported conversation cost beside context/token usage in the footer. Hover or click it for details; image bytes are omitted from exports.
Native diff reviewWorking-tree and staged Git changes, with explicit selection before opening a diff or file.
Inline completions and file checkpointsNot implemented; there is no automatic file undo or checkpoint restore.

Each image is limited to 5 MiB, 16,384 pixels per side, and 40 million pixels. A message accepts at most eight mixed attachments and 20 MiB of image bytes. The visible transcript retains at most 32 images / 20 MiB; omitted images receive a display notice. These limits apply before base64 expansion. Pi and individual providers can impose narrower format or image-count limits.

The RPC connection accepts JSON records up to 64 MiB and buffers at most 64 MiB of pending writes. A very large image-bearing Pi history can exceed the response limit even when each original prompt was within the attachment limit. Recognized oversized history responses are drained without disconnecting Pi; the sidebar explains that older messages could not be loaded, and you can continue, compact, or start a new chat. Editing a prompt from an oversized history reports the limit without changing the conversation.

Privacy and boundaries

The sidebar starts Pi as a child process over its local JSON-lines RPC interface. Pi owns provider authentication, provider requests, tools, and SpecPi enforcement. Chat messages and attached content are sent to Pi and may be sent by Pi to your configured provider. The extension does not store or inspect provider credentials.

Provider sign-in is delegated in full. Sign in to a provider starts your configured Pi executable in a VS Code terminal with no RPC flags and no session attached, and everything after that belongs to Pi: it prompts, opens any browser flow, and writes its own auth.json. Chat does not read that file, run Pi's auth commands, prompt for keys, or receive a credential over RPC. It only notices that the terminal closed and restarts Pi, because Pi resolves its model catalogue once at startup and cannot see a credential stored afterwards. The terminal is yours: Chat never sends input to it, and closing Chat leaves it running.

Opening the view does not start Pi. Connecting or sending a message does. Trusted-workspace access is required because Pi can read and change files and execute tools in the selected workspace. The extension does not replace Pi's tool policies or Permission System.

The permission editor reads/writes only extensions/pi-permission-system/config.json under the host's Pi agent directory (respecting PI_CODING_AGENT_DIR) or the selected project's .pi directory. It does not inspect permission logs, trust decisions, credentials, or per-agent files. Files must be unlinked regular UTF-8 files of at most 64 KiB, with no symlinked ancestry. Existing content is backed up to an adjacent config.json.<id>.bak before atomic replacement; backups remain local and can contain sensitive rules/paths. To restore one, paste its content into the full configuration editor and save. Stale disk revisions reject a save and retain the draft; reload explicitly before retrying. Native confirmation is bound to the requesting conversation and connection. Project policy is subject to Pi's own project-trust decision and per-agent precedence. Saving global settings affects other projects as they reload; this is not a per-chat permission mode. Concurrent external filesystem changes are not an OS-sandboxed transaction.

Only conversations created through this extension appear in Chat History. Pi writes those transcripts under VS Code's workspace storage, separate from its ordinary session directory. The extension keeps a bounded index of its own session references and retrieves conversation messages through Pi RPC. It does not enumerate or import your existing Pi terminal history. Archive hides a conversation from the main list without deleting its file or stopping its process; restore it from the Archived tab. VS Code can retain extension storage after uninstall.

Text/code attachments and file references are restricted to the selected workspace. Explicit image selection, pasted screenshots, and dropped image files may come from outside it; image file paths still undergo regular-file and sensitive-path checks. Image bytes are checked against supported formats, dimensions, and size limits. Attachments are snapshots for the user to review, not a content-based secret detector. Pi itself may read other files while completing your request.

Draft images and display media caches remain in memory. Sent images become part of Pi's extension-owned conversation files and may be sent to the configured provider. The webview receives media by identifier, renders validated data images under img-src data:, and does not fetch remote images, scripts, or styles. Model output never executes as HTML. There is no extension telemetry or transcript logging to an output channel. Copy and Export are explicit ways to move the visible conversation into the clipboard or a document.

Current limits

  • Pi must already be installed. SpecPi is optional. The sidebar does not install packages, and it does not perform provider sign-in itself: it starts Pi in a terminal so Pi can. Permission System's documented global/project config files are the only package settings edited by the Permissions UI.
  • Sign-in detection reads what Pi reports, not your credentials. An empty model list on a connected session, or Pi's own missing-credential error on a send, raises the prompt. A provider that is configured but rejected upstream (an expired key, a quota block) reports as an ordinary error instead. Sign-in needs a Pi that runs interactively in a terminal; Chat cannot drive Pi's login over RPC because Pi does not expose it there.
  • Pi's RPC dialog methods are supported; custom terminal UIs, overlays, and TUI-only commands do not run inside VS Code.
  • Ignore filtering reads the workspace-root .gitignore only; nested .gitignore files and core.excludesFile are not followed yet. The ignore file must be a regular, unlinked UTF-8 workspace file of at most 64 KiB. Unsafe or unavailable ignore files stop filtering with an error rather than exposing ignored entries; fix the file or explicitly disable search.useIgnoreFiles. Malformed character-class rules are skipped individually. Boolean files.exclude and search.exclude entries are supported; sibling-dependent { "when": ... } entries are not yet supported. false disables only the matching settings key. Filtering permits at most 1,000 compiled rules, 4,096 characters per pattern/path, and a bounded matching-work budget; exceeding a limit reports an error.
  • Folder listings are capped at 200 entries and 16 KiB per attachment, and scan at most 1,000 entries across the snapshot, including hidden entries. Only that bounded sample is sorted; large folders may be incomplete even when most entries are hidden. The listing includes a truncation notice when a limit is reached.
  • This preview does not provide inline ghost text, an apply-patch approval editor, file checkpoints or undo, or import of existing terminal conversations. Conversation branching changes chat history; it does not restore the worktree. Pi tools still perform workspace edits through the existing harness.
  • Each connected conversation keeps its own Pi process until explicitly disconnected or the extension host closes. Conversations can run concurrently in the same workspace; their tools operate on that shared workspace. Unsent drafts remain in memory for the current extension-host lifetime.
  • Model and reasoning choices depend on the connected Pi installation and provider. A successful local test does not establish that a provider is configured or reachable.
  • Image format, animation, and vision behavior vary by provider. Passing local validation establishes the sidebar's transport boundary, not provider support for every accepted image.
  • Remote workspace execution follows VS Code's extension-host model; the host and Pi must have access to the intended workspace filesystem.

Connection troubleshooting

If Pi works in the terminal but Chat 0.1.0 reports Pi did not respond to get_state in time, install the latest VSIX from the setup steps above and reload VS Code when prompted. Older SpecPi Guard versions wait 30 seconds for a startup selection before Pi begins reading RPC requests, which conflicts with 0.1.0's 30-second request timeout. Chat now gives startup up to 90 seconds while keeping normal request timeouts at 30 seconds.

The sidebar explains the startup delay and allows cancellation. If startup still times out, update the harness from this checkout and check whether another installed Pi extension waits for a startup dialog. Pi 0.84.4 cannot read dialog responses until its startup handlers return; an extension that waits indefinitely must implement an RPC-compatible startup path. The sidebar does not bypass extension policies or grant startup approvals.

If a message was accepted but the subsequent status refresh failed, use Refresh status. This only retrieves the current conversation and does not send the message again. A dropped connection before Pi acknowledges a prompt leaves its outcome uncertain; inspect the resumed conversation before deciding whether to send it again.