istari AI
A VS Code companion extension for the istari CLI - a general
bridge between the editor and the CLI over a local socket. You can run the
workflows as guided commands (no CLI typing), approve or deny istari's gated
actions, watch its live progress and report, and steer a running
session from VS Code instead of the terminal; more interactions can be added
over the same socket.
Guided commands
Run any workflow from the Command Palette (Ctrl/Cmd+Shift+P)
under the istari category - a short prompt sequence assembles the exact CLI
invocation for you, so you never hand-type a subcommand, flag spelling, or enum
value:
| Command |
Prompts |
| istari: Review Pull Request |
Remote PR (URL/number, prefilled from the clipboard) or local changes (scope, optional base); optional linked tickets, context, quality, and flags. |
| istari: Review Ticket |
One or more ticket ids/URLs (prefilled from the editor selection); optional context, quality, and flags. |
| istari: Review Plan |
Plan/design document path (prefilled from the active editor when possible), loop mode, readiness floor, optional round cap, and plan-review flags. |
| istari: Check Environment |
Provider (all / jira / ado / github) and whether to probe. |
| istari: Initialize Config |
Full interactive wizard or example file only. |
Extra entry points:
- Source Control view → Review Local Changes reviews the current worktree in
one click, targeting the repo the SCM view points at (multi-root safe).
- Editor context menu → istari: Review Ticket appears when you have a
selection, prefilling it as the ticket id.
The quality picker for PR/ticket reviews maps to the CLI's refine model: Standard (the default one round), Fast (--fast), or Refine 2-5 (--refine N). The PR/ticket review commands use istari.defaultModel (below) for --model; plan-review uses it for --architect-model; env-check and init never receive it.
The review commands (Pull Request / Ticket / Plan) hand off to an @istari
chat run, so the whole run - progress, approvals, questions, and the final
report - renders in one chat response; env-check / init launch in a task
terminal. Everything binds the same window-level socket, so only one review runs
at a time; a quick env-check or init can run alongside it.
How it works
While this extension is active it exports ISTARI_AI_SOCKET into the window's
integrated terminals, so any istari run started here binds the socket
automatically - no --approval-socket flag needed (passing the flag still
works and wins). istari sends each run-time question - a permission approval, a
timeout continue/stop, an ask_user question, or an inbound elicitation - over
that socket as a versioned ui_request; the extension renders it in the
@istari chat response with buttons or an editor form and sends a complete
ui_response straight back. There are no modal popups.
With no chat monitor, the extension surfaces a non-modal notification; opening
@istari /watch later re-renders every unanswered request for the live socket
connection. Closing a monitor therefore never loses a question. A startup version
handshake rejects a mismatched CLI/extension pair with one message and falls back
to the terminal rather than mis-rendering.
If another terminal-started review tries to bind the same Unix socket path, it
does not steal the active chat session; it falls back to terminal prompts.
The full message contract is the Run UI protocol.
sequenceDiagram
participant istari
participant Socket as .istari/istari.sock
participant Chat as @istari chat
istari->>Socket: hello (version)
Chat->>Socket: hello_ack + ui_available
istari->>Chat: ui_request {kind, questions, codeBlocks}
Chat->>istari: ui_response {action, answers}
Note over Chat: rendered as chat buttons
Usage
Build and install this extension (see Development below).
Open a terminal in this window and run istari normally - no flag needed:
istari ticket-review <jira-url>
(Terminals opened before the extension activated won't have the env var yet;
open a fresh one. The istari: Run istari in a terminal command also works.)
The status bar shows istari: connected once linked. Watch the run with
@istari /watch; approvals and questions then render in that chat response.
Chat: watch, steer, and run
The @istari chat participant reuses VS Code's built-in chat - no separate UI:
@istari /watch - stream the running agent's progress and report here.
@istari /reasoning - compatibility command; raw reasoning text is no longer streamed, so it points you to /watch or /report.
@istari /report - stream only the report/output and the final result.
@istari /run <args> - start a run in a terminal (e.g. /run ticket-review <url> or /run plan-review docs/plan/my-plan.md) and stream it here for review workflows.
@istari <message> - steer the run: the message is queued and folded into
the agent's next pass (istari can't interrupt a pass mid-flight, so it applies
at the next draft/repair/refine/steer pass). Steering never changes permission
decisions.
Streaming into chat needs an open chat turn, so start with /run (or invoke
/watch while a run is active). While a monitor is watching, istari's approvals
and questions render in that chat response. Simple choices use buttons; structured
elicitation and multiple required fields use the request's Answer action, which
collects the whole response before submitting it. A simple single-text question also
accepts @istari req:<id> <answer>. Cancel the chat response to stop watching; a
later /watch restores any unanswered request for the live socket connection.
CI / headless: omit the extension and use --yes (approve-all) or run without
a TTY; istari handles non-interactive approval on its own.
Windows: istari uses a named pipe instead of a Unix socket. Set
istari.socketPath to a pipe path (e.g. \\.\pipe\istari-ai); the extension
exports it the same way.
Settings
| Setting |
Default |
Description |
istari.socketPath |
.istari/istari.sock |
Socket path istari binds. Relative paths resolve to the workspace folder. |
istari.autoConnect |
true |
Connect automatically whenever the socket appears. |
istari.binaryPath |
istari |
Executable for the guided and terminal commands. Bare command → PATH; relative path → first workspace folder. |
istari.defaultModel |
"" (empty) |
Comma-separated model list for AI review commands. PR/ticket reviews receive it as --model; plan-review receives it as --architect-model; empty omits the flag. |
Commands
- istari: Review Pull Request / Review Ticket / Review Plan / Check Environment / Initialize
Config - guided workflows (see Guided commands).
- istari: Review Local Changes - one-click local review from the Source
Control view.
- istari: Run istari in a terminal - power-user escape hatch: type raw istari
args (tokenized and launched as a task; no shell).
- istari: Connect to the istari socket - connect now.
- istari: Disconnect from the istari socket - drop the connection, invalidate pending run-UI requests, and end active chat monitors.
Development
npm install
npm run compile # or: npm run watch
npm test # unit tests (arg assembly, tokenizer, CLI-manifest drift)
Press F5 in VS Code to launch an Extension Development Host.
The guided commands assemble argv from a small typed table
(src/commands.ts), whose enum/provider values are
drift-guarded against the CLI: cli-manifest.json is a committed snapshot of
istari __cli-manifest, and both a Rust test and
src/test/manifest.test.ts fail if a flag, enum, or
provider changes without regenerating it
(UPDATE_MANIFEST=1 cargo test manifest_matches_fixture).
Wire protocol
Line-delimited JSON, one object per line:
// istari -> extension
{ "type": "permission_request", "id": 1, "action": "run a shell command",
"command": "rm -rf build", "intention": "clean the build dir", "risk": "destructive" }
// istari -> extension (live run stream, rendered by @istari chat)
{ "type": "run_start" }
{ "type": "reasoning", "text": "…thinking tokens…" }
{ "type": "report", "text": "…agent message tokens…" }
{ "type": "status", "text": "← calling tool 'grep_code' query=foo|bar isRegexp=true" }
{ "type": "result", "text": "…final rendered deliverable…" }
{ "type": "run_end" }
// extension -> istari (approval verdict)
{ "id": 1, "decision": "approve" } // or "deny" | "always"
// extension -> istari (steering, from @istari chat)
{ "type": "steer", "text": "also cover the error-handling path" }