Shell Built-In
Built-in shell tools, sandbox modes, and approval flow
Shell Built-In
Shell is no longer a plugin. It is a built-in capability provided by @downcity/shell and mounted on an Agent with new Shell().
import { Agent } from "@downcity/agent";
import { Shell } from "@downcity/shell";
const agent = new Agent({
id: "repo-helper",
path: "/path/to/project",
shell: new Shell(),
});Tools
Mounting shell: new Shell() adds these model tools:
shell_execshell_startshell_statusshell_readshell_writeshell_waitshell_close
Sandbox Modes
Shell tools run in the Safe Sandbox by default.
Use sandbox: "unrestricted" only when a command needs host-level access, such as brew install, npm install -g, pip install --user, gh auth login, or service initialization outside the project sandbox.
shell_exec({
cmd: "brew install ffmpeg",
sandbox: "unrestricted",
reason: "Homebrew writes to the host-level package directory.",
});Unrestricted execution always requires user approval. Missing reason is rejected before execution.
Approval API
Clients approve shell requests through the Agent SDK:
const pending = await agent.approvals();
await agent.approve({ approval_id: pending[0].approval_id });
await agent.deny({ approval_id: pending[0].approval_id });RemoteAgent exposes the same API over the Downcity Agent HTTP gateway.
Session Approval Mode
Shell approval mode is scoped to the current session:
ask: default mode. Every unrestricted request enters the approval queue.always-allow: automatically approves shell approvals in the current session.
const modes = agent.approval_modes();
agent.set_approval_mode({
session_id: "consoleui",
mode: "always-allow",
});
const current = agent.approval_mode({ session_id: "consoleui" });always-allow does not change the sandbox mode. It only records new unrestricted requests as approved instead of creating pending approvals. Existing pending approvals are not auto-approved.
Semantics
- Shell is owned by
@downcity/shell, not@downcity/plugins. - Agent only mounts the Shell tools and forwards session events.
- Safe Sandbox commands can read and write the project and use the configured sandbox directory.
- Unrestricted commands execute outside the Safe Sandbox only after per-request approval.
always-allowonly affects new approval requests in the current session, not other sessions.- Every write to an unrestricted
shell_startsession also requires approval throughshell_write. agent.dispose()disposes Shell sessions.