Coding Owl is archived. It did not fulfill its core loop, so rather than pivoting or refactoring it, I am building something new from scratch with the lessons learned. Why Coding Owl is archived

Chat model providers

Where the desktop chat gets its model: Anthropic, OpenRouter, and how a key is configured.

The desktop app carries a chat, and a model answers it. This page is about where that model comes from: what a provider is here, how its key is configured, and what each of the two providers Owl drives needs from you.

What owl providers is for

Manage the model providers the desktop chat speaks to.

The chat lives in the desktop app and is answered by the daemon, which holds the keys: they go to the OS keychain, and the database keeps only a reference to them (ADR-0019, ADR-0022). The key is typed here rather than in the app, so the app never holds one.

Owl speaks to anthropic and openrouter. Which models a provider offers is Owl’s to know for Anthropic and yours to say for OpenRouter, which carries whatever your account has.

What the chat may do with a model is bounded: it reads what Owl knows - Projects, Jobs, Runs, logs and diffs - and it never acts on its own. A command it proposes runs only once you have agreed to it, from a fixed allowlist of read-only programs, executed without a shell (ADR-0022).

A provider is not an Account, and not a Driver

The three are easy to run together and mean different things (CONTEXT.md defines the other two):

What it is Configured with
Model provider Where the desktop chat’s model comes from owl providers add
Account The subscription Owl runs an Agent as, with its own tool configuration and its own rate limits owl account add
Driver The plugin that knows how to operate one coding tool, such as Claude Code owl account add --driver

An Account and a Driver are about work Owl does for you while you are away. A model provider is only about the conversation you have with Owl afterwards: nothing a Job runs on goes through one, and configuring one does not change what an Agent runs as.

Configuring a key

Configure a way to reach models.

The key is read from standard input rather than taken as a flag, so it is not in the shell history or in what every process on the machine can see:

owl providers add <provider> --key-stdin < key.txt

It is put in the credential store; the database records only that it is there. Configuring a provider that is already configured replaces it, which is how a key is rotated.

A file is only one way to get the key onto standard input, and the least safe: keep it outside every Project so it cannot be committed, and delete it once the provider is configured. Anything that prints the key will do instead, which is what a password manager is for:

pass show anthropic/api-key | owl providers add anthropic --key-stdin

The credential store is the OS keychain where there is one, and a file under the data home readable only by its owner where there is not - a continuous integration runner, say. The daemon’s own configuration chooses, and says which it used in its log at startup (ADR-0019).

There is no other way in. No flag takes a key as an argument, and the desktop app never asks for one, because it is not the process that would hold it.

Anthropic

Owl knows Anthropic’s model list itself, so there is no --model to name when you configure anthropic:

owl providers add anthropic --key-stdin < key.txt

That offers the chat these models:

  • claude-opus-5
  • claude-sonnet-5
  • claude-haiku-4-5-20251001

Requests go to https://api.anthropic.com unless --base-url says otherwise.

OpenRouter

OpenRouter carries models from many vendors and speaks the OpenAI wire shape for all of them, which is why there is no separate openai provider. Which of them your key can reach is your own account’s business rather than Owl’s, so --model is required for openrouter, once per model:

owl providers add openrouter --key-stdin \
  --model anthropic/claude-sonnet-4.5 \
  --model openai/gpt-5 \
  < key.txt

Requests go to https://openrouter.ai/api/v1 unless --base-url says otherwise. A base url has to be somewhere a request can be sent: http or https, with a host, and without a query, a fragment, or a name and password - every request puts a path after it, and a credential in a url would end up in the database and in a listing, which is not where one lives. Owl accepts http as well as https, but the key goes on every request, so http belongs only to something on the same machine, such as a proxy you are running yourself.

Listing and removing

owl providers list

reports each configured provider with the models it offers and, where --base-url named somewhere, that url - (none) for a provider on its own default. It prints nothing else: a key is never printed. With none configured it says so, and how to configure one.

owl providers remove openrouter

stops the chat speaking to a provider and deletes its key from the credential store along with it. Removing one that is not configured exits non-zero and says so.

See also

  • ADR-0019 - Accounts, credentials, and where a secret goes when there is no keychain.
  • ADR-0022 - the desktop chat as a daemon service, and the rules its commands run under.
  • CONTEXT.md - the words Owl uses for the rest of it.

Source: docs/guide/chat-providers.md