Reference
Providers
Sigil needs two things from a provider: an LLM for classification, extraction, AUDM decisions, and synthesis; and an embedder for vectors. They’re configured independently — you can mix a local embedder with a hosted LLM, or the reverse.
LLM providers
Section titled “LLM providers”| Provider | Key | Notes |
|---|---|---|
| OpenRouter | OPENROUTER_API_KEY | One key, namespaced models across Anthropic / OpenAI / Google / Meta. Default: google/gemini-flash-latest. |
| Anthropic | ANTHROPIC_API_KEY | Direct Claude access |
| OpenAI | OPENAI_API_KEY | Cheapest API option — gpt-4o-mini |
| Ollama | none | Fully local. Default qwen2.5:7b. |
Claude Code (claude-cli) | none | Uses your existing Claude Code subscription |
Codex CLI (codex) | none | Uses your existing Codex subscription |
What the LLM actually does
Section titled “What the LLM actually does”Not chat. Four structured jobs, in descending order of how much model quality matters:
| Job | Called | Matters because |
|---|---|---|
| AUDM decisions | Per ambiguous candidate | Getting these wrong compounds over every future write |
| Fact extraction | Per chunk | High volume — this is where cost lives |
| Synthesis | Per synthesized search | Prose quality is visible |
| Classification / routing | Per message, per query | Small labelling tasks; almost any model is fine |
That asymmetry is why per-task routing exists.
Why the default is Gemini Flash
Section titled “Why the default is Gemini Flash”At current OpenRouter pricing it’s the best all-rounder for Sigil’s call shapes: $0.0005/$0.003 per 1M tokens, 1M context, strong JSON output, ~500ms typical latency. It beats Claude Haiku roughly 2× on cost and 5× on context while matching reasoning and JSON reliability for extraction, AUDM, classification, routing, and synthesis.
Claude Code as a provider
Section titled “Claude Code as a provider”claude-cli shells out to the claude binary and uses your existing subscription — no API key, no per-token cost.
Two caveats. It’s slower than an API call, because it boots a CLI per invocation. And under launchd or systemd the daemon may run with a stripped PATH that can’t see ~/.local/bin or your nvm bin directory:
llm.cliPath = /Users/you/.local/bin/claudeThe optional managed-session engine keeps warm workers in tmux to amortize that boot cost across many calls.
Embedding providers
Section titled “Embedding providers”| Provider | Key | Default model | Notes |
|---|---|---|---|
| OpenAI | OPENAI_API_KEY | text-embedding-3-large | Best quality/cost. 1024 via Matryoshka truncation. |
| Voyage | VOYAGE_API_KEY | voyage-3-large | MTEB ~76, Anthropic-recommended |
| OpenRouter | OPENROUTER_API_KEY | namespaced | One key for both LLM and embeddings |
| Ollama | none | mxbai-embed-large | Free, local, native 1024 |
The dimension is fixed at 1024
Section titled “The dimension is fixed at 1024”Every embedding Sigil stores is exactly 1024 dimensions. The database’s vector(N) columns and every provider are pinned to it.
This is a build-time constant, not configuration. A model that can’t natively emit — or Matryoshka-truncate to — 1024 is rejected at setup rather than failing deep in the pipeline with a dimension-mismatch error that looks like “db not supporting / model not supporting”. Changing it is a schema break.
Auto-detection
Section titled “Auto-detection”When you don’t pick explicitly, Sigil walks a waterfall.
LLM: configured provider → OpenRouter key → Anthropic key → OpenAI key → Ollama reachable → claude CLI installed
Embeddings: configured provider → Voyage key → Ollama reachable → OpenAI key
Detection only fills a gap. Once onboarding saves a provider, that’s what’s used — no environment variable can override it, which was a real failure mode under the old .env design.
Per-task routing
Section titled “Per-task routing”Send different work to different models with provider:model syntax:
llm.extractionModel = openrouter:qwen/qwen3.5-flashllm.decisionModel = openrouter:anthropic/claude-sonnet-latestllm.entityModel = (provider default)search.synthesizeModel = openrouter:anthropic/claude-sonnet-latestCheap model for the high-volume per-chunk extraction; smart model for the per-decision AUDM judgement. OpenRouter’s init flow offers this split as an opt-in “Advanced overrides” step with sensible defaults pre-filled.
Set them in Settings → Advanced.
Choosing a stack
Section titled “Choosing a stack”decisionModel + Voyage embeddings.What leaves your machine
Section titled “What leaves your machine”| Sees what | |
|---|---|
| Database | Everything — but it’s yours |
| Embedding provider | Every chunk of every ingested document, and every search query |
| LLM provider | Chunks during extraction, fact pairs during AUDM, your message during classification |
| Sigil | Nothing. No telemetry, no account, no phone-home except the GitHub update check. |
Disable the update check with preferences.noUpdateCheck (Settings → General).
Changing provider later
Section titled “Changing provider later”Settings → Change provider re-runs the same tested step from setup: pick, enter a key, live-test, apply, restart. Or from the terminal, sigil init — it’s idempotent and preserves what you don’t change.
sigil doctor # confirms which providers are live, with a real callTimeouts and limits
Section titled “Timeouts and limits”| Setting | Default | Applies to |
|---|---|---|
llm.requestTimeout | 60000 | Network providers — OpenAI, OpenRouter, Voyage |
llm.cliTimeout | 120000 | CLI providers and local Ollama generation |
llm.maxRetries | 3 | All providers |
llm.maxClaudeProcs | 4 | Concurrent claude processes |
Local generation legitimately runs longer than an API call, which is why Ollama uses the CLI timeout. The maxClaudeProcs semaphore exists because an unbounded ingest fan-out once produced 1600+ live sessions.