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)
  1. Capture — Notes, RSS feeds, raw files all go into inbox
  2. Tidy — Clean, chunk, normalize into structured Markdown
  3. Organize — Embed, index, classify — make everything searchable
  4. Distill — Extract entities, compile wiki pages, detect contradictions
  5. 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-exec is 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.

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

CLI Commands Reference

Zen provides 29 CLI commands for knowledge management, agent orchestration, and system administration.

General

CommandDescription
zenLaunch TUI (interactive interface)
zen versionShow version information
zen --helpShow full help with all commands

Workspace & Configuration

CommandDescription
zen workspace initInitialize .zen/ workspace structure
zen config showShow effective configuration (all layers merged)
zen provider listList available LLM providers
zen provider test <name>Test a provider connection
zen auth listList stored credentials

Knowledge Management

CommandDescription
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 listList wiki pages
zen wiki show <id>Show a wiki page
zen wiki reindexReindex wiki pages
zen wiki lintLint wiki (orphan pages, broken wikilinks)
zen wiki distillDistill wiki content
zen ingest <path>Ingest files or RSS feeds
zen brief generateGenerate a brief from recent notes

Agentic Sessions

CommandDescription
zen session startStart an agentic session
zen session listList active sessions
zen session stop <id>Stop a session
zen chatInteractive LLM chat
zen research <topic>Run research task
zen agent listList available agents
zen dispatch run <task>Dispatch a task to agents
zen dispatch status <id>Check task status
zen dispatch listList dispatched tasks
zen dispatch cancel <id>Cancel a task

System

CommandDescription
zen serveStart 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

CommandDescription
zen habit logLog a habit entry
zen habit listList habits
zen goal createCreate a goal
zen goal listList goals
zen goal status <id>Check goal progress

Plugin Management

CommandDescription
zen plugin listList 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

PriorityLayerFile / SourceTypical Use
1 (highest)EnvironmentZEN_* environment variablesTemporary overrides, CI/CD, secrets
2Workspace.zen/config.tomlPer-project settings
3Global User~/.zen/config.tomlUser-wide preferences
4 (lowest)Embedded Defaultconfig/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:

SectionDescription
default_providerDefault provider name (references a [providers.*] key)
default_modelDefault 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

TypeAuth RequiredDescriptionExamples
ollamaNoLocal Ollama serverqwen3.6, llama3, mistral (local)
openaiAPI keyNative OpenAI APIgpt-4o, gpt-4o-mini
anthropicAPI keyNative Anthropic Messages APIclaude-sonnet-4-6, claude-haiku-4-5
geminiAPI keyGoogle Gemini APIgemini-2.0-flash
cohereAPI keyCohere APIcommand-r
mistralAPI keyMistral APImistral-large-latest
openai-compatibleAPI keyOpenAI-compatible endpointsDeepSeek, Groq, Perplexity, Aliyun, xAI
anthropic-compatibleAPI keyAnthropic-compatible endpointsMoonshot, MiniMax
mockNoTesting 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:

  1. api_key.env — named environment variable (e.g., DEEPSEEK_API_KEY)
  2. api_key.keychain — macOS Keychain service name (e.g., zen-deepseek-api-key)
  3. api_key_env — legacy env var field (deprecated)
  4. {PROVIDER}_API_KEY — auto-derived env var (e.g., OPENAI_API_KEY)
  5. 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

