Code Build
A generalized, Claude-Code-style coding-agent UI for VS Code that drives multiple
agentic CLIs behind one streaming chat — opened as an editor tab, a new window,
or a sidebar view.
One UI, many agents: Claude Code, Grok, Codex, and any ACP agent
(opencode, Cline). Every backend is normalized into a single ACP-shaped event model
(Approach A), so the UI is backend-agnostic.
Why
- Looks/feels like Claude Code for VS Code — streaming text, tool-call cards, inline
diffs, permission prompts, plan mode, slash commands.
- Backend-agnostic — pick Claude, Grok, Codex, or any ACP CLI from the same chat.
- Interops with Code Sessions
rather than replacing it: code-build produces sessions; Code Sessions analyzes them.
Architecture (Approach A — ACP-canonical)
Suite-level architecture (how CB relates to Code Sessions, KP, the sessions daemon and where the
store is heading) lives in the private unpolarize/architecture repo — ../architecture/tools/
next to this clone (docs/suite-architecture symlink). This section covers only CB internals.
Webview (React + Vite) ──typed postMessage──▶ Extension Host
chat · tool cards · diffs SessionManager
permissions · slash cmds AgentSession (ACP-shaped events)
├─ StreamJsonTransport (claude)
├─ CodexTransport (codex exec --json)
└─ AcpTransport (grok/opencode/cline)
EditorTools · SessionStore · JSONL export
AcpTransport — newline-delimited JSON-RPC 2.0 over the agent's stdio
(initialize → session/new → session/prompt → session/update), bridging
fs/* and session/request_permission back to the editor/UI. After
initialize, a read-only ACP protocol-version pin chip in the chat header
shows the negotiated version (amber warn on v1↔experimental-v2 mismatch; never
blocks the session). A spend-limit parity chip mirrors Claude Code 2.1.251
/usage spend-limit bar semantics when rate_limits.spend_limit is present;
other backends show spend n/a (never fake remaining %). A maxEffortLevel
ceiling chip (ceil high · managed / ceil med · local) surfaces Claude
2.1.267 org/user effort caps and codex-acp recommended effort; setEffort/send
above the ceiling warn or block per codeBuild.effortCeiling.mode
(codeBuild.maxEffortLevel host pin). Distinct from the effort-semantics
drift canary. A teammate-context compact proxy chip (team near N · compact M) watches Agent Team / Agent-tool children approaching their
context limit (Claude #49786
class — members lack vendor auto-compaction); click it or run Compact
Teammate Context to stage a summarize primer or park-handoff cartridge
(codeBuild.teammateCompact.*).
StreamJsonTransport — drives claude -p --input-format stream-json --output-format stream-json; a ClaudeNormalizer maps native NDJSON to
SessionUpdates.
CodexTransport — spawn-per-prompt codex exec --json; captures thread_id for
resume (codex exec resume).
Normalizers convert every backend into the one SessionUpdate union the webview reads.
Backend matrix
| Backend |
Transport |
Spawn |
| Claude |
stream-json |
claude -p --input-format stream-json --output-format stream-json --verbose |
| Grok |
ACP |
grok agent stdio |
| Codex |
exec-json |
codex exec --json --skip-git-repo-check -s <sandbox> |
| opencode |
ACP |
opencode acp |
| Cline |
ACP |
cline --acp |
Spawn args are centralized in src/host/backendRegistry.ts so CLI flag drift lives in
one place.
Voice mode (0.13+)
Dictation, hands-free interactive (listen → send → speak reply), and Voice Ideation Sessions (VIS) that extract thoughts/ideas into the knowledge-planning store.
- Voice bar above the composer: Mic · Hands-free · VIS · Stop
- Slash:
/voice, /dictation, /vis, /vis-close, /stop-voice
- Full guide: docs/VOICE.md
Requirements
Node.js ≥ 18 and npm (built with Node 24 / npm 11).
VS Code ≥ 1.90 with the code CLI on your PATH
(in VS Code: Cmd/Ctrl+Shift+P → "Shell Command: Install 'code' command in PATH").
At least one backend CLI installed and logged in — you only need the ones you plan to
use:
- Claude Code —
claude (install)
- Grok —
grok (xAI Grok Build)
- Codex —
codex (OpenAI Codex CLI)
- opencode / Cline —
opencode / cline (any ACP agent)
Code Build auto-detects which are present (via which) and disables the rest in the
backend picker. Set explicit paths with the codeBuild.binPaths setting if a CLI isn't
on PATH.
Install
Option A — build, package, and install a VSIX (recommended)
git clone https://github.com/unpolarize/code-build-vscode.git
cd code-build-vscode
npm install # install dependencies
npm run build # build the webview (vite) + host (esbuild) into dist/
npm run package # produce code-build-vscode-0.0.1.vsix
npm run install-extension # = code --install-extension <the .vsix> --force
Then reload VS Code (Cmd/Ctrl+Shift+P → "Developer: Reload Window"). You'll see a
Code Build icon in the Activity Bar.
Prefer the GUI? After npm run package, open the Extensions view
(Cmd/Ctrl+Shift+X) → … menu → Install from VSIX… → pick
code-build-vscode-0.0.1.vsix.
To uninstall: code --uninstall-extension zhirafovod.code-build-vscode.
Option B — run from source (Extension Development Host)
npm install
npm run build
Open the folder in VS Code and press F5 (Run → Start Debugging). A second
"Extension Development Host" window launches with Code Build loaded — handy for
iterating, since npm run watch:host and npm run watch:webview rebuild on change.
Usage
- Click the Code Build icon in the Activity Bar for the sidebar chat, or run
Code Build: New Conversation (
Cmd/Ctrl+N) to open a chat as an editor tab.
- Pick a backend (Claude / Grok / Codex / …) and a permission mode in the header.
Default is bypass (autonomous). Out of the box, new conversations run the agent without per-action approval prompts (Claude Code's --dangerously-skip-permissions workflow), and in bypass mode your $HOME is trusted. To require approvals, set codeBuild.allowDangerouslySkipPermissions to false or pick default / plan / acceptEdits.
- Type a request and press Enter. Type
/ to see backend-provided slash commands (per-agent).
Type @ (or pick from suggestions) to reference a workspace file as context; @browser or
@web for browser/web context hints. File references become resource_link blocks (or
inlined content for Codex) and work across all backends.
- Title bar actions (top-right of the editor tab, exactly like Claude Code): use the split-horizontal
and multiple-windows icons (or the commands / keybindings) to open the chat in a new tab or new window.
- Conversation history: Run Code Build: Open Previous Conversation... (Command Palette). It shows a
filterable QuickPick of all prior sessions (grouped naturally by backend when you type the name). Selecting one
opens it in a new tab with the full transcript rehydrated so you can review or continue. History is stored
under
~/.codebuild/.
- @-mentions now support full paths:
@knowledge/tech/knowledge-base-architecture.md (or any subpath) works
for file context. @browser / @web injects a browser-context hint.
- Media / pixel tool-tax (advisory): when screenshot or image MCP tool results inflate tokens, the header
shows a
media … chip and (after thresholds) a sticky pause notice with a one-click Prefer DOM/CLI action.
That arms a session-sticky host hint to prefer text/DOM snapshots over pixel loops — it never rewrites or
blocks tools. Prefer the personal Chrome Playwright path (browser-personal skill / Playwright MCP Bridge)
over screenshot-heavy MCP servers when browsing authenticated pages. Config: codeBuild.mediaToolTax.*.
- Host governors (Read size): ACP
fs/read_text_file is gated by codeBuild.toolRead.maxBytesWarn
(default 100 KiB, notice only) and codeBuild.toolRead.maxBytesBlock (default 1 MiB, hard deny until
Allow once / Allow session). Composes with post-read inject budgets — this blocks the invoice before
bytes enter context. Night/unattended sessions inherit deny without an interactive grant.
- Host governors (small-effort ScopeFence): When
/kp primes a session from a KP item with
implement_effort: small|tiny, ACP fs/write_text_file is budgeted (codeBuild.scopeFence.maxWritePaths,
default 5 distinct paths) and denied for CLAUDE.md / AGENTS.md / .grok/** unless overridden.
Architecture-digression phrases latch a write pause until expand-effort. Advisory + deny-list only —
never rewrites prompts; human override always available.
Sessions are persisted under ~/.codebuild/ and exported in a Code-Sessions-readable
JSONL format.
Data & storage
Code Build is local-first. It runs agent CLIs as subprocesses on your machine over stdio and persists conversations to your own disk — it sends no data to any external service itself; the only network traffic is whatever the agent CLI you selected makes on its own (e.g. to its model provider).
On-disk session store — ~/.codebuild/. Each chat is written as a JSONL transcript under ~/.codebuild/sessions/<session-id>.jsonl, with a history list in ~/.codebuild/index.json. Every line is one JSON record: a meta header (backend, title, mode, cwd, model, effort), user prompt records, and normalized agent update events. This directory is gitignored (.codebuild/) and is never committed.
Plaintext warning: transcripts are stored unencrypted. Anything you paste into a prompt — including API keys or secrets — is written verbatim to ~/.codebuild/sessions/*.jsonl and stays on disk until you delete it. To reset all history: rm -rf ~/.codebuild.
UI preferences (your last permission mode / model / effort) are stored separately in VS Code's globalState, not in ~/.codebuild.
Code Sessions export. Code Build can export a transcript as a Claude-Code-style turn JSONL (summary + user/assistant/tool_use/result lines) shaped to be read by the Code Sessions indexer. The two extensions are complementary: Code Build produces sessions; Code Sessions analyzes them. Code Build cross-links into it via the codeSessions.viewConversation command, and Code Sessions can open a session back in Code Build.
Filesystem confinement. ACP agents can request file reads/writes through the fs/* bridge, which bypasses the interactive permission UI. Those paths are sandboxed by a realpath-based path guard (createPathGuard / confine) that resolves the session workspace root once, follows in-workspace symlinks only when the final real path stays under that root, and rejects anything that escapes (including ../, absolute outside paths, and in-root symlinks that point out) — blocking access to ~/.ssh, ~/.aws, and other files outside your project. Bypass permission mode still skips the guard by design.
Other hardening. Subprocesses inherit your environment so CLI logins keep working, but Code Build never injects API keys. The webview runs under a strict CSP (nonce-gated scripts, default-src 'none') and renders assistant markdown through DOMPurify sanitization.
See docs/DATA-STORES.md for the full architecture, record formats, backend matrix, and event model.
Develop
npm install
npm run build # build:webview (vite) + build:host (esbuild)
npm run typecheck # host + webview type-check
npm run test:unit # node:test unit suite
npm run watch:host & npm run watch:webview # rebuild on change (use with F5)
Manual integration checks (need the real CLIs installed + logged in)
npx tsx test/manual/claudeRoundtrip.ts # Claude stream-json round-trip
npx tsx test/manual/grokRoundtrip.ts # Grok ACP round-trip (token streaming)
npx tsx test/manual/grokPermission.ts # Grok file-write task
npx tsx test/manual/codexRoundtrip.ts # Codex spawn-per-prompt (set CODEX_MODEL)
Status
Built and validated through P0–P5 (scaffold → Claude → Grok/ACP → diffs &
permissions → Codex & persistence → sidebar & slash commands). Real round-trips
validated against claude and grok.
Roadmap (remaining)
- Full new-window state restore (rehydrate transcript from
~/.codebuild on the
reload a window-move forces).
- Localhost
ide MCP server exposing EditorTools to CLIs (Claude Code's pattern).
- Live permission-mode switching for stream-json backends (control protocol).
- MCP server config UI; modes/profiles; checkpoints/rewind.
License
MIT