
Steerable¶
The model-quality layer that makes local, quantized, and cheap models behave.
Fewer hallucinations Simple to use Ready out of the box Componentized
Fewer hallucinations, fewer silent failures — even on cheap models. 79.0% on Terminal-Bench 2.1 with GLM-5.3-Flash. One command boots a full agent shell; every layer underneath ships as its own package, so you adopt only what you need.
79.0% Steerable + GLM-5.3-Flash
+5.6 vs Pi on the same Flash model
229.9M input tokens per catalog run
A full agent in one command
Chat, an integrated terminal, bundled skills, a model picker, and a sandboxed sidecar, ready on first launch. Run it in the browser, as a desktop app, or from the command line — same shell, same data. Bring any OpenAI-compatible, Anthropic, or Gemini key.
More ways to installgit clone https://github.com/pathlyapp/steerable.git
cd steerable && pnpm install
pnpm agent-shell:web
git clone https://github.com/pathlyapp/steerable.git
cd steerable && pnpm install
pnpm agent-shell:client
npm install -g @steerable/agent-cli
steerable-cli
Frontier results on Flash-priced models
Terminal-Bench 2.1, 89 real terminal tasks, hidden tests; timeouts count as fail. Same models, same protocol, five agent harnesses. Methodology
Tasks solved out of 89. Color is the harness.
One run per cell at high effort (Qwen: medium). Run list and commit SHAs
Color is the harness; shape is the model (circle GLM, square DeepSeek, diamond Qwen). Higher and further left is better.
OpenRouter list prices on the pinned host. Pricing formula
GLM-5.3-Flash @high, same run as the charts: Steerable 79.8% · Claude Code 77.5% · Pi 73.0% · DSH 66.3% · Codex 56.2%.
Why Steerable
Cheap models invent data, claim work they never did, and emit tool calls as plain text. Every agent SDK assumes they don't. Steerable checks the model at each of those points — and stays out of your way.
01 · Fewer hallucinations
Answers backed by real data¶
Grounding judges reject answers the tool results don't support, a discipline retry catches claimed-but-undone work, and a completion veto can send a draft back before it reaches the user. Tool calls written as text are recovered and executed. On the DeepPath API this turns a class of 646 hard failures into retries.
02 · Simple to use
Learn it in an afternoon¶
No graph DSL or framework runtime to learn. Tools are plain functions with an @tool decorator, the harness is pure functions with zero I/O, and one JSON Schema generates both the TypeScript and Python types.
03 · Ready out of the box
Everything already wired up¶
Chat, terminal, skills, model picker, and an OS sandbox with a per-host egress allow-list come preconfigured. The hosted live demo runs in the browser with no key at all.
04 · Componentized
Take one layer, skip the rest¶
Five tiers and 13 independently published packages. Lower tiers never import higher ones, so you can use only the protocol types, only the React UI, or only the sidecar without pulling in anything else.
What's inside
The model-quality layer¶
Local, quantized, and cheap models break the structured-tool_calls assumptions every SDK makes. Steerable recovers and executes malformed calls (MiniMax XML, DeepSeek <function=>, markdown), vetoes completion drafts (accept / retry / narrate), judges grounding, and self-calibrates token estimates. Why this is the differentiator.
One wire protocol¶
One JSON Schema → generated TypeScript types + Pydantic models. content, tool_call, tool_result, error, done, budget_exhausted — all standardised, with a conformance suite keeping both SDKs byte-compatible. All 13 published packages share one lockstep X.Y.Z (including the Rust CoreLoop wheel); npm tarballs ship sigstore provenance attestations.
Pure-function harness¶
Policy, budget, retry, completion, tracing, safety patterns. Zero I/O coupling — drop into FastAPI, Celery, or a notebook. Unit and golden tests in CI.
Pluggable runtime¶
One LLMProvider interface across four wire protocols — OpenAI-compatible chat/completions (Ollama, vLLM, DeepSeek, Groq, …), OpenAI Responses, Anthropic-native, Gemini-native — plus a live gateway model catalog, per-vendor sampling presets, @tool decorator, ToolRouter, SSE-over-HTTP and stdio JSON-RPC transports.
Embeddable sidecar¶
A portable, signed CPython binary speaking JSON-RPC over stdio (34 methods). Ship local LLMs inside Electron / Tauri / Wails — macOS notarised, Windows code-signed — with an OS sandbox, per-host egress proxy, and plugin lifecycle built in.
Headless React UI & Web Shell¶
7 components + 14 rich cards + 3 hooks + Tailwind preset, each state covered by Storybook, axe a11y, and visual-regression baselines in CI. The same components power the full Web Shell (pnpm agent-shell:web).
Quickstart — pick your path
git clone https://github.com/pathlyapp/steerable.git
cd steerable && pnpm install
pnpm agent-shell:web # full agent shell → http://127.0.0.1:4787
pnpm agent-shell:client # same shell as a desktop (Electron) window
Chat, integrated terminal, bundled skills, model picker, and a Seatbelt-sandboxed sidecar, all on the production code path. Add your model endpoint in settings and start working.
Only want to explore the UI? pnpm shell:dev opens a UI-only reference app on http://localhost:5180 that replays all 14 rich cards from sample data, with no backend or API key.
from steerable_agent_runtime import ToolRouter, tool
from steerable_agent_protocol import ToolCall
router = ToolRouter()
@tool(router=router, description="Read a file by path")
async def read_file(path: str) -> dict:
return {"path": path, "content": open(path).read()}
result = await router.dispatch(
ToolCall(id="c1", name="read_file", arguments={"path": "README.md"})
)
# result.success, result.data, result.error — all typed.
# Bundle the sidecar binary into resources/python-runtime/<platform>/
# TS hosts: link:../steerable/packages/agent-runtime/ts
import { AgentRuntime } from '@steerable/agent-runtime';
const runtime = new AgentRuntime({ sidecarPath });
await runtime.start(); // spawn + lifecycle.ready handshake
const stream = await runtime.chatStream({
provider: 'openai_compat',
model: 'glm-5.3-flash',
baseUrl: process.env.GATEWAY_BASE_URL!,
apiKey: process.env.GATEWAY_API_KEY!,
messages: [{ role: 'user', content: 'hi' }],
});
for await (const event of stream.events) { /* typed SSEEvent stream */ }
Architecture
Five tiers, strict no-upward-imports rule. Tier N never imports Tier N+1 — adopting any layer means inheriting only the layers below it.
graph BT
T5["<b>Tier 5 · Host Shell</b> (TypeScript, private)<br/>@steerable/agent-shell · agent-shell-web · pack-sdk<br/>Electron main + headless HTTP server · local backend ·<br/>sidecar supervision · product-neutral renderer SPA"]
T4["<b>Tier 4 · UI</b> (TypeScript / React)<br/>@steerable/agent-ui<br/>Hooks: useChatStream · useToolCallStatus · useAgentSession<br/>Components: ChatPanel · MessageList · AgentSelector · ModelSelector ·<br/>OrchestrationPlanCard · ToolCallRenderer · SSEStreamView + 14 cards<br/>Tailwind preset (dark-mode aware)"]
T3S["<b>Tier 3 · Sidecar</b> (portable CPython binary)<br/>steerable-sidecar<br/>JSON-RPC over stdio · 34 methods · graceful shutdown<br/>agent.chat.stream · tool.invoke · agent.session.* · plugin.* · models.list"]
T3R["<b>Tier 3 · Runtime</b> (Python only)<br/>steerable-agent-runtime<br/>CoreLoop · LLMProvider (OpenAI-compat / Responses / Anthropic / Gemini)<br/>ToolRouter · StorageAdapter · TransportAdapter (FastAPI SSE)"]
T2["<b>Tier 2 · Harness</b> (Python — single source of truth)<br/>steerable-agent-harness<br/>Policy · Budget · Retry · Completion · Tracing · Safety<br/><i>thin TS facade @steerable/agent-harness exists for parity tests</i>"]
T1["<b>Tier 1 · Protocol</b> (TypeScript + Python, lock-step versions)<br/>@steerable/agent-protocol · steerable-agent-protocol<br/>SSEEvent · ChatMessage · ToolCall · ToolResult · AgentSession<br/>HarnessTrace · TraceSpan · SidecarRequest/Response/Notification"]
T5 -->|"spawns + supervises"| T3S
T5 -.->|"renders with"| T4
T4 -.->|"shared wire types"| T1
T4 -->|"spawns + JSON-RPC stdio (Electron)"| T3S
T3S -->|"embeds"| T2
T3S -->|"validates against"| T1
T3R -->|"embeds"| T2
T3R -->|"validates against"| T1
T2 -->|"imports types"| T1
What's in the box
| Package | Tier | What you get |
|---|---|---|
@steerable/agent-protocol · steerable-agent-protocol |
1 | SSEEvent envelope, ToolCall / ToolResult, ChatMessage, sidecar JSON-RPC types — codegen from spec/, drift-checked in CI |
@steerable/agent-harness · steerable-agent-harness |
2 | decide_tool_mode, consume_budget, next_retry_delay_ms, is_terminal_result, command-safety patterns |
steerable-agent-runtime · @steerable/agent-runtime (TS, source-only) |
3 | CoreLoop + LLMProvider adapters (OpenAI-compat / Responses / Anthropic / Gemini), ToolRouter + @tool, storage & transport adapters (FastAPI SSE, stdio JSON-RPC); the TS package owns the sidecar process lifecycle for pure-TypeScript hosts |
steerable-sidecar · steerable-egress-proxy |
3 | Portable CPython binary — boots in <1s, macOS notarised, Windows signed — plus the bundled per-host CONNECT allow-list egress proxy |
@steerable/agent-ui |
4 | ChatPanel, MessageList, AgentSelector, ModelSelector, OrchestrationPlanCard, ToolCallRenderer, SSEStreamView + 14-card /cards subpath + hooks + Tailwind preset |
@steerable/agent-shell · agent-shell-web · agent-shell-tauri · pack-sdk |
5 | Tauri + headless host shell, shared Node HostRuntime, sidecar supervision, product-neutral renderer — published to npm (dist / source / pure-types respectively) |
@steerable/agent-cli |
5 | Product-neutral command line and terminal session. npm install -g @steerable/agent-cli, then steerable-cli. It shares the host database with the desktop app. |
How it compares
Steerable isn't the only way to ship an agent. The short, honest version against the frameworks you're probably also evaluating:
| Dimension | Steerable | OpenAI Codex | DeepSeek Harness | LangGraph | OpenAI Agents SDK | Claude Code / Agent SDK |
|---|---|---|---|---|---|---|
| Form factor | Layered library — the same loop in a desktop sidecar and a server | Product family: CLI, IDE, desktop, cloud — Rust core | Plugin-based harness (TS) on Cordis | Orchestration library — you write the graph | Lightweight framework over the Responses API | One closed-source bundle behind both the CLI and the Agent SDK |
| Loop / events | CoreLoop + structured LoopEvent taxonomy; mid-turn agent.chat.steer |
Session-owned turn loop; interrupt/abort; 12-event hooks | Inbox-driven ReactLoop; steer / inject / followup | Interrupts at node boundaries | Handoffs + guardrails; no mid-run steer | Mid-turn fold queue; hooks can veto continuation |
| Sandbox | Seatbelt + bwrap/Landlock, fail-closed; command classifier; per-host egress proxy | Approvals + ExecPolicy + Seatbelt/Landlock + Guardian | sandbox.confine, fail-closed |
None built-in | Guardrails; no sandbox | Permission modes; Seatbelt/bwrap opt-in, fail-open |
| Model quality | Recovers malformed tool calls; completion veto; grounding; token calibration | Assumes structured tool_calls |
Assumes structured tool_calls |
Substrate — you own the loop | Built for frontier models | Built for frontier models |
| Maturity | 0.6.x; used in production deployments |
Massive real-world usage | Pre-release (0.1.x); internal use |
Widely adopted in production | Production, OpenAI-tied | Production; Anthropic models via first-party, Bedrock, Vertex, Foundry, Gateway |
Where Steerable genuinely differs, where it lags, and how to choose: Full comparison.
Who's using it
Tsinghua University