Introduction
Zenspace is your personal AI agentic workspace — a self-learning knowledge system that builds your wiki, remembers across sessions, and evolves with your decisions.
Most AI tools are chat boxes. You talk, they respond, and tomorrow it's gone. Zenspace takes a different path: your notes grow into a wiki. Your sessions build memory. Your patterns become wisdom.
The 10 Things That Make Zenspace Different
1. 📝 Notes That Build Themselves
Write normally — agents extract entities, auto-generate wiki pages, detect contradictions, and weave everything into a knowledge graph. Your notes become a living wiki, not a pile of files.
2. 🧠 Three Brains, One System
Short-term memory ("what just happened?") → Mid-term knowledge ("what do I know?") → Long-term wisdom ("what have I learned?"). Session context flows naturally upward. No cold starts.
3. 📈 It Learns From You
Daily reflection, weekly synthesis, Bayesian belief updates. The system spots recurring patterns, surfaces blind spots, and adapts to your workflow. Every session makes the next one sharper.
4. 🔄 Information → Knowledge → Wisdom
5-stage pipeline: Capture → Tidy → Organize → Distill → Fuse. From raw notes to polished wiki to deep wisdom. Data in, decisions out.
5. 🏛️ 13 Agents, Each an Expert
A Greek pantheon of AI specialists: Sisyphus orchestrates, Prometheus plans, Momus gatekeeps quality, Hephaestus executes, Hermes validates, Zeus judges. Each with the right model for the job.
6. 🎯 Smart Model Routing — No Manual Picking
Private data → local Ollama. Complex reasoning → Anthropic. Cost-sensitive → DeepSeek. Per-task fallback chains so nothing fails silently. One config, zero guesswork.
7. 💡 Built-in Decision Engine
Log decisions, compute expected value, set stop-loss lines, detect anti-patterns. The system doesn't just remember what you decided — it helps you decide better next time.
8. 📚 Seed Wisdom — 12 Mental Models + 21 Anti-Patterns
Pre-loaded thinking frameworks: Map ≠ Territory, Circle of Competence, Second-Order Thinking, Hanlon's Razor. Plus behavioral anti-pattern detection. Thinking tools, not just storage.
9. 🔗 Obsidian + OKF Dual Format
All notes are Obsidian-compatible Markdown with [[wikilinks]] and YAML frontmatter — open ~/.zen/vault/ directly in Obsidian, edit in both directions, no import/export. Under the hood, wiki pages follow OKF v0.1 (Open Knowledge Format): typed frontmatter (type: concept|reference|tool|...), bundle-relative links, and structured index files. Two formats, one knowledge base.
10. 🏠 Your Data, Your Rules
Local-first by default. macOS Keychain for secrets. Sensitive data never touches the cloud unless you explicitly allow it. Zero vendor lock-in.
How It Works (The 5-Stage Pipeline)
RAW NOTES ──► TIDY ──► ORGANIZE ──► DISTILL ──► FUSE
│
Entity Extraction
Wiki Generation
Contradiction Detection
│
WISDOM
(MEMORY.md + beliefs)
- Capture — Notes, RSS feeds, raw files all go into inbox
- Tidy — Clean, chunk, normalize into structured Markdown
- Organize — Embed, index, classify — make everything searchable
- Distill — Extract entities, compile wiki pages, detect contradictions
- Fuse — Synthesize wisdom, update beliefs, promote to long-term memory
Who Is It For?
- Knowledge workers who want their notes to actively work for them
- Thinkers who value structured decision-making and mental models
- Privacy-conscious users who want AI without surrendering data
- Power users who want to customize model routing across providers
Next: Installation
Installation
Prerequisites
macOS
- macOS (Apple Silicon or Intel) — primary supported platform
- Rust toolchain 1.80+ (only for building from source)
- No additional dependencies —
sandbox-execis built-in
Linux
- Rust toolchain 1.80+ (only for building from source)
- bubblewrap (
bwrap) — required for sandbox isolation
# Ubuntu/Debian
sudo apt install bubblewrap
# Fedora
sudo dnf install bubblewrap
# Arch
sudo pacman -S bubblewrap
Why bubblewrap? Zen uses Linux namespaces for sandbox isolation. Bubblewrap provides unprivileged sandboxing without requiring root access.
Homebrew (macOS & Linux, Recommended)
brew install savechina/tap/zenspace
Note: On Linux, Homebrew (Linuxbrew) also handles bubblewrap dependency automatically.
From Source
git clone https://github.com/savechina/zenspace.git
cd zenspace
bin/build
./target/release/zen --help
Binary Download
Download pre-built binaries from GitHub Releases:
macOS:
zen-{version}-aarch64-apple-darwin.tar.gz(Apple Silicon)zen-{version}-x86_64-apple-darwin.tar.gz(Intel)
Linux:
zen-{version}-x86_64-unknown-linux-gnu.tar.gz(x86_64)zen-{version}-aarch64-unknown-linux-gnu.tar.gz(ARM64)
Linux Note: After downloading, install bubblewrap:
sudo apt install bubblewrap # Ubuntu/Debian
Post-Installation
Verify the installation:
zen version
Initialize your workspace:
zen workspace init
This creates the ~/.zen/ directory structure and default configuration.
Next: Quick Start
Quick Start
1. Initialize a Workspace
zen workspace init
This sets up ~/.zen/ with the default directory structure and embedded configuration.
2. Create Your First Note
zen note create "Meeting Notes: Q3 Planning" --tag project
Notes are stored as Markdown in ~/.zen/vault/inbox/ with YAML frontmatter.
3. Search Your Knowledge Base
zen search run "Q3 planning"
Zen searches across 5 tiers: ripgrep → FTS5 → vector embeddings → entity graph → LLM.
4. View Your Configuration
zen config show
Shows the merged configuration from all 5 layers.
5. Explore More Commands
zen --help
Or dive into the CLI Commands reference.
Next Steps
- Configure LLM providers to unlock AI features
- Set up model routing for agent tasks
- Explore the CLI reference for all available commands
CLI Commands Reference
Zen provides 29 CLI commands for knowledge management, agent orchestration, and system administration.
General
| Command | Description |
|---|---|
zen | Launch TUI (interactive interface) |
zen version | Show version information |
zen --help | Show full help with all commands |
Workspace & Configuration
| Command | Description |
|---|---|
zen workspace init | Initialize .zen/ workspace structure |
zen config show | Show effective configuration (all layers merged) |
zen provider list | List available LLM providers |
zen provider test <name> | Test a provider connection |
zen auth list | List stored credentials |
Knowledge Management
| Command | Description |
|---|---|
zen note create <title> | Create a new note |
zen search run <query> | Search knowledge base (5 tiers) |
zen similar find <id> | Find similar notes by vector similarity |
zen notion query <entity> | Query entity graph |
zen wiki list | List wiki pages |
zen wiki show <id> | Show a wiki page |
zen wiki reindex | Reindex wiki pages |
zen wiki lint | Lint wiki (orphan pages, broken wikilinks) |
zen wiki distill | Distill wiki content |
zen ingest <path> | Ingest files or RSS feeds |
zen brief generate | Generate a brief from recent notes |
Agentic Sessions
| Command | Description |
|---|---|
zen session start | Start an agentic session |
zen session list | List active sessions |
zen session stop <id> | Stop a session |
zen chat | Interactive LLM chat |
zen research <topic> | Run research task |
zen agent list | List available agents |
zen dispatch run <task> | Dispatch a task to agents |
zen dispatch status <id> | Check task status |
zen dispatch list | List dispatched tasks |
zen dispatch cancel <id> | Cancel a task |
System
| Command | Description |
|---|---|
zen serve | Start HTTP gateway daemon |
zen logs <service> | View structured logs |
zen clean <target> | Clean up (trash, cache, all) |
zen starter <template> | Generate project scaffold from template |
zen wps <action> | Work process utilities |
Habit & Goal Tracking
| Command | Description |
|---|---|
zen habit log | Log a habit entry |
zen habit list | List habits |
zen goal create | Create a goal |
zen goal list | List goals |
zen goal status <id> | Check goal progress |
Plugin Management
| Command | Description |
|---|---|
zen plugin list | List installed plugins |
zen plugin install <id> | Install a plugin |
zen plugin remove <id> | Remove a plugin |
Quick Reference
# Initialize
zen workspace init
zen config show
# Daily workflow
zen note create "Daily Log" --tag journal
zen search run "yesterday's decisions"
zen wiki reindex
zen wiki lint
# Agentic work
zen session start
zen research "Rust async patterns"
zen dispatch run "summarize inbox"
# Maintenance
zen clean cache
zen logs agent
Full reference: zen --help for the most up-to-date list of commands and flags.
Configuration Overview
Zen uses a 5-layer configuration system that merges settings from multiple sources. Higher-priority layers override lower ones, and you only need to specify the values you want to change.
Configuration Layers
| Priority | Layer | File / Source | Typical Use |
|---|---|---|---|
| 1 (highest) | Environment | ZEN_* environment variables | Temporary overrides, CI/CD, secrets |
| 2 | Workspace | .zen/config.toml | Per-project settings |
| 3 | Global User | ~/.zen/config.toml | User-wide preferences |
| 4 (lowest) | Embedded Default | config/config.toml (compiled in) | Shipped defaults |
How Merging Works
Each layer merges cleanly into the previous one. A higher layer only overrides keys it explicitly sets — so you can override just default_model without copying the entire config.
# Example: ~/.zen/config.toml — just override what you need
default_provider = "deepseek"
default_model = "deepseek-v4-flash"
# Only the providers you want to customize
[providers.deepseek]
type = "openai-compatible"
base_url = "https://api.deepseek.com"
api_key = { env = "DEEPSEEK_API_KEY" }
default_model = "deepseek-v4-flash"
This minimal config merges with the embedded defaults — all other providers (Ollama, OpenAI, Anthropic, etc.) remain available from the embedded config.
Config Structure
The configuration is organized into these top-level sections:
| Section | Description |
|---|---|
default_provider | Default provider name (references a [providers.*] key) |
default_model | Default model when no task-specific model is set |
[providers.*] | Named provider definitions (connection settings) |
[agents.*] | Agent task routing (provider/model per task) |
[tui] | TUI theme settings |
[features] | Feature flags |
[plugin.*] | Plugin system configuration |
[cron] | Scheduled task configuration |
[history] | Command history settings |
Viewing Effective Configuration
# Show the complete merged configuration
zen config show
# List available providers
zen provider list
# Test a provider connection
zen provider test <provider-name>
The zen config show command displays the fully merged configuration from all 5 layers, so you can always see exactly what's in effect.
Next: Provider Definitions
Provider Definitions
Providers are the connection endpoints to LLM services. Define them once by name in [providers.*] sections, then reference them in agent routing.
Supported Protocol Types
| Type | Auth Required | Description | Examples |
|---|---|---|---|
ollama | No | Local Ollama server | qwen3.6, llama3, mistral (local) |
openai | API key | Native OpenAI API | gpt-4o, gpt-4o-mini |
anthropic | API key | Native Anthropic Messages API | claude-sonnet-4-6, claude-haiku-4-5 |
gemini | API key | Google Gemini API | gemini-2.0-flash |
cohere | API key | Cohere API | command-r |
mistral | API key | Mistral API | mistral-large-latest |
openai-compatible | API key | OpenAI-compatible endpoints | DeepSeek, Groq, Perplexity, Aliyun, xAI |
anthropic-compatible | API key | Anthropic-compatible endpoints | Moonshot, MiniMax |
mock | No | Testing mock (no external calls) | — |
Basic Provider Configuration
# Local Ollama (no API key needed)
[providers.ollama]
type = "ollama"
base_url = "http://127.0.0.1:11434"
default_model = "qwen3.6:35b-mlx"
# OpenAI
[providers.openai]
type = "openai"
base_url = "https://api.openai.com/v1"
api_key = { env = "OPENAI_API_KEY" }
default_model = "gpt-4o-mini"
# Anthropic
[providers.anthropic]
type = "anthropic"
api_key = { env = "ANTHROPIC_API_KEY" }
default_model = "claude-haiku-4-5"
# OpenAI-compatible (DeepSeek)
[providers.deepseek]
type = "openai-compatible"
base_url = "https://api.deepseek.com"
api_key = { env = "DEEPSEEK_API_KEY" }
default_model = "deepseek-v4-flash"
# OpenAI-compatible (Aliyun/Qwen)
[providers.aliyun]
type = "openai-compatible"
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
api_key = { env = "DASHSCOPE_API_KEY" }
default_model = "qwen3.6-plus"
Dual-Protocol Providers
Some providers support both OpenAI-compatible and Anthropic-compatible protocols:
# DeepSeek: OpenAI-compatible (default)
[providers.deepseek]
type = "openai-compatible"
base_url = "https://api.deepseek.com"
api_key = { env = "DEEPSEEK_API_KEY" }
# DeepSeek: Anthropic-compatible (alternative)
[providers.deepseek-anthropic]
type = "anthropic-compatible"
base_url = "https://api.deepseek.com/anthropic"
api_key = { env = "DEEPSEEK_API_KEY" }
# Moonshot: either protocol works
[providers.moonshot]
type = "openai-compatible"
base_url = "https://api.moonshot.cn/v1"
api_key = { env = "MOONSHOT_API_KEY" }
default_model = "kimi-k2.5"
API Key Resolution
API keys are resolved lazily at first use (not during startup), following this order per provider:
api_key.env— named environment variable (e.g.,DEEPSEEK_API_KEY)api_key.keychain— macOS Keychain service name (e.g.,zen-deepseek-api-key)api_key_env— legacy env var field (deprecated){PROVIDER}_API_KEY— auto-derived env var (e.g.,OPENAI_API_KEY)- Ollama/local providers — no auth required
# Using environment variable
api_key = { env = "DEEPSEEK_API_KEY" }
# Using macOS Keychain
api_key = { keychain = "zen-deepseek-api-key" }
# Direct env var name (auto-derived if not specified)
# ^ will try: DEEPSEEK_API_KEY automatically
Keychain Integration
On macOS, Zen integrates with the system Keychain for secure credential storage:
# Store an API key in Keychain
security add-generic-password -a "zen" -s "zen-openai-api-key" -w "sk-..."
# Configure provider to use Keychain
[providers.openai]
type = "openai"
api_key = { keychain = "zen-openai-api-key" }
If Keychain is unavailable (non-macOS, headless environment), Zen falls back to environment variables automatically.
Provider Fields Reference
| Field | Required | Description |
|---|---|---|
type | Yes | Protocol type (see table above) |
base_url | For some types | API endpoint URL (Ollama: http://127.0.0.1:11434) |
api_key | For cloud providers | Secret reference (env var or keychain) |
api_key_env | No | Legacy env var name (deprecated) |
default_model | Recommended | Default model name for this provider |
models | No | Per-model catalog with parameters (see Model Catalog) |
wire_api | No | Wire protocol: "completions" (default) or "responses" |
Next: Model Catalog & Parameters
Model Catalog & Parameters
Each provider can define a model catalog — a map of model names to their API identifiers, generation parameters, and named parameter variants.
Defining Models
When a models map is present under a provider, default_model selects a key in this map:
[providers.openai]
type = "openai"
api_key = { env = "OPENAI_API_KEY" }
default_model = "gpt-4o-mini" # selects from [providers.openai.models]
[providers.openai.models.gpt-4o]
model = "gpt-4o"
options = { temperature = 0.7, max_tokens = 4096 }
[providers.openai.models.gpt-4o-mini]
model = "gpt-4o-mini"
options = { temperature = 0.3, max_tokens = 2048, reasoning_effort = "low" }
When models is absent, default_model is used directly as the API model name (backward compatible):
# Simple configuration — no model catalog
[providers.deepseek]
type = "openai-compatible"
base_url = "https://api.deepseek.com"
api_key = { env = "DEEPSEEK_API_KEY" }
default_model = "deepseek-v4-flash" # used directly as API model name
Model Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
temperature | float (0.0–2.0) | Sampling temperature. Higher = more random | 0.7 |
max_tokens | integer | Maximum tokens in the response | 4096 |
reasoning_effort | string | Reasoning depth: "low", "medium", "high" | "high" |
top_p | float (0.0–1.0) | Nucleus sampling threshold | 0.9 |
Complete Example
[providers.anthropic]
type = "anthropic"
api_key = { env = "ANTHROPIC_API_KEY" }
default_model = "claude-sonnet-4-6"
[providers.anthropic.models.claude-sonnet-4-6]
model = "claude-sonnet-4-6"
options = { temperature = 0.5, max_tokens = 8192 }
[providers.anthropic.models.claude-haiku-4-5]
model = "claude-haiku-4-5"
options = { temperature = 0.3, max_tokens = 4096 }
[providers.ollama]
type = "ollama"
base_url = "http://127.0.0.1:11434"
default_model = "qwen3.6-35b-mlx"
[providers.ollama.models.qwen3.6-35b-mlx]
model = "qwen3.6:35b-mlx"
options = { temperature = 0.6, max_tokens = 4096 }
Named Variants
Named variants allow the same model to be used with different parameters for different agents. This is useful when the same model needs different reasoning depths or creativity levels depending on the task.
[providers.anthropic.models.claude-sonnet-4-6]
model = "claude-sonnet-4-6"
options = { temperature = 0.5, max_tokens = 8192 }
# Variant: creative
[providers.anthropic.models.claude-sonnet-4-6.variants.creative]
temperature = 0.9
# Variant: precise
[providers.anthropic.models.claude-sonnet-4-6.variants.precise]
temperature = 0.1
reasoning_effort = "high"
Agents reference variants via the variant field:
[agents.Prometheus]
provider = "anthropic"
model = "claude-sonnet-4-6"
variant = "precise" # uses temperature=0.1, reasoning_effort="high"
Variant parameters merge into the base model options — they only override the fields specified.
Parameter Resolution Order
When an agent makes a call, parameters are resolved in this order:
- Model-level defaults from the model catalog entry
- Variant overrides (if specified)
- Agent-level overrides (if specified in
[agents.*])
This means an agent can always override temperature or max_tokens at the agent config level, regardless of model defaults.
Next: Agent → Model Routing
Agent → Model Routing
Each agent can be assigned a specific provider and model, with a sequential fallback chain for reliability.
Basic Routing
[agents.Sisyphus]
provider = "anthropic"
model = "claude-sonnet-4-6"
fallbacks = [
{ provider = "openai", model = "gpt-4o" },
{ provider = "deepseek", model = "deepseek-v4-flash" }
]
The router tries providers in order: primary → first fallback → second fallback → ... → Mock (always available).
Agent Routing Fields
| Field | Required | Description |
|---|---|---|
provider | Yes | Primary provider name (must match a [providers.*] key) |
model | No | Model override (falls back to provider's default_model) |
fallbacks | No | Ordered fallback chain if primary fails |
llm_preferences | No | "Any", "LocalOnly", "CloudOnly", or "Provider(name)" |
max_sensitivity | No | Max data sensitivity: "Low", "Medium", "High" |
temperature | No | Override per-agent temperature |
max_tokens | No | Override per-agent max tokens |
variant | No | Select a named variant from the model catalog |
retry_policy | No | Retry settings for transient errors |
LLM Preferences
| Preference | Behavior |
|---|---|
Any | Standard routing (primary → fallbacks) |
LocalOnly | Force Ollama if available, error if unreachable |
CloudOnly | Force default_provider if it's a cloud provider |
Provider(name) | Use the named provider directly |
Privacy-Sensitive Routing
When max_sensitivity is set to "Medium" or "High", Zen enforces local-only routing for sensitive data:
- Private/Confidential data is never sent to cloud providers
- If no local LLM is available, the agent returns an error instead of falling back to cloud
# Private data — local-only enforced
[agents.Metis]
provider = "deepseek"
model = "deepseek-v4-flash"
fallbacks = [{ provider = "ollama", model = "qwen3.6:35b-mlx" }]
max_sensitivity = "Medium"
# Public data — can use any provider
[agents.Explore]
provider = "anthropic"
model = "claude-haiku-4-5"
fallbacks = [{ provider = "openai", model = "gpt-4o-mini" }]
llm_preferences = "CloudOnly"
Fallback Chain
Each fallback step can specify:
| Field | Description |
|---|---|
provider | Provider name for this fallback step |
model | Override model (optional, uses provider's default if omitted) |
timeout_secs | Timeout for this step (optional) |
variant | Variant name for this step's model (optional) |
[agents.dispatch]
provider = "anthropic"
model = "claude-sonnet-4-6"
fallbacks = [
{ provider = "openai", model = "gpt-4o", timeout_secs = 30 },
{ provider = "ollama", model = "qwen3.6:35b-mlx" }
]
retry_policy = { max_retries = 3, timeout_secs = 30 }
Complete Agent Configuration Examples
Orchestrator Tier (requires capable models)
[agents.Sisyphus]
provider = "anthropic"
model = "claude-sonnet-4-6"
fallbacks = [
{ provider = "openai", model = "gpt-4o" },
{ provider = "deepseek", model = "deepseek-v4-flash" }
]
llm_preferences = "Any"
max_sensitivity = "High"
Knowledge Pipeline (local-first)
[agents.notion_extraction]
provider = "ollama"
model = "qwen3.6:35b-mlx"
fallbacks = [
{ provider = "deepseek", model = "deepseek-v4-flash" },
{ provider = "openai", model = "gpt-4o-mini" }
]
Fast Explorer (cost-optimized)
[agents.Explore]
provider = "anthropic"
model = "claude-haiku-4-5"
fallbacks = [{ provider = "openai", model = "gpt-4o-mini" }]
llm_preferences = "CloudOnly"
max_sensitivity = "Low"
Privacy-Sensitive Analyst
[agents.Hermes]
provider = "deepseek"
model = "deepseek-v4-flash"
fallbacks = [
{ provider = "openai", model = "gpt-4o-mini" },
{ provider = "ollama", model = "qwen3.6:35b-mlx" }
]
llm_preferences = "Any"
max_sensitivity = "High"
Next: Environment Variable Overrides
Environment Variable Overrides
Environment variables provide the highest-priority configuration layer. They're useful for temporary overrides, CI/CD environments, and sensitive values.
Global Overrides
# Default provider and model
export ZEN_DEFAULT_PROVIDER="deepseek"
export ZEN_DEFAULT_MODEL="deepseek-v4-flash"
Per-Agent Overrides
Override specific agent routing without modifying any config files:
# Force notion_extraction to use local Ollama
export ZEN_AGENT_NOTION_EXTRACTION_PROVIDER="ollama"
# Override synthesis agent's model
export ZEN_AGENT_SYNTHESIS_MODEL="claude-sonnet-4-6"
# Override dispatch agent
export ZEN_AGENT_DISPATCH_PROVIDER="anthropic"
export ZEN_AGENT_DISPATCH_MODEL="claude-sonnet-4-6"
Supported agent env var targets:
| Env Var | Effect |
|---|---|
ZEN_AGENT_NOTION_EXTRACTION_PROVIDER | Override notion_extraction provider |
ZEN_AGENT_NOTION_EXTRACTION_MODEL | Override notion_extraction model |
ZEN_AGENT_CONTRADICTION_DETECTION_PROVIDER | Override contradiction detection provider |
ZEN_AGENT_CONTRADICTION_DETECTION_MODEL | Override contradiction detection model |
ZEN_AGENT_SYNTHESIS_PROVIDER | Override synthesis provider |
ZEN_AGENT_SYNTHESIS_MODEL | Override synthesis model |
ZEN_AGENT_DISPATCH_PROVIDER | Override dispatch provider |
ZEN_AGENT_DISPATCH_MODEL | Override dispatch model |
Cron Overrides
export ZEN_CRON_CONSOLIDATION_TIME="03:00"
export ZEN_CRON_TIMEZONE="America/New_York"
export ZEN_CRON_SUBCONSCIOUS_INTERVAL_MINUTES=10
Plugin Overrides
export ZEN_PLUGIN_BASE_PATH="/custom/plugin/path"
export ZEN_PLUGIN_WASM_CACHE_PATH="/custom/cache/path"
export ZEN_LEARNING_AUTO_RESEARCH="true"
export ZEN_LEARNING_INTERVAL="weekly"
export ZEN_FINANCE_BASE_CURRENCY="USD"
API Key Environment Variables
# Set API keys for providers
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
export DEEPSEEK_API_KEY="sk-..."
export DASHSCOPE_API_KEY="sk-..."
export GEMINI_API_KEY="..."
export COHERE_API_KEY="..."
export MISTRAL_API_KEY="..."
export GROQ_API_KEY="gsk_..."
export MOONSHOT_API_KEY="..."
export XAI_API_KEY="..."
export PERPLEXITY_API_KEY="..."
Priority Rules
- Explicit
api_key.envin provider config takes precedence over auto-derived names - Environment variables override both global and workspace config files
- Per-agent env vars override the agent's provider/model settings
- Set env vars in
.envfile (loaded automatically) or export them in your shell profile
Next: Configuration Examples
Configuration Examples
1. Local-Only Setup (Ollama Only)
For complete offline operation with no cloud dependencies:
default_provider = "ollama"
default_model = "qwen3.6:35b-mlx"
[providers.ollama]
type = "ollama"
base_url = "http://127.0.0.1:11434"
default_model = "qwen3.6:35b-mlx"
# No other providers needed
Best for: Privacy-critical environments, air-gapped setups, offline use.
2. Cloud-First with Local Fallback
Use cloud for quality, fall back to local when offline:
default_provider = "anthropic"
default_model = "claude-haiku-4-5"
[providers.anthropic]
type = "anthropic"
api_key = { env = "ANTHROPIC_API_KEY" }
default_model = "claude-haiku-4-5"
[providers.ollama]
type = "ollama"
base_url = "http://127.0.0.1:11434"
default_model = "qwen3.6:35b-mlx"
[agents.dispatch]
provider = "anthropic"
model = "claude-sonnet-4-6"
fallbacks = [{ provider = "ollama", model = "qwen3.6:35b-mlx" }]
Best for: Daily driver — cloud quality with offline resilience.
3. Multi-Cloud Hybrid Routing
Route different tasks to different cloud providers based on cost and capability:
default_provider = "deepseek"
default_model = "deepseek-v4-flash"
[providers.deepseek]
type = "openai-compatible"
base_url = "https://api.deepseek.com"
api_key = { env = "DEEPSEEK_API_KEY" }
default_model = "deepseek-v4-flash"
[providers.aliyun]
type = "openai-compatible"
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
api_key = { env = "DASHSCOPE_API_KEY" }
default_model = "qwen3.6-plus"
[providers.groq]
type = "openai-compatible"
base_url = "https://api.groq.com/openai/v1"
api_key = { env = "GROQ_API_KEY" }
default_model = "llama-3.3-70b-versatile"
# Knowledge pipeline: local-first, cloud backup
[agents.notion_extraction]
provider = "ollama"
model = "qwen3.6:35b-mlx"
fallbacks = [
{ provider = "deepseek", model = "deepseek-v4-flash" }
]
# Orchestrator: capable cloud model with fallbacks
[agents.Sisyphus]
provider = "anthropic"
model = "claude-sonnet-4-6"
fallbacks = [
{ provider = "openai", model = "gpt-4o" },
{ provider = "deepseek", model = "deepseek-v4-flash" }
]
Best for: Cost optimization with multiple provider accounts.
4. Privacy-Preserving Setup
Local for sensitive data, cloud for public information:
default_provider = "ollama"
default_model = "qwen3.6:35b-mlx"
[providers.ollama]
type = "ollama"
base_url = "http://127.0.0.1:11434"
[providers.deepseek]
type = "openai-compatible"
base_url = "https://api.deepseek.com"
api_key = { env = "DEEPSEEK_API_KEY" }
# Private data stays local
[agents.Metis]
provider = "ollama"
max_sensitivity = "Medium"
# Public research can use cloud
[agents.Explore]
provider = "deepseek"
llm_preferences = "CloudOnly"
max_sensitivity = "Low"
Best for: Healthcare, legal, finance — any domain with data residency requirements.
5. Cost-Optimized Setup
Cheapest capable model for each task tier:
default_provider = "deepseek"
default_model = "deepseek-v4-flash"
[providers.deepseek]
type = "openai-compatible"
base_url = "https://api.deepseek.com"
api_key = { env = "DEEPSEEK_API_KEY" }
[providers.ollama]
type = "ollama"
base_url = "http://127.0.0.1:11434"
# Heavy reasoning: use local (free)
[agents.dispatch]
provider = "ollama"
model = "qwen3.6:35b-mlx"
# Light tasks: cheapest cloud API
[agents.Explore]
provider = "deepseek"
model = "deepseek-v4-flash"
# Synthesis: use best model sparingly
[agents.synthesis]
provider = "deepseek"
model = "deepseek-v4-flash"
fallbacks = [{ provider = "ollama", model = "qwen3.6:35b-mlx" }]
Best for: Budget-conscious setups, hobbyist use, development.
6. Complete Production Config
default_provider = "anthropic"
default_model = "claude-haiku-4-5"
[providers.ollama]
type = "ollama"
base_url = "http://127.0.0.1:11434"
default_model = "qwen3.6:35b-mlx"
[providers.anthropic]
type = "anthropic"
api_key = { env = "ANTHROPIC_API_KEY" }
default_model = "claude-haiku-4-5"
[providers.openai]
type = "openai"
api_key = { env = "OPENAI_API_KEY" }
default_model = "gpt-4o-mini"
[providers.deepseek]
type = "openai-compatible"
base_url = "https://api.deepseek.com"
api_key = { env = "DEEPSEEK_API_KEY" }
default_model = "deepseek-v4-flash"
# Orchestrator
[agents.Sisyphus]
provider = "anthropic"
model = "claude-sonnet-4-6"
fallbacks = [
{ provider = "openai", model = "gpt-4o" },
{ provider = "deepseek", model = "deepseek-v4-flash" }
]
# Planner
[agents.Prometheus]
provider = "anthropic"
model = "claude-sonnet-4-6"
fallbacks = [{ provider = "openai", model = "gpt-4o" }]
# Knowledge pipeline
[agents.notion_extraction]
provider = "ollama"
model = "qwen3.6:35b-mlx"
fallbacks = [
{ provider = "deepseek", model = "deepseek-v4-flash" },
{ provider = "openai", model = "gpt-4o-mini" }
]
# Fast exploration
[agents.Explore]
provider = "anthropic"
model = "claude-haiku-4-5"
fallbacks = [{ provider = "openai", model = "gpt-4o-mini" }]
llm_preferences = "CloudOnly"
# Privacy-sensitive analysis
[agents.Metis]
provider = "deepseek"
model = "deepseek-v4-flash"
fallbacks = [{ provider = "ollama", model = "qwen3.6:35b-mlx" }]
max_sensitivity = "Medium"
# Worker agents
[agents.Hephaestus]
provider = "anthropic"
model = "claude-sonnet-4-6"
fallbacks = [
{ provider = "openai", model = "gpt-4o" },
{ provider = "deepseek", model = "deepseek-v4-flash" }
]
[agents.Atlas]
provider = "ollama"
model = "qwen3.6:35b-mlx"
fallbacks = [{ provider = "deepseek", model = "deepseek-v4-flash" }]
[agents.Junior]
provider = "ollama"
model = "qwen3.6:35b-mlx"
fallbacks = []
Next: Introduction — back to guide start
System Architecture
Zen is a Rust CLI productivity suite with agentic workspace architecture. It follows a binary/library split with 12 workspace crates.
High-Level Architecture
┌─────────────────────────────────────────────┐
│ zen (binary, 13 lines) │
│ loads .env, calls zen_cli::shell() │
└──────────────────┬──────────────────────────┘
│
┌──────────────────▼──────────────────────────┐
│ zen-cli (library) │
│ clap Parser (29 commands), TUI (ratatui) │
│ command dispatcher │
└──┬────┬────┬────┬────┬────┬────┬────┬───────┘
│ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
┌────┬────┬────┬────┬────┬────┬────┬──────┐
│zen │zen │zen │zen │zen │zen │zen │zen │
│core│repo│vault│agents│mem │prov│auth│... │
└────┴────┴────┴────┴────┴────┴────┴──────┘
Crates Overview
| Crate | Role | Key Modules |
|---|---|---|
| zen | Binary entry (13-line main.rs) | .env loading, dispatches to zen_cli::shell() |
| zen-cli | CLI library | 29 commands, TUI (ratatui), clap derive dispatch |
| zen-core | Core infrastructure | 5-layer config, error taxonomy, path scoping, constants, secrets |
| zen-service | Business logic | Starter/wps/cleanup services |
| zen-repo | Data layer | sqlx + rusqlite dual API, FTS5, vec0, graph schema |
| zen-vault | Knowledge services | Note, Wiki, 5-tier search, consolidation, lint, ingest |
| zen-agents | Agent system | 13 agents, 4 tiers, blackboard, QualityPipeline, registry |
| zen-provider | LLM routing | 13 providers, 3 protocol types, DefaultRouter, auth resolution |
| zen-memory | Identity context | SOUL.md, MEMORY.md loading and management |
| zen-auth | Credential management | Keychain integration, SecretRef resolution |
| zen-plugin | Extension system | WASM sandbox (wasmtime), MCP server |
| zen-gateway | HTTP daemon | Axum-based HTTP server (placeholder) |
Key Architectural Patterns
Binary/Library Split
The zen binary (13 lines in crates/zen/src/main.rs) loads .env, calls zen_core::config::load_config(), then delegates to zen_cli::shell().await. All logic lives in library crates.
5-Layer Configuration
Embedded defaults → ~/.zen/config.toml → .zen/config.toml → ZEN_* env vars
Each layer merges into the previous one — higher layers override only the keys they set.
4-Tier Agent Architecture
Orchestrator (L0) → Planner (L1) → Specialist (L2) → Worker (L3)
- Orchestrator: Session coordination, routing (ZenCoordinator)
- Planner: Task decomposition, planning (AgentOrchestrator, Prometheus)
- Specialist: Domain expertise (search, consolidate, research)
- Worker: Execution, tool calling (AgentExecutor)
5-Tier Search Pipeline
ripgrep → FTS5 → vector embeddings → entity graph → LLM
Each tier adds depth: keyword search first, semantic when needed.
13 Built-In Agents
| Agent | Tier | Role |
|---|---|---|
| Sisyphus | L0 | Lead orchestrator |
| Prometheus | L1 | Task planner |
| Metis | L1 | Plan correctness review |
| Momus | L1 | Plan quality review |
| Zeus | L1 | Escalation handler |
| Oracle | L2 | Architecture consultation |
| Explore | L2 | Codebase exploration |
| Librarian | L2 | External reference search |
| Argus | L2 | Monitoring & observation |
| Hephaestus | L3 | Tool execution |
| Atlas | L3 | Knowledge pipeline |
| Junior | L3 | General task execution |
| Hermes | L3 | Safety & audit |
Data Flow: Note Creation to Wiki
zen note create → zen-vault (NoteService) → Markdown file in inbox/
→ zen-repo (sqlx insert)
zen consolidate → zen-vault (ConsolidationPipeline)
→ zen-provider (entity extraction)
→ zen-repo (graph entities)
→ zen-vault (WikiPage generation)
zen search run → zen-vault (SearchService)
→ tier 1: ripgrep
→ tier 2: FTS5 (notes_fts)
→ tier 3: vec0 embeddings
→ tier 4: entity graph
→ tier 5: LLM semantic reranking
Learn more: AGENTS.md for the full project knowledge base.
Development
Prerequisites
- Rust 1.80+ (edition 2024)
- macOS (primary development platform)
Build
# Build all crates
cargo build
# Build release binary
bin/build
Test
# Run all tests
cargo test
# Run with nextest (recommended for env-isolated tests)
cargo nextest run
# Run specific crate tests
cargo test -p zen-core
cargo test -p zen-provider
cargo test -p zen-agents
Note: Some tests (particularly path tests) require
cargo nextestfor process isolation because they modify environment variables.
Lint & Format
# Run linter
bin/lint
# Or individually:
cargo clippy -- -D warnings
cargo fmt --all --check
# Format code
cargo fmt --all
Project Structure
zenspace/
├── crates/ # 12 Rust workspace crates
│ ├── zen/ # Binary entry (13-line main.rs)
│ ├── zen-cli/ # CLI library + TUI
│ ├── zen-core/ # Core infrastructure (13 modules)
│ ├── zen-service/ # Business logic
│ ├── zen-repo/ # Data layer (sqlx + rusqlite)
│ ├── zen-vault/ # Knowledge services
│ ├── zen-agents/ # Agent system
│ ├── zen-provider/ # LLM provider routing
│ ├── zen-memory/ # Identity context
│ ├── zen-auth/ # Credential management
│ ├── zen-plugin/ # WASM sandbox + MCP
│ └── zen-gateway/ # HTTP daemon
├── config/ # Embedded config.toml
├── templates/ # Tera templates
├── docs/ # Documentation
│ ├── src/ # User guide (mdBook source)
│ │ ├── introduction.md
│ │ ├── installation.md
│ │ ├── quickstart.md
│ │ └── ...
│ ├── theme/ # mdBook custom theme
│ ├── book/ # Generated HTML output
│ └── specs/ # Architecture specifications
└── bin/ # Build/test/lint/release scripts
Release
# Automated release
bin/release patch # 0.1.0 → 0.1.1
bin/release minor # 0.1.0 → 0.2.0
bin/release major # 0.1.0 → 1.0.0
# Manual release
echo "0.1.2" > VERSION
git commit -am "release: v0.1.2"
git tag v0.1.2
git push origin main --tags
Code Conventions
- Imports:
use crate::for internal,use zen_*::for cross-crate - Errors:
thiserrorfor libraries,anyhowfor app-level - CLI commands: Each command in
src/cmd/{name}_command.rswithpub fn execute_command() - Config: Embedded
config/config.toml+ user~/.zen/config.toml - Tests: Integration tests only (no inline
#[cfg(test)]in most crates)
Design Principles
See AGENTS.md for the full project constitution:
- CLI-First — Every feature via CLI subcommands
- Robust Error Handling —
thiserrorfor types,anyhowfor propagation - Observability — Structured logging via
tracing - Configuration —
.envviadotenvy, 5-layer config inheritance - Template-Driven — Embedded templates via
include_dir - Code Quality — Zero warnings,
unsafeblocks justified - Single Responsibility — 12 crates with clear boundaries
- Testing — Unit + integration tests required
- UX Consistency — JSON/human-readable dual output
- Performance — <500ms cold start, <50MB footprint
- Design-First & Reuse — Reuse frameworks, don't reinvent