feat: pi extension - #1
Conversation
|
add |
|
sandbox firewall show <sb> |
read the allowlist |
sandbox firewall set <sb> <host>… |
replace the allowlist |
sandbox firewall clear <sb> |
open the firewall |
--egress exists only on create and fork. Additionally, an empty rules array produced a no-op rather than clearing the allowlist, which is the opposite of what the prompt promised.
sandbox_list had the same class of bug: it called sandbox list with no flags, which hides everything not active, while its own prompt claimed it listed paused sandboxes. It now takes all and status.
2. The prompt surface had no layering
Restructured into three layers, each with a distinct job:
| Layer | Where | Job |
|---|---|---|
| System prompt block | sandboxSystemPrompt() in index.ts |
Facts no single tool can teach. Injected every turn. |
description |
per tool | What it does + preconditions (paused source, ingress on, running sandbox). |
promptGuidelines |
per tool | When to reach for it, what to reach for instead, and the failure it prevents. |
Two facts were absent from every prompt and cost the model turns on every session:
- The user's files are not in the sandbox. It starts empty and cannot see their disk, so reading a
/Users/…path always fails. The model would discover this by failing, then reach forsandbox_sync. - Exec output is buffered.
createos sandbox execreturns only when the command exits, so a foreground server (npm run dev,flask run) hangs the tool call forever. Nothing said to background it.
The system prompt now also carries the cross-tool routing rules, which are the part the model genuinely cannot derive:
- Port access:
sandbox_preview_url→sandbox_tunnel→ device VPN - Many identical machines:
sandbox_pause+sandbox_fork, not N ×sandbox_create - Anything that must outlive the sandbox:
sandbox_sync,sandbox_disk_attach, or git bashis always the session sandbox; every other sandbox needssandbox_exec
Per-tool guidelines now name the failure they prevent rather than restating the description — e.g. a firewall allowlist without a DNS resolver such as 1.1.1.1:53 breaks name resolution and every subsequent request.
3. Features with no tool behind them
A prompt cannot make the model aware of a capability that has no tool, so these were added. 33 tools → 47.
| New | Covers |
|---|---|
sandbox_editor |
remote VS Code / Cursor / Zed over SSH |
sandbox_auto_pause |
idle timeout so a sandbox stops billing compute |
sandbox_firewall_show |
read the current egress allowlist |
sandbox_template_submit / _list / _logs / _delete |
custom rootfs images built from a Dockerfile |
sandbox_create gained env, disks, egress, auto_pause, ssh_keys and disk_mib — all documented CLI flags the tool previously dropped.
4. Docs drift
packages/pi-extension/README.md listed five agent tools that do not exist (sandbox_manage, tunnel, preview_url, network, device). Both READMEs carried stale tool counts, and CLAUDE.md's inventory was off by seven. All corrected.
Verification
Drove the real src/cli.ts wrappers against a live sandbox, not mocks:
PASS createSandbox(env, egress, autoPause) — sb-01kz6510wh2bbkb3z9kczekw30
PASS ingress enabled at create — https://01kz…-<port>.app.sb.createos.sh
PASS create --env reaches exec — "yes"
PASS showFirewall reflects create --egress — {"rules":["pypi.org","1.1.1.1:53"]}
PASS setFirewall replaces allowlist — {"rules":["github.com","1.1.1.1:53"]}
PASS clearFirewall empties allowlist — {"rules":[]}
PASS editSandbox --auto-pause off
PASS listSandboxes(status) — 12 running
PASS listTemplates
cleaned up sb-01kz6510wh2bbkb3z9kczekw30
9/9, sandbox destroyed afterwards. tsc --noEmit and oxlint both clean.
Structure
src/tools-resources.ts (networks, disks, templates, devices) split out of tools.ts to stay under the 1100-line file limit. tools.ts calls registerResourceTools(); the import back from tools-resources.ts is type-only and erased at compile time, so the cycle is not real.
Deliberately left out
sandbox exec --stream—pi.exec()returns only on process exit, so streaming changes nothing observable.sandbox shell— an interactive PTY, which a tool call cannot host.sandbox_editorcovers the "let the user in" case.- REST-only features (self-signal, metrics, bandwidth recharge, resize, webhooks) — no
createos sandboxsubcommand exists for them, and this extension is CLI-only by design. They stay out until the CLI carries them.
The scope question, the three options weighed, and these exclusions are recorded in packages/pi-extension/docs/decisions.md.
Note for reviewers
The oxfmt pre-commit hook reformats any .ts file it touches, and this repo had never been oxfmt'd (it was single-quote / no-semicolon). Roughly 80% of the diff in index.ts, cli.ts and tools.ts is therefore style, not substance. src/ops.ts, find-tool.ts and grep-tool.ts were left untouched, so the package is currently half-formatted — worth a separate mechanical commit to make it uniform.
fb21567 to
606f9a0
Compare
Move createos-sandbox and pi-extension into packages/ directory, following the Daytona integrations pattern. Add apps/ placeholder, CONTRIBUTING.md, and update marketplace.json source path.
Rename packages/createos-sandbox → packages/claude-code-plugin to make it clear the package is for Claude Code. Add Pi extension quick start, flags, and in-session commands to the root README.
606f9a0 to
7187f7b
Compare
Changes
piextension.Usage
pi install /path/to/repo/packages/pi-extensionpi --createos