Query multiple LLMs and deep research APIs in parallel.
Post each response as a comment on a GitHub Issue.
Built on Simon Willison's llm for standard model access, with direct API integrations for deep research endpoints. Supports dozens of free models via OpenRouter.
# From source
pip install -e .
# Or globally with pipx (recommended)
pipx install .
# 1. Configure your council (interactive picker)
owl council
# 2. Ask the council
owl ask "What are the tradeoffs between Redis and Memcached for session storage?"
# 3. Read from a file
owl ask -f research_question.md
# 4. Pipe from stdin
echo "Explain quantum computing" | owl ask
# 5. Post to a GitHub issue
owl ask "..." --gh owner/repo
owl ask "..." --gh owner/repo --issue 42
llm)Install llm plugins and set their API keys:
# OpenAI
llm install llm-openai # included by default with llm
llm keys set openai # paste your OpenAI API key
# Anthropic (Claude)
llm install llm-anthropic
llm keys set anthropic # paste your Anthropic API key
# Google Gemini
llm install llm-gemini
llm keys set gemini # paste your Google AI API key
# Mistral
llm install llm-mistral
llm keys set mistral # paste your Mistral API key
# Grok (xAI)
llm install llm-grok
llm keys set grok # paste your xAI API key
# DeepSeek
llm install llm-deepseek
llm keys set deepseek # paste your DeepSeek API key
# Cohere
llm install llm-command-r
llm keys set cohere # paste your Cohere API key
# OpenRouter (dozens of models, many free — no credit card needed)
llm install llm-openrouter
llm keys set openrouter # paste your OpenRouter API key
# Local models via Ollama
llm install llm-ollama
# No key needed — just have Ollama running
Verify your installed models:
llm models # list all available models
Keys are stored in ~/Library/Application Support/io.datasette.llm/keys.json (macOS) or ~/.config/io.datasette.llm/keys.json (Linux).
You can also pass keys via environment variables (e.g. OPENAI_API_KEY) or inline with --key.
See the full llm plugin directory for more providers.
Sign up at openrouter.ai (no credit card required) and get a free API key. Many powerful models are completely free:
llm models | grep ":free" to see allRate limits: ~20 req/min, ~200 req/day per free model. Owl staggers requests to stay within limits.
Deep research models use direct API calls (not llm plugins). Set their keys as environment variables:
export OPENAI_API_KEY=sk-... # o3-deep-research, o4-mini-deep-research
export PERPLEXITY_API_KEY=pplx-... # sonar-deep-research
export GOOGLE_API_KEY=AI... # Gemini Deep Research Agent
export DEEPSEEK_API_KEY=sk-... # deepseek-v4-flash
export XAI_API_KEY=xai-... # Grok agentic search
Add these to your ~/.zshrc or ~/.bashrc to persist them.
For posting results to GitHub Issues, owl uses your gh CLI auth or a GITHUB_TOKEN:
# Option A: gh CLI (recommended)
gh auth login
# Option B: environment variable
export GITHUB_TOKEN=ghp_...
owl ask "prompt" # Query all council members
owl ask -f prompt.md # Read prompt from file
cat prompt.txt | owl ask # Read from stdin
owl ask "prompt" --format brief # Shorter answers (see below)
owl ask "prompt" --synthesise # Add an arbiter's combined answer
owl ask "prompt" --arbiter gpt-5 # Synthesise with a specific model
owl ask "prompt" --gh owner/repo # Create new issue with responses
owl ask "prompt" --gh owner/repo --issue 42 # Post to existing issue
owl council # Interactive TUI to select council members
owl council-list # Show current council
owl models # Show all available models
owl -v ask "prompt" # Show provider stack traces on stderr
By default owl shows you every answer and leaves you to reconcile them. With
--synthesise, one more model reads all of them and produces a single
answer:
owl ask "Redis or Memcached for session storage?" --synthesise
owl ask "..." --arbiter gpt-5 # pick the arbiter explicitly
╭─ ⚖️ Synthesis judge (3.3s) ──────────────────────────────────────────────╮
│ ANSWER: Use Redis. It offers persistence and richer data structures... │
│ │
│ CONFIDENCE: Moderate. Two of three members reached this independently, │
│ and the reasoning about durability is the load-bearing part. │
│ │
│ DISAGREEMENT: One member preferred Memcached for simplicity... │
│ │
│ WATCH OUT FOR: The persistence claim was sourced by only one member. │
╰──────────────────────────────────────────────────────────────────────────╯
The arbiter is given every answer in full, including any reasoning, and is told to weigh the reasoning rather than count votes. A council can agree and still be wrong, and the argument in a dissenting answer is often what shows it, so agreement is treated as evidence rather than as the result. The individual answers are still printed underneath.
Set a default arbiter in ~/.owl/config.yaml:
council:
- name: gpt-5
source: llm
- name: claude-sonnet-4.6
source: llm
arbiter:
name: claude-sonnet-4.6
source: llm
Without one, owl uses the first llm member of your council. Deep research
members are skipped as arbiters: they are slow and expensive for what is a
reconciling job. Synthesis is skipped entirely when fewer than two members
answered, rather than spending a request to restate a single answer.
--format sets a word-count target in the system prompt:
| Value | Target |
|---|---|
brief | 100-200 words |
standard (default) | 250-400 words |
detailed | 600-1000 words |
It has no effect on openai-deep and google-deep members, which use a
fixed deep research report structure regardless of the flag.
Provider failures appear as red panels with the reason reported by the API.
For the underlying stack trace and retry activity, add -v before the
subcommand: owl -v ask "prompt".
Run owl council to open the interactive selector:
🦉 Parliament of Owls — Select Your Council
# Model Source Description
Standard Models (via llm)
1 ☑ gpt-5 llm
2 ☑ claude-sonnet-4.6 llm
3 ☐ gemini-2.5-pro llm
Deep Research
4 ☑ o3-deep-research openai-deep OpenAI Deep Research
5 ☑ sonar-deep-research perplexity Perplexity Deep Research
6 ☐ gemini-deep-research google-deep Gemini Deep Research Agent
7 ☐ deepseek-v4-flash deepseek DeepSeek V4 Flash (thinking)
8 ☐ grok-agentic xai Grok 4.5 agentic search
Number to toggle, /text=filter, a=all shown, n=none shown, s=save, q=quit:
The table caps at 30 rows. With OpenRouter installed the catalogue runs to
several hundred models, so use /text to filter by model name or source —
/:free then a selects the free models, since a and n act on what is
shown rather than the whole list.
Saved to ~/.owl/config.yaml.
Each provider implements deep research differently:
| Provider | What Happens | API |
|---|---|---|
| OpenAI | Separate model (o3-deep-research) that searches the web and synthesises reports. Runs as a background job that owl polls to completion | Responses API |
| Perplexity | Separate model (sonar-deep-research) with multi-step retrieval and citations | /chat/completions |
| Google Gemini | Async agent that plans, searches, reads, and reasons (can take minutes) | Interactions API |
| DeepSeek | V4 Flash with thinking mode enabled (deepseek-v4-flash) | /chat/completions |
| xAI Grok | Grok 4.5 with agentic web and X search | Responses API + server-side tools |
llm's key management or environment variables — never in the owl config file~/.owl/config.yaml only stores model names and sources, no secretsgh CLI auth or GITHUB_TOKEN env varOwl ships as a Claude Code plugin, giving Claude full knowledge of the owl CLI, config, providers, and architecture.
# Add the marketplace
/plugin marketplace add joelio/owl
# Install the plugin
/plugin install owl@owl
The /owl:owl skill teaches Claude how to:
When working on owl itself, load the plugin from your local checkout:
claude --plugin-dir .
git clone https://github.com/joelio/owl.git
cd owl
pip install -e ".[dev]"
pytest tests/ -v
ruff check src/ tests/
ruff format src/ tests/
mypy src/owl
ruff is pinned to a compatible release in pyproject.toml, and the lint
rules are selected explicitly under [tool.ruff.lint]. Both are deliberate:
ruff's default rule set changes between minor versions, which otherwise
turns CI red without anyone touching the code.
git checkout -b feature/amazing-owl)ruff check, ruff format --check, mypy src/owl and pytest passMIT — see LICENSE.
54 commits
2 commits
Python
100.0%
Query multiple LLMs and deep research APIs in parallel.
Post each response as a comment on a GitHub Issue.
Built on Simon Willison's llm for standard model access, with direct API integrations for deep research endpoints. Supports dozens of free models via OpenRouter.
# From source
pip install -e .
# Or globally with pipx (recommended)
pipx install .
# 1. Configure your council (interactive picker)
owl council
# 2. Ask the council
owl ask "What are the tradeoffs between Redis and Memcached for session storage?"
# 3. Read from a file
owl ask -f research_question.md
# 4. Pipe from stdin
echo "Explain quantum computing" | owl ask
# 5. Post to a GitHub issue
owl ask "..." --gh owner/repo
owl ask "..." --gh owner/repo --issue 42
llm)Install llm plugins and set their API keys:
# OpenAI
llm install llm-openai # included by default with llm
llm keys set openai # paste your OpenAI API key
# Anthropic (Claude)
llm install llm-anthropic
llm keys set anthropic # paste your Anthropic API key
# Google Gemini
llm install llm-gemini
llm keys set gemini # paste your Google AI API key
# Mistral
llm install llm-mistral
llm keys set mistral # paste your Mistral API key
# Grok (xAI)
llm install llm-grok
llm keys set grok # paste your xAI API key
# DeepSeek
llm install llm-deepseek
llm keys set deepseek # paste your DeepSeek API key
# Cohere
llm install llm-command-r
llm keys set cohere # paste your Cohere API key
# OpenRouter (dozens of models, many free — no credit card needed)
llm install llm-openrouter
llm keys set openrouter # paste your OpenRouter API key
# Local models via Ollama
llm install llm-ollama
# No key needed — just have Ollama running
Verify your installed models:
llm models # list all available models
Keys are stored in ~/Library/Application Support/io.datasette.llm/keys.json (macOS) or ~/.config/io.datasette.llm/keys.json (Linux).
You can also pass keys via environment variables (e.g. OPENAI_API_KEY) or inline with --key.
See the full llm plugin directory for more providers.
Sign up at openrouter.ai (no credit card required) and get a free API key. Many powerful models are completely free:
llm models | grep ":free" to see allRate limits: ~20 req/min, ~200 req/day per free model. Owl staggers requests to stay within limits.
Deep research models use direct API calls (not llm plugins). Set their keys as environment variables:
export OPENAI_API_KEY=sk-... # o3-deep-research, o4-mini-deep-research
export PERPLEXITY_API_KEY=pplx-... # sonar-deep-research
export GOOGLE_API_KEY=AI... # Gemini Deep Research Agent
export DEEPSEEK_API_KEY=sk-... # deepseek-v4-flash
export XAI_API_KEY=xai-... # Grok agentic search
Add these to your ~/.zshrc or ~/.bashrc to persist them.
For posting results to GitHub Issues, owl uses your gh CLI auth or a GITHUB_TOKEN:
# Option A: gh CLI (recommended)
gh auth login
# Option B: environment variable
export GITHUB_TOKEN=ghp_...
owl ask "prompt" # Query all council members
owl ask -f prompt.md # Read prompt from file
cat prompt.txt | owl ask # Read from stdin
owl ask "prompt" --format brief # Shorter answers (see below)
owl ask "prompt" --synthesise # Add an arbiter's combined answer
owl ask "prompt" --arbiter gpt-5 # Synthesise with a specific model
owl ask "prompt" --gh owner/repo # Create new issue with responses
owl ask "prompt" --gh owner/repo --issue 42 # Post to existing issue
owl council # Interactive TUI to select council members
owl council-list # Show current council
owl models # Show all available models
owl -v ask "prompt" # Show provider stack traces on stderr
By default owl shows you every answer and leaves you to reconcile them. With
--synthesise, one more model reads all of them and produces a single
answer:
owl ask "Redis or Memcached for session storage?" --synthesise
owl ask "..." --arbiter gpt-5 # pick the arbiter explicitly
╭─ ⚖️ Synthesis judge (3.3s) ──────────────────────────────────────────────╮
│ ANSWER: Use Redis. It offers persistence and richer data structures... │
│ │
│ CONFIDENCE: Moderate. Two of three members reached this independently, │
│ and the reasoning about durability is the load-bearing part. │
│ │
│ DISAGREEMENT: One member preferred Memcached for simplicity... │
│ │
│ WATCH OUT FOR: The persistence claim was sourced by only one member. │
╰──────────────────────────────────────────────────────────────────────────╯
The arbiter is given every answer in full, including any reasoning, and is told to weigh the reasoning rather than count votes. A council can agree and still be wrong, and the argument in a dissenting answer is often what shows it, so agreement is treated as evidence rather than as the result. The individual answers are still printed underneath.
Set a default arbiter in ~/.owl/config.yaml:
council:
- name: gpt-5
source: llm
- name: claude-sonnet-4.6
source: llm
arbiter:
name: claude-sonnet-4.6
source: llm
Without one, owl uses the first llm member of your council. Deep research
members are skipped as arbiters: they are slow and expensive for what is a
reconciling job. Synthesis is skipped entirely when fewer than two members
answered, rather than spending a request to restate a single answer.
--format sets a word-count target in the system prompt:
| Value | Target |
|---|---|
brief | 100-200 words |
standard (default) | 250-400 words |
detailed | 600-1000 words |
It has no effect on openai-deep and google-deep members, which use a
fixed deep research report structure regardless of the flag.
Provider failures appear as red panels with the reason reported by the API.
For the underlying stack trace and retry activity, add -v before the
subcommand: owl -v ask "prompt".
Run owl council to open the interactive selector:
🦉 Parliament of Owls — Select Your Council
# Model Source Description
Standard Models (via llm)
1 ☑ gpt-5 llm
2 ☑ claude-sonnet-4.6 llm
3 ☐ gemini-2.5-pro llm
Deep Research
4 ☑ o3-deep-research openai-deep OpenAI Deep Research
5 ☑ sonar-deep-research perplexity Perplexity Deep Research
6 ☐ gemini-deep-research google-deep Gemini Deep Research Agent
7 ☐ deepseek-v4-flash deepseek DeepSeek V4 Flash (thinking)
8 ☐ grok-agentic xai Grok 4.5 agentic search
Number to toggle, /text=filter, a=all shown, n=none shown, s=save, q=quit:
The table caps at 30 rows. With OpenRouter installed the catalogue runs to
several hundred models, so use /text to filter by model name or source —
/:free then a selects the free models, since a and n act on what is
shown rather than the whole list.
Saved to ~/.owl/config.yaml.
Each provider implements deep research differently:
| Provider | What Happens | API |
|---|---|---|
| OpenAI | Separate model (o3-deep-research) that searches the web and synthesises reports. Runs as a background job that owl polls to completion | Responses API |
| Perplexity | Separate model (sonar-deep-research) with multi-step retrieval and citations | /chat/completions |
| Google Gemini | Async agent that plans, searches, reads, and reasons (can take minutes) | Interactions API |
| DeepSeek | V4 Flash with thinking mode enabled (deepseek-v4-flash) | /chat/completions |
| xAI Grok | Grok 4.5 with agentic web and X search | Responses API + server-side tools |
llm's key management or environment variables — never in the owl config file~/.owl/config.yaml only stores model names and sources, no secretsgh CLI auth or GITHUB_TOKEN env varOwl ships as a Claude Code plugin, giving Claude full knowledge of the owl CLI, config, providers, and architecture.
# Add the marketplace
/plugin marketplace add joelio/owl
# Install the plugin
/plugin install owl@owl
The /owl:owl skill teaches Claude how to:
When working on owl itself, load the plugin from your local checkout:
claude --plugin-dir .
git clone https://github.com/joelio/owl.git
cd owl
pip install -e ".[dev]"
pytest tests/ -v
ruff check src/ tests/
ruff format src/ tests/
mypy src/owl
ruff is pinned to a compatible release in pyproject.toml, and the lint
rules are selected explicitly under [tool.ruff.lint]. Both are deliberate:
ruff's default rule set changes between minor versions, which otherwise
turns CI red without anyone touching the code.
git checkout -b feature/amazing-owl)ruff check, ruff format --check, mypy src/owl and pytest passMIT — see LICENSE.
54 commits
2 commits
Python
100.0%