Multi-Agent AI Coding Assistant. TypeScript Monorepo. ECHO-Protocol Citizen.
Two products ship from this monorepo. Savant-Code is the full-featured AI coding agent for your terminal — multi-agent orchestration, custom skills, MCP tool discovery, progressive skill loading, custom slash commands, stream-JSON output for CI (now with real agent output via SavantClient integration in v0.2), and the @savant-code/sdk for embedding agents in your own apps. Savant-Free is the free, ad-supported variant — no subscription, no API key, same agent runtime with paid features stripped at compile time via SAVANT_FREE_MODE=true.
Savant-Code is a TypeScript monorepo that builds, ships, and maintains two AI coding-agent products from one workspace:
- Savant-Code (npm:
savant-code) — the paid CLI + the public@savant-code/sdk. Multi-agent orchestration, custom skills, MCP tool discovery, OAuth + API-key auth, mode switching (FREE/MAX/PLAN), usage metering. - Savant-Free (npm:
savant-free) — the free, ad-supported CLI. Same agent runtime, same SDK, but built withSAVANT_FREE_MODE=trueso the bundler strips paid-only slash commands, credits UI, and mode switching. Result: a single binary that "just works" — no subscription, no API key, no config.
Both products are built from the same cli/ source — only the build flag differs. The SDK, the agent runtime, the multi-agent orchestration engine, the tool layer, and the LLM provider shims are shared. That's why two products can ship from one monorepo without duplicating thousands of lines.
The whole project ships under ECHO Protocol v0.1.3 — the same 15-law agent discipline that governs savant-trading and savant-bot. Every change goes through the RED → GREEN → AUDIT → SELF-CORRECT → COMPLETE Perfection Loop FSM, with a hard 10-iteration cap and a 10% Levenshtein change-cap per pass.
| Layer | Tech | Version |
|---|---|---|
| Runtime | Bun | 1.3.14 (engines >=1.3.11) |
| Language | TypeScript | 5.5.4 (strict: true, noImplicitReturns: true) |
| TUI | OpenTUI + React 19 | @opentui/core 0.2.2, react ^19.0.0 |
| State | Zustand + Immer | zustand ^5.0.8, immer ^10.1.3 |
| Validation | Zod | ^4.2.1 |
| LLM SDK | Vercel AI SDK | ai ^5.0.52 + @ai-sdk/anthropic 2.0.50 |
| MCP | Model Context Protocol | @modelcontextprotocol/sdk ^1.18.2 |
| Code parsing | tree-sitter (WASM) | @vscode/tree-sitter-wasm 0.1.4 |
| HTTP / WS | ws, node-fetch, custom SDK client | ws ^8.18.0 |
| Package manager | Bun workspaces (hoisted) | bunfig.toml [install] linker = "hoisted" |
- Multi-agent orchestration — specialized agents coordinate via a hand-off protocol: a File Picker scans the repo, a Planner sequences edits, an Editor makes precise diffs, and a Reviewer validates them.
/initcommand — scaffolds.agents/types/{agent-definition,tools,util-types}.tsand a starterknowledge.md. The TypeScript generators give programmatic control over hand-offs, tool selection, and prompt construction.- Slash commands —
/new,/history,/bash,/feedback,/theme:toggle,/login,/logout,/exit, plus agent-specific commands. Seecli/src/data/slash-commands.tsfor the canonical registry. @filenameand@AgentNamementions — file and agent mentions with inline autocomplete.- Bash mode —
!commandor/bashto run shell commands inline (with confirmation). - OAuth + API-key auth — login flows for ChatGPT Plus/Pro (OAuth), Savant-Code API keys, and guest mode (savant-free).
- Mode switching —
FREE/MAX/PLANmodes, togglable at runtime via UI; onlyFREEin savant-free builds (compile-time flag). - Streaming & cancellation — token-by-token SSE streaming with mid-stream cancellation, retry-with-backoff, and subagent streaming for parallel work.
- Knowledge files — project-level
knowledge.mdplus per-user home-dir knowledge, auto-loaded into agent context. - Skills — OpenClaw-format
SKILL.mdfiles discovered at startup, schemas sent to the LLM, available as native tools. - MCP tools — Model Context Protocol servers discovered at startup, schemas published to the LLM API.
- Local agent registry — load custom
.agents/agents from any project directory. - Theming — light/dark toggle (
/theme:toggle), per-agent color palettes.
SavantClientclass — single entry point for running agents from any Node.js / Bun / browser app.- Streaming events —
handleEventcallback receivesRunStateupdates, tool calls, file diffs, and final output. - Custom agents — pass
agentDefinitions: AgentDefinition[]to override defaults. - Custom tools — pass
customToolDefinitionsto extend the tool registry. - Cancellation —
AbortSignalpropagates through subagent streams. - Three module formats —
dist/index.cjs(require),dist/index.mjs(import),dist/index.d.ts(types). - Pure types —
sideEffects: false, tree-shakeable. - Stream-JSON event schema (v0.1) —
StreamJsonEmitter+StreamEventtypes for non-interactive agent runs. Emitsession.start/message.user/message.assistant(chunked) /message.assistant.done/tool.call/tool.result/error/session.endto anyWritablestream.
- LLM-agnostic — calls any provider registered with
@savant-code/llm-providers(OpenAI-compatible chat, Anthropic, etc.). - Multi-step loop — model decides tool → tool executes → result fed back → repeat until
end_turnor budget exhausted. - Tool registry — built-in (
read_files,write_file,run_terminal_command,code_search,web_search,spawn_agents_inline, …) + custom + MCP. - Cost aggregation — per-call token counts and USD cost estimates surfaced in
RunState. - Prompt caching — subagent caching for repeated context blocks.
- Propose-tools — model proposes new tools at runtime; user approves; tool registry is mutable.
- tree-sitter-based parser for fast incremental indexing of TS/TSX/JS/JSX.
- Per-file language detection and per-symbol scoping.
- Used by
code_searchtool to keep search latency under 200ms on 100K+ line repos.
- OpenAI-compatible chat shim — drop-in for any provider that speaks the OpenAI Chat Completions API.
- Streaming + non-streaming paths.
- Provider-options metadata — passthrough for vendor-specific features (Anthropic prompt caching, OpenAI reasoning, etc.).
- Shared types —
AgentDefinition,RunState,ToolDefinition,Message,ChatMessage. - Shared tools —
read_files,write_file,code_search, etc., consumed by both CLI and SDK. - Shared utilities —
analytics-dispatcher,rate-limit,partial-json-delta,saxy,messages,string,zoned-time.
- Buffbench — Savant-Code's public benchmark subset (the larger internal benchmark is not open-sourced).
- Multi-repo tasks — coding tasks over multiple open-source repos that simulate real-world edits.
- Scoring — binary pass/fail + rubric scoring per task, aggregated per model.
- 15 Laws active — 4 immutable process (Read 0-EOF, Present Before Act, Verify Before Proceed, Call-Graph Reachability) + 11 extended code laws.
strict: true— TypeScript strict mode is non-negotiable. Zeroany,@ts-ignore,@ts-expect-errorin production code (test fixtures may useas anycasts where necessary — currently ~900 occurrences in test code, zero in production code).- TypeScript coding standard —
max_file_lines: 400,max_function_lines: 60,max_line_length: 100(overrides the ECHO defaults of 300 / 50 / 100). - 6 validation commands —
bun run build:sdk && bun run build:savant-free(build),bun test(test),bun x tsc --noEmit -p tsconfig.json(type_check),bun x eslint . --max-warnings 0(lint),bun x prettier --write .(format), clean (clean). All 6 are wired intoprotocol/protocol.config.yaml. - FID lifecycle — bugs, anti-patterns, security concerns, and improvements tracked via
dev/fids/with auto-archive on closure. - Honest Assessment — every status claim is backed by tool output, never self-reporting.
| Workspace | Package | Purpose |
|---|---|---|
agents/ |
@savant-code/agents |
Public agent definitions shipped with the CLI (base, base2, thinker, editor, basher, context-pruner, librarian, file-picker, browser-use, e2e fixtures) |
cli/ |
@savant-code/cli |
The CLI source — UI, commands, state, hooks, OpenTUI/React components. bin/savant-code (paid) is built from here |
common/ |
@savant-code/common |
Shared types, tool definitions, utilities, analytics, error helpers |
evals/ |
@savant-code/evals |
Buffbench benchmark runner + public eval fixtures |
free-build/ |
@savant-code/savant-free |
The savant-free product layer — cli/build.ts (sets SAVANT_FREE_MODE=true), release packaging, e2e tests, SPEC.md |
packages/agent-runtime/ |
@savant-code/agent-runtime |
The agent loop, tool executor, LLM API integration, subagent streaming |
packages/code-map/ |
@savant-code/code-map |
tree-sitter code indexing, language detection |
packages/llm-providers/ |
@savant-code/llm-providers |
Public LLM provider shims (OpenAI-compatible chat) |
scripts/tmux/ |
@savant-code/tmux-scripts |
tmux helpers for interactive CLI testing |
sdk/ |
@savant-code/sdk |
The public SDK — SavantClient, types, build + verify scripts |
Top-level directories:
savant-code/
├── agents/ # Public agent definitions
├── assets/ # Banner / diagram images
├── cli/ # CLI source (paid + free)
│ ├── src/ # OpenTUI/React UI, commands, state
│ ├── scripts/ # Build + release scripts
│ ├── release/ # Prebuilt npm release (paid) — codebuff shim
│ └── release-staging/ # Prebuilt npm release (staging) — codecane shim
├── common/ # Shared types, tools, utilities
├── docs/ # Project documentation (agents-and-tools, testing)
├── evals/ # Buffbench benchmark + fixtures
├── free-build/ # Savant-Free product layer
├── packages/ # Internal packages (agent-runtime, code-map, llm-providers)
├── protocol/ # ECHO Protocol v0.1.3 scaffold (read protocol/README.md)
├── sdk/ # Public SDK (@savant-code/sdk)
├── scripts/tmux/ # tmux helpers
├── dev/ # Runtime state (FIDs, LEARNINGS, session summaries)
├── package.json # Root workspace config (Bun workspaces, hoisted)
├── tsconfig.json # Root TS config (extends tsconfig.base.json)
├── tsconfig.base.json # Shared compiler options (strict, noImplicitReturns)
├── eslint.config.js # Flat-config ESLint (typescript-eslint, import, unused-imports, prettier)
├── bunfig.toml # Bun config (hoisted linker, test exclude, env preload)
├── AGENTS.md # Repo map + conventions
├── README.md # This file
└── LICENSE # Apache-2.0
- Bun 1.3.14+ — bun.sh (engines field requires
>=1.3.11) - Node.js 18+ — only required if you consume the SDK from a non-Bun app
- No global tools needed; everything runs from the monorepo.
git clone https://github.com/fame0528/savant-code.git
cd savant-code
bun installbun install uses the hoisted linker (bunfig.toml [install] linker = "hoisted") so workspace dependencies are deduplicated at the root.
# Run the CLI in dev mode (paid: savant-code)
bun run dev
# Or run the savant-free variant (compile-time flag set)
bun run dev:savant-freeBoth commands launch the CLI pointed at the repo root as the working directory, with hot reload.
# Build the SDK (publishable to npm)
bun run build:sdk
# Build the savant-free CLI binary
bun run build:savant-free
# Build both in sequence (matches `protocol.config.yaml → commands.build`)
bun run build:sdk && bun run build:savant-freeimport { SavantClient } from '@savant-code/sdk'
const client = new SavantClient({
apiKey: process.env.SAVANT_CODE_API_KEY,
cwd: '/path/to/your/project',
onError: (err) => console.error('Savant-Code error:', err.message),
})
const result = await client.run({
agent: 'base',
prompt: 'Add error handling to all API endpoints',
handleEvent: (event) => console.log('Progress', event),
})npm install -g savant-free
cd ~/my-project
savant-freenpm install -g savant-code
cd ~/my-project
savant-code# Auto-detected when stdout is not a TTY
savant-code "fix the failing tests" | jq -c 'select(.type | IN("message.assistant.done", "session.end"))'
# Or be explicit
savant-code --output-format stream-json "refactor the auth module" > session.ndjson 2> diagnostics.logExit code: 0 on success, 1 on error or cancellation. One JSON object per line, versioned with v: 1. See protocol/CHANGELOG.md for the event schema.
.savant/commands/
review.md → /review
pr.md → /pr
Each .md file has optional YAML frontmatter and a body template:
---
description: Review code changes with focus on a specific area
aliases: [rev]
argument-hint: "<area>"
---
Please review the recent changes with focus on $1. Use $@ for the full context.Placeholders (per opencode convention): $1–$N (positional, shell-quoted), $ARG / $@ (entire args), $SELECTION (editor selection). Built-in commands always win on collision. Strict mode (SAVANT_CODE_STRICT_COMMANDS=1 + ~/.savant/allowlist.json) gates which custom commands are allowed to load.
Root package.json scripts (also see each workspace's own scripts):
| Command | What it does |
|---|---|
bun run start-cli |
bun --cwd cli dev — launch the CLI in dev mode |
bun run dev |
Same as start-cli |
bun run dev:savant-free |
Launch the CLI with SAVANT_FREE_MODE=true |
bun run build:sdk |
Build the SDK for npm publish |
bun run build:savant-free |
Build the savant-free CLI binary |
bun run release:cli |
bun run --cwd=cli release — full CLI release flow |
bun run release:sdk |
bun run --cwd=sdk release — full SDK release flow |
bun run release:savant-free |
bun run --cwd=free-build release — full savant-free release flow |
bun run buffbench |
Run the buffbench eval (bun --cwd evals run-buffbench) |
bun run ci |
build:sdk && build:savant-free — CI gate |
Per-workspace scripts (run from workspace dir, or via bun --cwd <workspace> <script>):
cli/:dev,prebuild:agents,build:binary,release,test,test:tmux-poc,typechecksdk/:build,clean,typecheck,test,test:e2e,test:integration,verify,verify:skip-build,smoke-test:dist,prepare-dist,release,fetch-ripgrep,prepack,devcommon/:typecheck,testagents/:typecheck,test,test:e2efree-build/:release,build:binary,e2e,e2e:version,e2e:startup,e2e:help,e2e:slash-commands,e2e:mode,e2e:ads,e2e:agent,e2e:code-edit,e2e:terminal-command,e2e:knowledge-filepackages/agent-runtime/:typecheck,testpackages/code-map/:typecheck,testpackages/llm-providers/:typecheck,testevals/:typecheck,run-buffbench
| What | Where | Format |
|---|---|---|
| ECHO Protocol runtime config | protocol/protocol.config.yaml |
YAML — language, commands, quality limits, paths |
| ECHO Protocol agent spec | dev/ECHO.md (mirror of protocol/ECHO.md) |
Markdown — 15 Laws, Perfection Loop, anti-patterns |
| TypeScript base config | tsconfig.base.json |
JSON — strict: true, noImplicitReturns: true, ignoreDeprecations: "6.0" |
| ESLint config | eslint.config.js |
Flat config — typescript-eslint, import, unused-imports, prettier |
| Prettier config | .prettierrc |
JSON — tabWidth: 2, singleQuote: true, semi: false |
| Bun config | bunfig.toml |
TOML — linker: "hoisted", linkWorkspacePackages: true, test exclude |
| Path aliases | tsconfig.json → compilerOptions.paths |
@savant-code/sdk, @savant-code/common/*, etc. |
| Workspace list | package.json → workspaces |
Bun workspaces (hoisted) |
| Limit | Value | Source |
|---|---|---|
max_file_lines |
400 | TypeScript override of ECHO default 300 |
max_function_lines |
60 | TypeScript override of ECHO default 50 |
max_line_length |
100 | Matches TS standard |
max_complexity |
10 | ECHO default |
max_params |
4 | ECHO default |
max_nesting_depth |
3 | ECHO default |
max_comment_density |
0.33 | ECHO default |
| Rule | Value | Purpose |
|---|---|---|
| Max changes per pass | 10% of file chars | Prevents runaway rewrites |
| 500-char sample verification | exact match | Catches unintended side effects |
| Convergence detection | <2% delta for 2 passes | Stops when stable |
| Oscillation detection | 3× same issue | Escalates to architecture review |
| Hard stop | 10 iterations | Per Perfection Loop |
All 6 ECHO validation commands (per protocol/protocol.config.yaml → commands) — currently run from the repo root:
# 1. Build (SDK + savant-free binary)
bun run build:sdk && bun run build:savant-free
# 2. Test
bun test
# 3. Type check
bun x tsc --noEmit -p tsconfig.json
# 4. Lint
bun x eslint . --max-warnings 0
# 5. Format
bun x prettier --write .
# 6. Clean
rm -rf dist tsconfig.tsbuildinfo && find . -name node_modules -prune -o -name '*.tsbuildinfo' -print -deleteCurrent state (v0.0.1 base): all 6 wired; type_check and lint require bun install first to populate node_modules. Test count: 197 test files across agents/, cli/, common/, free-build/, packages/agent-runtime, packages/code-map, packages/llm-providers, sdk/.
From AGENTS.md:
- Use
bun installandbun run— nevernpmoryarn. - Prefer dependency injection over module mocking. Tests inject fixtures via constructor params.
- Run interactive CLI tests in tmux —
scripts/tmux/provides helpers. - Do not force-push
main— use a feature branch + PR.
From the ECHO Protocol (protocol/coding-standards/typescript.md):
- No
anyin production code;unknown+ type guards instead. - No
@ts-ignore/@ts-expect-errorwithout justification comment (currently 3 justified uses incli/src/commands/init.tsfor Bun text import attributes). - Named exports only; no default exports.
interfaceovertypefor object shapes;typefor unions/intersections/branded IDs.- One import group per block: std → external → internal → relative.
This project ships with the ECHO Protocol v0.1.3 scaffolded at ./protocol/ and mirrored at ./dev/ECHO.md. Key entry points:
- protocol/README.md — scaffold notes (what was customized for savant-code)
- protocol/ECHO.md — the single source of truth for agent behavior
- protocol/protocol.config.yaml —
language: typescript, all 6 validation commands wired - protocol/coding-standards/typescript.md — TypeScript naming, patterns, quality overrides
- protocol/templates/FID-TEMPLATE.md — Feature Implementation Document template
- protocol/templates/SESSION-SUMMARY.md — Session summary template
- dev/LEARNINGS.md — cross-session lessons learned
- dev/fids/ — active FIDs (Created → Verified lifecycle)
- dev/session-summaries/ — session summaries (YYYY-MM-DD-HHMM format)
Runtime state lives at the repository root in ./dev/ (not under protocol/dev/). .gitignore tracks LEARNINGS.md and the .gitkeep markers; everything else is ephemeral.
Savant-Code is one product in the Savant family:
- Savant — the brand and core project (Rust-native multi-agent swarm, hybrid memory, soul/personality, 25 channel integrations)
- Savant-Trading — autonomous DEX trading on Arbitrum (Rust, 0x API, OpenRouter LLM)
- Savant-Bot — Discord bot interface to Savant (Rust, Poise, SQLite, OpenRouter)
- Savant-Protocol — the ECHO Protocol itself (MIT, language-agnostic agent discipline)
- docs/agents-and-tools.md — how to author agents and tools
- docs/testing.md — testing strategy and conventions
- free-build/SPEC.md — full specification of the savant-free build-time flag
- sdk/README.md — SDK usage and examples
- WINDOWS.md — Windows-specific install and tmux setup
- CONTRIBUTING.md — contribution guide
- SECURITY.md — security policy
Apache-2.0 — see LICENSE for full text.
The ECHO Protocol scaffold (protocol/) is MIT-licensed (see protocol/LICENSE) and inherited from Savant-Protocol.
Savant-Code is the public TypeScript monorepo for the Savant-Code agent framework. Savant-Free is the ad-supported variant. Both share one runtime, one SDK, and one set of engineering laws (ECHO).
Savant • 2026