<p align="center">
<img src="assets/banner.png" alt="SynapsCLI" />
</p>
# SynapsCLI




> **A Rust-native AI agent runtime that boots before your Node binary finishes `require()`-ing.**
One binary, any model. Start with Claude, drop in a free Groq key, point at localhost for private โ same subagents, same TUI, same config. No Node. No Python. No Electron. No excuses.
---
## Why SynapsCLI?
- โก **Sub-100ms cold start.** Single Rust binary, ~70K lines, `cargo build` and you're done.
- ๐ **Any model, any provider.** Claude, Groq, Cerebras, NVIDIA NIM, OpenRouter, or your local Ollama. 17 providers, 55+ models. Set a key, pick a model, go.
- ๐ญ **Named agents, not anonymous forks.** `subagent(agent: "spike", task: "...")` dispatches a crew member with their own soul. Watch them all work in a live panel.
- ๐ก **Event Bus.** External systems push events into a running session โ the agent reacts in real time. `synaps send` from any script, cron job, or monitoring tool.
- ๐ **Reactive Subagents.** Dispatch, poll, steer, collect. Five tools that turn fire-and-forget into collaborative orchestration.
- ๐ค **Autonomous mode that won't eat your wallet.** `watcher` supervises long-running agents with heartbeats, crash recovery, cost limits, and session handoff.
- ๐จ **18 themes.** cyberpunk, tokyo-night, gruvbox, catppuccin, nord, dracula, and friends. Live preview in `/settings`, hot-reload with `/theme`.
- ๐ง **90%+ prompt cache hit rate.** Hand-tuned cache breakpoints beat auto-cache (tested: 90% vs 53%). Built for multi-hour sessions.
- โ๏ธ **Mid-stream steering.** Type while the model is generating to redirect in real time.
- ๐ฑ๏ธ **Mouse text selection.** Left-click drag to select, right-click to copy/paste. Works in the TUI.
- ๐ **MCP + plugins + skills.** Model Context Protocol servers spawn lazily. Skills load from markdown. Plugins ship as marketplaces.
- ๐ **Plugin agent resolution.** `subagent(agent: "dev-tools:sage")` โ dispatch agents from installed plugins via `plugin:agent` syntax.
---
## Quick Start
```bash
cargo install synaps-cli
synaps login # OAuth (Claude Pro/Max/Team)
synaps # Launch TUI
```
Or build from source:
```bash
git clone https://github.com/HaseebKhalid1507/SynapsCLI.git
cd SynapsCLI
cargo build --release
./target/release/synaps
```
Or use an API key instead of OAuth:
```bash
export ANTHROPIC_API_KEY="sk-ant-..."
synaps
```
### Other Models
No Claude key? No problem. SynapsCLI works with any OpenAI-compatible provider.
```bash
# Set a free provider key (Groq, Cerebras, NVIDIA โ no credit card)
export GROQ_API_KEY="gsk_..."
synaps
/model groq/llama-3.3-70b-versatile
```
Or configure in `~/.synaps-cli/config`:
```
provider.groq = gsk_...
provider.cerebras = csk-...
provider.nvidia = nvapi-...
provider.local.url = http://localhost:11434/v1
model = groq/llama-3.3-70b-versatile
```
17 providers supported. `/ping` to health-check them all. Manage keys in `/settings โ Providers`.
| Groq | 30 RPM, 14.4K req/day | Llama 3.3 70B, Llama 4 Scout |
| Cerebras | 30 RPM, 1M tokens/day | Qwen3 235B (S+ tier) |
| NVIDIA NIM | ~40 RPM | Qwen3 Coder 480B, Devstral 2, Mistral Large 675B |
| Google AI Studio | 60 RPM | Gemini 2.5 Flash |
| Local (Ollama/vLLM) | Unlimited | Any local model |
Full list: `synaps` โ `/settings` โ Providers.
`/help` for commands. `/theme` to browse the candy store. `/compact` when context gets long. `/status` to check usage. `/saveas <name>` to alias a session. `/chain name <name>` to bookmark a compaction lineage.
```bash
synaps send "alert" --source monitoring # inject events from anywhere
```
---
## Usage
One binary, every mode as a subcommand.
### Default โ Interactive TUI
```bash
synaps # launch TUI
synaps --continue # resume last session
synaps --continue my-project # resume by name (session alias or chain bookmark)
synaps --system prompt.md # custom system prompt
synaps --no-extensions # disable extension system
```
Name a session with `/saveas my-project`, or bookmark a compaction lineage with `/chain name my-project` โ then `synaps --continue my-project` picks up where you left off. Resolution tries chain name โ session name โ partial ID.
Streaming, markdown, syntax highlighting, and a live panel showing every subagent you dispatched.
```
โญ โ 4 agents โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ โ spike done 12.3s โ
โ โ น chrollo โ read (tool #5) 8.1s โ
โ โ shady done 9.7s โ
โ โ น zero thinking... 4.2s โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
```
### Usage Status
```bash
synaps status # check account usage + reset times
```
Or use `/status` inside the TUI.
### One-Shot
```bash
synaps run "explain this error" # single prompt
synaps run "fix it" --agent spike # with named agent
```
### Headless Chat
```bash
### Server Mode
```bash
synaps server --port 3145
synaps client ws://localhost:3145
```
### Autonomous Agents
```bash
synaps watcher init scout # scaffold an agent
synaps watcher deploy scout # run supervised
synaps watcher start # start supervisor
synaps watcher status # monitor the fleet
synaps watcher logs scout -f # tail the brain
```
Minimal agent config (`~/.synaps-cli/watcher/scout/config.toml`):
```toml
[agent]
name = "scout"
model = "claude-sonnet-4-20250514"
[trigger]
paths = ["./src"]
patterns = ["*.rs"]
[limits]
max_session_cost_usd = 0.50
max_daily_cost_usd = 10.0
```
Full schema in [AGENTS.md](AGENTS.md). Agents checkpoint state on exit and resume where they left off.
### Event Bus
```bash
# Any script, cron job, or service can push events into a running session
synaps send "Jellyfin is DOWN" --source uptime-kuma --severity high
synaps send "deploy complete" --source ci --severity low --content-type event
synaps send "check PR #42" --source github --channel reviews
```
Events appear as styled cards in the TUI and auto-trigger the agent to respond. During streaming, events buffer and flush after the current response completes.
---
## Built-in Tools
| `bash` | Shell execution (30s default, 300s max) |
| `read` / `write` / `edit` | Atomic, UTF-8 validated file ops |
| `grep` / `find` / `ls` | Regex, glob, directory ops |
| `subagent` | Dispatch a named crew member |
| `subagent_start` | Dispatch reactive subagent (returns immediately) |
| `subagent_status` | Poll running subagent progress |
| `subagent_steer` | Inject guidance into running subagent |
| `subagent_collect` | Check if subagent is done, get result |
| `shell_start/send/end` | Interactive PTY sessions |
| `connect_mcp_server` | Load tools from MCP servers |
| `load_skill` | Load behavioral guidelines from markdown |
See [AGENTS.md](AGENTS.md) for parameters and behavior.
---
## Extensions
SynapsCLI has a first-class extension system. Extensions are external processes that hook into the agent loop via JSON-RPC 2.0 over stdio.
- **5 hooks:** `before_tool_call`, `after_tool_call`, `before_message`, `on_session_start`, `on_session_end`
- **Tool-specific filtering:** narrow a hook to a single tool by adding `"tool"` to the registration, e.g. `{ "hook": "before_tool_call", "tool": "bash" }` fires only for bash calls
- **Context injection:** Extensions inject context into the system prompt via `HookResult::Inject`
- **Permission-gated:** 6 permissions control what extensions can access
- **Drop-in plugins:** Clone into `~/.synaps-cli/plugins/<name>/` and restart
### Available Extensions
- [**Synaps Deck**](https://github.com/HaseebKhalid1507/synaps-deck) โ Live agent dashboard at localhost:3456
- [**Axel**](https://github.com/HaseebKhalid1507/axel) โ Portable agent intelligence (.r8 brain files)
See [docs/extensions/](docs/extensions/) for the full guide and protocol spec.
---
## Context Compaction
Long sessions eat context. `/compact` fixes that.
```
/compact # summarize & replace history
/compact focus on the auth module # with custom focus
```
The LLM produces a structured checkpoint (goals, progress, decisions, file ops, next steps) and the entire message history is replaced with that summary. Iterative โ `/compact` again merges new work into the existing summary. Inspired by [pi coding agent](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent).
- Chain sessions: `/compact` creates a new linked session, preserving the original
- Configurable model: compaction defaults to Sonnet (saves tokens)
- System prompt carried through compaction chains
---
## Themes
`minimal` ยท `cyberpunk` ยท `tokyo-night` ยท `gruvbox` ยท `catppuccin` ยท `nord` ยท `dracula` ยท `solarized-dark` ยท `solarized-light` ยท `monokai` ยท `one-dark` ยท `rose-pine` ยท `kanagawa` ยท `ayu-dark` ยท `ayu-light` ยท `github-dark` ยท `github-light` ยท `terminal` ยท `default`
Preview live in `/settings` (scroll to preview, Enter to confirm, Esc to revert). Or hot-swap instantly with `/theme <name>`.
---
## Configuration
Config lives at `~/.synaps-cli/config`. Simple `key = value` format.
```
# Model
model = claude-opus-4-7
thinking = high
context_window = 200k
compaction_model = claude-sonnet-4-6
# Provider API keys
provider.groq = gsk_...
provider.cerebras = csk-...
provider.nvidia = nvapi-...
provider.local.url = http://localhost:11434/v1
# Appearance
theme = cyberpunk
# Custom keybinds
keybind.F5 = /compact
keybind.A-h = /help
keybind.A-k = /keybinds
keybind.F6 = disabled
```
Provider keys can also be set via environment variables (`GROQ_API_KEY`, `CEREBRAS_API_KEY`, etc.) or through `/settings โ Providers` in the TUI.
---
## Keybinds
Plugins can register keyboard shortcuts, and users can override or add their own.
### User keybinds (in config)
```
keybind.F5 = /compact # F5 runs /compact
keybind.A-s = /scholar # Alt+S runs /scholar
keybind.A-k = /keybinds # Alt+K shows all keybinds
keybind.F6 = disabled # Disable a plugin keybind
```
### Plugin keybinds (in plugin.json)
Plugins declare keybinds in their manifest:
```json
{
"name": "my-plugin",
"keybinds": [
{
"key": "F5",
"action": "slash_command",
"command": "compact",
"description": "Quick compact"
},
{
"key": "A-r",
"action": "load_skill",
"skill": "code-review",
"description": "Load code review"
}
]
}
```
### Key notation
| `C-x` | Ctrl+X |
| `A-x` | Alt+X |
| `S-x` | Shift+X |
| `C-A-x` | Ctrl+Alt+X |
| `F1`โ`F12` | Function keys |
| `Space`, `Tab`, `Enter`, `Esc` | Special keys |
### Priority
Core keybinds (Ctrl+C, Esc, Enter, etc.) are never overridable. User config overrides plugins. `/keybinds` to see what's registered.
---
<details>
<summary><b>๐งฌ Architecture (for the curious)</b></summary>
One binary. Subcommands dispatched from `main.rs`. Two API paths: Anthropic (native) and OpenAI-compatible (17 providers).
```
src/
โโโ main.rs # unified CLI entry point + subcommand dispatch
โโโ cmd/ # subcommand handlers (run, chat, server, client, agent, login, watcher)
โโโ chatui/ # TUI: event loop, rendering, markdown, themes, settings, plugins
โ โโโ settings/ # /settings modal โ model picker, provider keys, themes
โโโ runtime/ # THE BRAIN
โ โโโ api.rs # Anthropic API + provider router (try_route)
โ โโโ stream.rs # tool dispatch loop (provider-agnostic)
โ โโโ openai/ # OpenAI-compatible provider engine
โ โโโ registry.rs # 17 providers, 55+ models
โ โโโ stream.rs # SSE streaming + BytesMut/memchr parsing
โ โโโ translate.rs # AnthropicโOpenAI format bridge
โ โโโ wire.rs # StreamDecoder + tool call accumulation
โ โโโ ping.rs # /ping health check
โโโ core/ # config, session, chain, auth, models, logging
โโโ events/ # event bus: types, priority queue, inotify watcher
โโโ tools/ # 15 built-in tools (bash, read, write, edit, subagent*, shell*, etc.)
โโโ mcp/ # Model Context Protocol client, lazy server spawning
โโโ watcher/ # supervisor daemon, IPC, heartbeats
โโโ skills/ # markdown-driven behavioral guidelines + plugin marketplace
```
| *(none)* | Interactive TUI with streaming + subagent panel |
| `run` | One-shot prompt, prints to stdout |
| `chat` | Headless streaming chat for scripting |
| `server` / `client` | WebSocket transport |
| `agent` | Worker runtime spawned by watcher |
| `watcher` | Supervisor daemon for autonomous agents |
| `login` | OAuth flow |
| `send` | Push events into a running session |
| `status` | Check account usage |
**Provider routing:** Model IDs with a `/` (e.g. `groq/llama-3.3-70b`) route through `runtime/openai/`. Everything else goes to Anthropic. Both paths emit the same `StreamEvent` type โ the TUI and tool loop are provider-blind.
Config lives at `~/.synaps-cli/` โ config, sessions, agents, plugins, skills, chains, mcp.json. Project-local `.synaps-cli/` overrides global. Provider API keys stored with `0600` permissions.
</details>
---
## License
MIT. See [LICENSE](LICENSE).
## Author
Built by [Haseeb Khalid](https://github.com/HaseebKhalid1507) because every other CLI agent was a 400MB Electron app pretending to be a terminal tool.