any-llm on the command line

Built v1 sessions for docs/design-any-llm.md, after the first review pass. Every command, the flags it touches, and each response. Glyphs, colours and today's lines are the shipped CLI's; the any-llm wording is what the built code prints, noted under each frame. Generated by docs/mockups/any-llm-cli-session.py.

Terminal: what shipsCommentary: why, not product

1 · First run, no provider yet

bristlenose run — first run
~/research $ bristlenose run interviews/

No LLM provider configured.

Set one up once — bristlenose configure <provider> validates your
key and stores it securely (Keychain):

  Claude   https://console.anthropic.com/settings/keys
  ChatGPT  https://platform.openai.com/api-keys
  Gemini   https://aistudio.google.com/apikey
  Azure    https://portal.azure.com

For local models via Ollama:  bristlenose configure local
For Mistral, OpenRouter and others:  bristlenose configure any-llm

2 · The extra isn't installed

configure any-llm — not installed
~/research $ bristlenose configure any-llm

✗ any-llm isn't installed in this copy of Bristlenose.
  Add it:  pipx install --force "bristlenose[any-llm]"

~/research $ pipx install --force "bristlenose[any-llm]"
  installed package bristlenose 0.43.0, installed using Python 3.12.13
  These apps are now globally available
    - bristlenose
done! ✨ 🌟 ✨

3 · configure any-llm — key already in the shell

configure any-llm — Mistral, key from environment
~/research $ export MISTRAL_API_KEY=…
~/research $ bristlenose configure any-llm

Which model? Write it as provider:model, e.g. mistral:mistral-large-latest
Model: mistral:mistral-large-latest
Using the Mistral key from your environment (MISTRAL_API_KEY).
Checking with Mistral (~$0.0001, no transcript content)... ✓ Valid
Transcripts will go to Mistral, through any-llm 1.27.0.

any-llm is now your provider for analysis (was Claude).
Switch back any time:  bristlenose use claude
Run it with:  bristlenose run <folder>

4 · configure any-llm — no key yet, so it's stored

configure any-llm — DeepSeek, key stored in Keychain
~/research $ bristlenose configure any-llm

Which model? Write it as provider:model, e.g. mistral:mistral-large-latest
Model: deepseek:deepseek-flash

Enter your DeepSeek API key: 
Checking with DeepSeek (~$0.0001, no transcript content)... ✓ Valid
✓ Stored in Keychain as "Bristlenose DeepSeek API Key (any-llm)"
Transcripts will go to DeepSeek (api.deepseek.com), through any-llm 1.27.0.

any-llm is now your provider for analysis.
Run it with:  bristlenose run <folder>

5 · Scripted setup: --key and the model variable

configure any-llm --key, non-interactive
~/research $ export 
BRISTLENOSE_ANYLLM_MODEL=openrouter:meta-llama/llama-3.3-70b-instruct:free
~/research $ bristlenose configure any-llm --key sk-or-v1-…

Model: openrouter:meta-llama/llama-3.3-70b-instruct:free  (from 
BRISTLENOSE_ANYLLM_MODEL)
Checking with OpenRouter (~$0.0001, no transcript content)... ✓ Valid
✓ Stored in Keychain as "Bristlenose OpenRouter API Key (any-llm)"
Transcripts will go to OpenRouter (openrouter.ai), which passes them to the
model's host. Check their data policy for the model you picked.

any-llm is now your provider for analysis.

6 · configure any-llm — every way it can say no

configure any-llm — refusals
~/research $ bristlenose configure any-llm
Model: mistral-large-latest
✗ Write the model as provider:model, e.g. mistral:mistral-large-latest

~/research $ bristlenose configure any-llm
Model: mistrall:mistral-large-latest
✗ any-llm doesn't know a provider called "mistrall". Did you mean mistral?
  Providers: https://mozilla-ai.github.io/any-llm/providers/

~/research $ bristlenose configure any-llm
Model: anthropic:claude-sonnet-4-6
✗ Claude is built in. Use:  bristlenose configure claude

~/research $ bristlenose configure any-llm
Model: cohere:command-r-plus
✗ Cohere needs an add-on this install doesn't have.
  Add it:  pipx inject bristlenose "any-llm-sdk[cohere]"

7 · run — the everyday path

bristlenose run interviews/
~/research $ bristlenose run interviews/

Bristlenose v0.43.0 · any-llm · Apple M2 Max · MLX

Analysis: mistral:mistral-large-latest via any-llm → Mistral
4 sessions in interviews/

 ✓ Ingested 4 sessions (4 video)                          0.8s
 ✓ Extracted audio from 4 sessions                        1.3s
 ✓ Transcribed 4 sessions (229 segments)                2m 41s
 ✓ Identified speakers for 4 sessions                     6.2s
 ✓ Merged transcripts for 4 sessions                      0.1s
 ✓ Segmented 4 transcripts into 35 topics                11.4s
 ✓ Extracted 48 quotes from 4 sessions                   38.9s
 ✓ Clustered quotes into 4 themes (7 screens)             9.7s
 ✓ Rendered report                                        0.2s

  4 participants · 7 screens · 4 themes · 48 quotes
  LLM: 44,920 in · 9,112 out (mistral:mistral-large-latest)

  Done in 3m 52s

  Report:  http://127.0.0.1:8150/report/
  Press Ctrl-C to stop the server