FieldRequiredDescription
typeYesProtocol type (see table above)
base_urlFor some typesAPI endpoint URL (Ollama: http://127.0.0.1:11434)
api_keyFor cloud providersSecret reference (env var or keychain)
api_key_envNoLegacy env var name (deprecated)
default_modelRecommendedDefault model name for this provider
modelsNoPer-model catalog with parameters (see Model Catalog)
wire_apiNoWire 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

ParameterTypeDescriptionExample
temperaturefloat (0.0–2.0)Sampling temperature. Higher = more random0.7
max_tokensintegerMaximum tokens in the response4096
reasoning_effortstringReasoning depth: "low", "medium", "high""high"
top_pfloat (0.0–1.0)Nucleus sampling threshold0.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:

  1. Model-level defaults from the model catalog entry
  2. Variant overrides (if specified)
  3. 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

FieldRequiredDescription
providerYesPrimary provider name (must match a [providers.*] key)
modelNoModel override (falls back to provider's default_model)
fallbacksNoOrdered fallback chain if primary fails
llm_preferencesNo"Any", "LocalOnly", "CloudOnly", or "Provider(name)"
max_sensitivityNoMax data sensitivity: "Low", "Medium", "High"
temperatureNoOverride per-agent temperature
max_tokensNoOverride per-agent max tokens
variantNoSelect a named variant from the model catalog
retry_policyNoRetry settings for transient errors

LLM Preferences

PreferenceBehavior
AnyStandard routing (primary → fallbacks)
LocalOnlyForce Ollama if available, error if unreachable
CloudOnlyForce 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:

FieldDescription
providerProvider name for this fallback step
modelOverride model (optional, uses provider's default if omitted)
timeout_secsTimeout for this step (optional)
variantVariant 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 VarEffect
ZEN_AGENT_NOTION_EXTRACTION_PROVIDEROverride notion_extraction provider
ZEN_AGENT_NOTION_EXTRACTION_MODELOverride notion_extraction model
ZEN_AGENT_CONTRADICTION_DETECTION_PROVIDEROverride contradiction detection provider
ZEN_AGENT_CONTRADICTION_DETECTION_MODELOverride contradiction detection model
ZEN_AGENT_SYNTHESIS_PROVIDEROverride synthesis provider
ZEN_AGENT_SYNTHESIS_MODELOverride synthesis model
ZEN_AGENT_DISPATCH_PROVIDEROverride dispatch provider
ZEN_AGENT_DISPATCH_MODELOverride 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

  1. Explicit api_key.env in provider config takes precedence over auto-derived names
  2. Environment variables override both global and workspace config files
  3. Per-agent env vars override the agent's provider/model settings
  4. Set env vars in .env file (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

CrateRoleKey Modules
zenBinary entry (13-line main.rs).env loading, dispatches to zen_cli::shell()
zen-cliCLI library29 commands, TUI (ratatui), clap derive dispatch
zen-coreCore infrastructure5-layer config, error taxonomy, path scoping, constants, secrets
zen-serviceBusiness logicStarter/wps/cleanup services
zen-repoData layersqlx + rusqlite dual API, FTS5, vec0, graph schema
zen-vaultKnowledge servicesNote, Wiki, 5-tier search, consolidation, lint, ingest
zen-agentsAgent system13 agents, 4 tiers, blackboard, QualityPipeline, registry
zen-providerLLM routing13 providers, 3 protocol types, DefaultRouter, auth resolution
zen-memoryIdentity contextSOUL.md, MEMORY.md loading and management
zen-authCredential managementKeychain integration, SecretRef resolution
zen-pluginExtension systemWASM sandbox (wasmtime), MCP server
zen-gatewayHTTP daemonAxum-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

AgentTierRole
SisyphusL0Lead orchestrator
PrometheusL1Task planner
MetisL1Plan correctness review
MomusL1Plan quality review
ZeusL1Escalation handler
OracleL2Architecture consultation
ExploreL2Codebase exploration
LibrarianL2External reference search
ArgusL2Monitoring & observation
HephaestusL3Tool execution
AtlasL3Knowledge pipeline
JuniorL3General task execution
HermesL3Safety & 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 nextest for 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: thiserror for libraries, anyhow for app-level
  • CLI commands: Each command in src/cmd/{name}_command.rs with pub 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:

  1. CLI-First — Every feature via CLI subcommands
  2. Robust Error Handlingthiserror for types, anyhow for propagation
  3. Observability — Structured logging via tracing
  4. Configuration.env via dotenvy, 5-layer config inheritance
  5. Template-Driven — Embedded templates via include_dir
  6. Code Quality — Zero warnings, unsafe blocks justified
  7. Single Responsibility — 12 crates with clear boundaries
  8. Testing — Unit + integration tests required
  9. UX Consistency — JSON/human-readable dual output
  10. Performance — <500ms cold start, <50MB footprint
  11. Design-First & Reuse — Reuse frameworks, don't reinvent