8 · run --llm any-llm with no model set

run --llm any-llm — no model
~/research $ bristlenose run interviews/ --llm any-llm

✗ any-llm needs a model, written as provider:model.
  Set it once:  bristlenose configure any-llm
  Or per run:   BRISTLENOSE_ANYLLM_MODEL=mistral:mistral-large-latest

9 · use — switching between stored keys

bristlenose use
~/research $ bristlenose use mistral:mistral-large-latest
any-llm is now your provider for analysis (was Claude).
Switch back any time:  bristlenose use claude
Model: mistral:mistral-large-latest (was deepseek:deepseek-flash)

~/research $ bristlenose use deepseek:deepseek-flash
any-llm is now your provider for analysis.
Model: deepseek:deepseek-flash (was mistral:mistral-large-latest)

~/research $ bristlenose use openrouter:x-ai/grok-4
✗ No OpenRouter API key: OPENROUTER_API_KEY isn't set and none is stored.
  Store one:  bristlenose configure any-llm

~/research $ bristlenose use claude
Claude is now your provider for analysis (was any-llm).
Switch back any time:  bristlenose use any-llm

10 · doctor

bristlenose doctor
~/research $ bristlenose doctor

bristlenose 0.43.0

 ✓ FFmpeg          8.1.1 (/opt/homebrew/bin/ffmpeg)
 ✓ Transcription   mlx-whisper 0.4.3 (MLX)
 ✓ Whisper model   large-v3-turbo cached (1.5 GB)
 ✓ API key         Mistral (…f2a) (environment)
 ✓ any-llm         1.27.0 · mistral, groq, openrouter, deepseek
 — Network         checked by the run's preflight for Mistral
 — PII redaction   off (use --redact-pii to enable)
 ✓ Voice pass      model cached (40 MB)
 ✓ Disk space      44 GB free
 ✓ Serve mode      6 deps installed
 ✓ Auth token      random (generated at serve startup)

All clear.

11 · doctor — when something's off

bristlenose doctor — key missing
~/research $ bristlenose doctor

bristlenose 0.43.0

 ✓ FFmpeg          8.1.1 (/opt/homebrew/bin/ffmpeg)
 ✗ API key         No DeepSeek API key: DEEPSEEK_API_KEY isn't set and none is 
stored.
 — Network         skipped (no key)

API key
  Store one:  bristlenose configure any-llm

12 · pipeline

bristlenose pipeline (excerpt)
~/research $ bristlenose pipeline
QUOTE EXTRACTION, QUOTE CLUSTERING,
THEMATIC GROUPING, DISCUSSION
  Claude
    Sonnet 4.6  (default)                    ✓  ●
  ChatGPT
    GPT-5.6 Terra                            ✓  ●
  Azure OpenAI                               ✗     no Azure OpenAI key set
  Gemini
    3.8 Flash                                ✓  ?  untested
  Local (Ollama)
    llama3.2 3B                              ✓  ⚠  small models miss 
multi-clause quotes
  any-llm
    mistral:mistral-large-latest  (current)  ✓  ?  untested
  Apple FM                                   —     check in the desktop app

OS: Darwin arm64 · RAM: 32.0 GB · keys: anthropic, openai, anyllm · ollama: 
running

~/research $ bristlenose pipeline   # on a machine without the add-on
  ...
  any-llm                                    ✗     any-llm not installed

13 · run — the provider says no

run — out of credit, bad key, rate limit
~/research $ bristlenose run interviews/

Bristlenose v0.43.0 · any-llm · Apple M2 Max · MLX

Analysis: openrouter:anthropic/claude-sonnet-4.6 via any-llm → openrouter.ai

 ✓ Ingested 4 sessions (4 video)                            0.8s
 ✓ Transcribed 4 sessions (229 segments)                 (cached)
 ✗ Identifying speakers

✗ Your OpenRouter account ran out of credit.
  then run  bristlenose run interviews/  again.

~/research $ bristlenose run interviews/
  ...
✗ Mistral rejected your API key (…x7f).
  Run  bristlenose configure any-llm  to set a new key.

~/research $ bristlenose run interviews/
  ...
✗ Rate-limited by DeepSeek.
  Wait a minute and run  bristlenose run interviews/  again.

14 · Help text

run --help / configure --help (excerpts)
~/research $ bristlenose run --help
│ --llm                 -l      <str>   LLM provider: claude, chatgpt, azure, gemini,  │
│                                       local, any-llm.                                │

~/research $ bristlenose configure --help
│ *    provider      <str>  Provider to configure: claude, chatgpt, gemini,       │
│                           azure, local, any-llm, or miro.                         │