11
Clients
Alex Clarke edited this page 2026-08-14 15:37:08 -06:00

Coyote supports a large number of model providers (referred to as clients since Coyote is a client of these providers). In order to use them, you must configure each one in the clients array in the global Coyote configuration file.

The location of the global Coyote configuration file varies between systems, so you can use the following command to locate your configuration file:

coyote --info | grep 'config_file' | awk '{print $2}'

Supported Clients

Coyote supports the following model client types:

  • Azure AI Foundry
  • AWS Bedrock
  • Anthropic Claude
  • Cohere
  • Google Gemini
  • OpenAI
  • OpenAI-Compatible (e.g. Ollama)
  • GCP Vertex AI

In addition to the settings detailed below, each client may have additional settings specific to the provider. Check the example global configuration file to verify that your client has all the necessary fields defined.

Client Configuration

Each client in Coyote has the same configuration settings available to them, with only special authentication fields added for specific clients as necessary. They are each placed under the clients array in your global configuration file:

clients:
  - name: client1
    # ... client configuration ...
  - name: client2
    # ... client configuration ...

Metadata

The client metadata uniquely identifies the client in Coyote so you can reference it across your configurations. The available settings are listed below:

Setting Description
name The name of the client (e.g. openai, gemini, etc.)
auth Authentication method: oauth for OAuth, or omit to use api_key (see Authentication)
models See the model settings documentation below
patch See the client patch configuration documentation
extra See the extra settings documentation below

Be sure to also check provider-specific configurations for any extra fields that are added for authentication purposes.

Model Settings

The models array lists the available models from the model client. Each one has the following settings:

Setting Required Model Type Description
name * all The name of the model
real_name all You can define model aliases via the name field. However, Coyote still needs to know the real name
of the model so it can query it. For example: If you have name: gpt-alias, then you must
also define real_name: gpt-oss:latest
type * all The type of model. Coyote supports only 3 types of models:
  • chat
  • embedding
  • reranker
input_price all The cost in USD per 1M tokens for each input sequence; Coyote will keep track of usage costs if this is defined
output_price all The cost in USD per 1M tokens of the model output; Coyote will keep track of usage costs if this is defined
patch all See the model-specific patch configuration documentation
max_input_tokens all The maximum number of input tokens for the model
max_output_tokens chat The maximum number of output tokens for the model
require_max_tokens chat Whether to enforce the max_output_tokens constraint.
supports_vision chat Indicates if the model supports multimodal queries that would require vision (i.e. image recognition)
supports_function_calling chat Indicates if the model supports function calling
reasoning_levels chat A list of named reasoning effort levels the model accepts (e.g. [low, medium, high]). When non-empty, .reasoning and .set reasoning_effort become available in the REPL for this model
default_reasoning_effort chat The effort level applied by default when reasoning_levels is non-empty and no explicit override is set. Must be one of the values listed in reasoning_levels
no_stream chat Enable or disable streaming API responses
no_system_message chat Controls whether the model supports system messages
system_prompt_prefix chat An additional prefix prompt to add to all system prompts to ensure consistent behavior across all interactions
max_tokens_per_chunk embedding The maximum chunk size supported by the embedding model
default_chunk_size embedding The default chunk size to use with the given model
max_batch_size embedding The maximum batch size that the given embedding model supports

Authentication

Coyote clients support two authentication methods: API keys and OAuth. Each client entry in your configuration must use one or the other.

API Key Authentication

Most clients authenticate using an API key. Simply set the api_key field directly or inject it from the Coyote vault:

clients:
  - type: claude
    api_key: '{{ANTHROPIC_API_KEY}}'

API keys can also be provided via environment variables named {CLIENT_NAME}_API_KEY (e.g. OPENAI_API_KEY, GEMINI_API_KEY). See the environment variables documentation for details.

OAuth Authentication

For providers that support OAuth, you can authenticate using your existing subscription instead of an API key. This uses the OAuth 2.0 PKCE flow.

Step 1: Configure the client

Add a client entry with auth: oauth and no api_key:

clients:
  - type: claude
    name: my-claude-oauth
    auth: oauth

Step 2: Authenticate

Run the --authenticate flag with the client name:

coyote --authenticate my-claude-oauth

Or if you have only one OAuth-configured client, you can omit the name:

coyote --authenticate

Alternatively, you can use the REPL command .authenticate.

This opens your browser for the OAuth authorization flow. Depending on the provider, Coyote will either start a temporary localhost server to capture the callback automatically (e.g. Gemini, OpenAI) or ask you to paste the authorization code back into the terminal (e.g. Claude). Coyote stores the tokens in <coyote_cache_dir>/coyote/oauth and automatically refreshes them when they expire.

Step 3: Use normally

Once authenticated, the client works like any other. Coyote uses the stored OAuth tokens automatically:

coyote -m my-claude-oauth:claude-sonnet-4-20250514 "Hello!"

Note: You can have multiple clients for the same provider. For example: you can have one with an API key and another with OAuth. Use the name field to distinguish them.

OpenAI OAuth Note

OpenAI OAuth requires a ChatGPT Plus or Pro subscription. It uses the shared Codex CLI OAuth app registered with OpenAI, so no additional API credentials or app registration are needed.

When authenticating, Coyote starts a localhost server on port 1455 to capture the OAuth callback automatically. This port is fixed by OpenAI's app registration and cannot be changed. Make sure port 1455 is available when you run --authenticate/.authenticate.

When auth: oauth is set and no api_base is configured, Coyote automatically routes all requests through chatgpt.com/backend-api/codex/responses (the OpenAI Responses API), which is what ChatGPT Plus/Pro subscribers have access to. If you later add an api_key or a custom api_base, Coyote will use the standard api.openai.com/v1 endpoint instead.

Example configuration:

clients:
  - type: openai
    name: openai-oauth
    auth: oauth

Gemini OAuth Note

Coyote uses the following scopes for OAuth with Gemini:

Since the generative-language.retriever scope is a sensitive scope, Google needs to verify Coyote, which requires full branding (logo, official website, privacy policy, terms of service, etc.). The Coyote app is open-source and is designed to be used as a simple CLI. As such, there's no terms of service or privacy policy associated with it, and thus Google cannot verify Coyote.

So, when you kick off OAuth with Gemini, you may see a page similar to the following:

Simply click the Advanced link and click Go to Coyote (unsafe) to continue the OAuth flow.

xAI OAuth Note

xAI OAuth requires a SuperGrok or X Premium+ subscription. Coyote ships with the required OAuth endpoints and client ID bundled in models.yaml, so you can enable OAuth by just adding auth: oauth to your xAI client entry. No additional endpoints or app registration needed.

When authenticating, Coyote starts a localhost server on port 56121 to capture the OAuth callback automatically. This port matches what xAI's OAuth app expects and cannot be changed. Make sure port 56121 is available when you run --authenticate/.authenticate.

If the authorization succeeds but the token exchange returns 403, that indicates your account does not have a valid SuperGrok / X Premium+ subscription. This is not a Coyote configuration error.

Example configuration:

clients:
  - type: openai-compatible
    name: xai
    api_base: https://api.x.ai/v1
    auth: oauth

OAuth for OpenAI-Compatible Providers

For any provider that speaks the OpenAI API shape (type: openai-compatible), you can enable OAuth by setting auth: oauth and configuring an oauth: block. This section is your reference for what fields each OAuth flow needs.

Not needed for built-in providers (Claude, Gemini, OpenAI, xAI-when-using-bundled-defaults): those work with just auth: oauth, meaning no fields are required. See the provider-specific notes above for details.

Which flow does my provider use?

Look at your provider's own login docs or CLI for signal words:

What your provider does Flow to configure Section
Opens your browser, redirects to a http://localhost or http://127.0.0.1 URL Authorization Code + PKCE (loopback callback) Flow 1, Mode A
Opens your browser, redirects to a https://... URL you'd copy from the address bar Authorization Code + PKCE (browser-paste) Flow 1, Mode B
Displays a short user code you enter at a URL, with no browser callback Device Authorization Grant (RFC 8628) Flow 2
No user at all; just client_id + client_secret exchanged headlessly Client Credentials (RFC 6749 §4.4) Flow 3

If your provider's OAuth app is already registered with a specific redirect URI, Coyote's routing follows it: put the value in redirect_uri and Coyote does the right thing based on the URL shape (loopback vs public).

Flow 1: Authorization Code + PKCE

Standard OAuth 2.0 with PKCE (RFC 7636). Coyote opens the authorize URL in your browser, receives back an authorization code, and exchanges it for tokens. Refresh tokens are supported (silently refreshed on expiry).

Coyote picks between two delivery modes automatically based on what you set for the callback:

Mode A: Loopback callback (Coyote listens on your machine)

Coyote binds a TCP listener on 127.0.0.1 and the browser redirects there directly. This is the smoothest UX (i.e. no manual copy/paste), but requires that the provider's OAuth app allows a loopback redirect URI.

Required fields:

  • flow: pkce (or omit. This is the default)
  • client_id: your OAuth app's client ID
  • authorize_url: where the browser goes to authorize
  • token_url: where Coyote exchanges the code for tokens

Callback config (pick one):

  • redirect_port: <u16>: if the provider registered a specific port (e.g. 56121 for xAI). Coyote synthesizes http://127.0.0.1:<port>/callback.
  • redirect_uri: http://127.0.0.1:<port>/<path>: full custom loopback URL (overrides redirect_port).
  • Omit both: Coyote picks an ephemeral port on 127.0.0.1 (only works if the provider allows arbitrary loopback ports).

Optional fields:

  • scopes: [scope1, scope2]: space-joined into the scope= query param.
  • extra_authorize_params: { key: value }: extra query params on the authorize URL (e.g. xAI needs plan: generic).
  • echo_pkce_in_token_exchange: true: some providers (like xAI) require re-sending code_challenge on token exchange.
  • include_state_in_token_exchange: false: some providers reject state on the token endpoint (default true).
  • token_request_format: form_url_encoded: some providers require form-encoded token bodies (default is form_url_encoded for openai-compatible).
  • client_secret: rare with PKCE, but supported for hybrid setups.

Example:

clients:
  - type: openai-compatible
    name: my-provider
    api_base: https://api.provider.com/v1
    auth: oauth
    oauth:
      client_id: '{{PROVIDER_CLIENT_ID}}'
      authorize_url: https://auth.provider.com/oauth/authorize
      token_url: https://auth.provider.com/oauth/token
      redirect_port: 8765
      scopes: [read, write]

Mode B: Browser-paste (you paste the callback back into the terminal)

For providers whose OAuth app is registered with a public HTTPS URL (not loopback). The browser redirects to that URL, the provider's page displays the code (or you copy it from the URL bar), and you paste it back into Coyote.

Coyote detects Mode B automatically when redirect_uri is set to a non-loopback URL (anything other than 127.0.0.1, localhost, or ::1). No opt-in flag needed.

Required fields: same as Mode A above, except the callback config:

  • redirect_uri: https://<provider-callback-host>/<path>: the exact URL the provider is registered with.

What Coyote accepts at the paste prompt:

  1. Full callback URL from the browser bar (e.g. https://provider.example.com/callback?code=abc&state=xyz). Coyote parses code and state from the query string.
  2. <code>#<state> fragment (Anthropic-style; supported for provider pages that display both concatenated).
  3. Bare code (just the authorization code, no state). Accepted with a warning. CSRF state validation is skipped. Use this for providers whose callback page shows only the code.

Example:

clients:
  - type: openai-compatible
    name: my-hosted-provider
    api_base: https://api.provider.com/v1
    auth: oauth
    oauth:
      client_id: '{{PROVIDER_CLIENT_ID}}'
      authorize_url: https://auth.provider.com/oauth/authorize
      token_url: https://auth.provider.com/oauth/token
      redirect_uri: https://provider.com/oauth/callback   # public URL -> paste mode
      scopes: [read]

Flow 2: Device Authorization Grant (RFC 8628)

For CLIs and headless environments: no browser callback required. Coyote displays a short user_code and a verification_uri. You visit the URL on any device (phone, another laptop, or the same browser Coyote tries to open) and enter the code to approve. Coyote polls the token endpoint until you approve or the code expires. Refresh tokens are supported.

Required fields:

  • flow: device_code
  • client_id: your OAuth app's client ID
  • device_authorization_url: where Coyote requests the initial user_code
  • token_url: where Coyote polls for the token

Optional fields:

  • scopes: [scope1, scope2]
  • use_pkce_in_device_flow: true: some providers (like MiniMax) require PKCE with device flow. Coyote generates a fresh code_verifier + code_challenge (S256) on each authentication.
  • token_request_format: form_url_encoded: usually needed for device flow (default for openai-compatible).
  • extra_token_headers: { key: value }: custom headers applied to both device and token endpoints.
  • client_secret: rare but supported.

Example:

clients:
  - type: openai-compatible
    name: my-device-flow-provider
    api_base: https://api.example.com/v1
    auth: oauth
    oauth:
      client_id: '{{MY_CLIENT_ID}}'
      device_authorization_url: https://auth.example.com/oauth/device_authorization
      token_url: https://auth.example.com/oauth/token
      flow: device_code
      scopes: [openid, profile]

Sandbox bonus: when IS_SANDBOX=1 (set automatically by coyote --sandbox), Coyote renders a scannable QR code in the terminal so you can point your phone camera at the verification URL and complete the flow in seconds.

Flow 3: Client Credentials (M2M)

For headless machine-to-machine authentication. No user, no browser. Coyote POSTs directly to the token endpoint with client_id + client_secret. Best for CI, servers, agent runtimes.

Required fields:

  • flow: client_credentials
  • client_id
  • client_secret
  • token_url

Optional fields:

  • scopes: [scope1, scope2]
  • token_request_format
  • extra_token_headers: { key: value }

Example:

clients:
  - type: openai-compatible
    name: acme-gateway
    api_base: https://gateway.acme.com/v1
    auth: oauth
    oauth:
      client_id: '{{ACME_CLIENT_ID}}'
      client_secret: '{{ACME_CLIENT_SECRET}}'
      token_url: https://auth.acme.com/oauth/token
      scopes: [openai.chat]
      flow: client_credentials

Note on refresh: RFC 6749 forbids refresh tokens for this flow. When the access token expires, Coyote silently re-runs the client credentials exchange (still no browser or user interaction).

Providers with Bundled OAuth Defaults

Coyote ships OAuth defaults for the following providers, so you only need auth: oauth in your config, with no fields required:

  • xAI: SuperGrok / X Premium+ subscribers. See xAI OAuth Note above for behavior details.

To bundle defaults for additional providers locally, edit your models.yaml (see Local Models Override) and add an oauth: block under the provider entry using the field reference for the appropriate flow above.

Configuration Precedence

Coyote resolves OAuth configuration in two layers:

  1. Bundled defaults in models.yaml under provider: <name>.
  2. Inline overrides in your config.yaml under clients[i].oauth.

Per-field: config.yaml wins over models.yaml. If neither source provides a required field for your flow (see the "Required fields" list in each flow section above), Coyote bails with a clear error at authentication time telling you which field is missing.

You can override individual fields. For example, if the bundled default has the wrong token URL for your corporate gateway, just set oauth.token_url inline and the rest of the bundled defaults still apply.

Known Limitation: Token Namespacing

OAuth tokens are stored on disk at ~/.cache/coyote/oauth/{client_name}_oauth_tokens.json, keyed by the client's name field only (not by provider type). Two clients with the same name, even if they use different provider types, will overwrite each other's tokens.

To prevent accidental collisions, Coyote rejects configuration files with duplicate name values across all clients[] entries at load time. Fixing the underlying single-namespace layout is future work.

Sandbox and headless environments

When Coyote runs inside a sandbox (coyote --sandbox), your host OAuth tokens (~/.cache/coyote/oauth/) are copied into the container so agents can call OAuth-authenticated providers without re-authenticating. If you do need to authenticate from inside a sandbox:

  • Flow 2 (Device Grant) works out of the box. Coyote prints a QR code you can scan with your phone camera.
  • Flow 3 (Client Credentials) works fine (no browser or callback needed).
  • Flow 1 Mode A (loopback callback) generally cannot complete because the loopback listener binds inside the sandbox's network namespace, unreachable from the host browser.
  • Flow 1 Mode B (browser-paste) works if you can open the authorize URL in a browser somewhere and paste back.

Recommendation: authenticate on the host first and let the sandbox token copy carry you through.

Providers That Support OAuth

Built-in providers: (just set auth: oauth, no fields required):

Any OpenAI-compatible provider: Configured inline via an oauth: block. Coyote supports all four common flows: Authorization Code + PKCE (loopback callback OR browser-paste), Device Authorization Grant (RFC 8628), and Client Credentials. See OAuth for OpenAI-Compatible Providers for the field reference for each flow.

Extra Settings

Coyote also lets you customize some extra settings for interacting with APIs:

Setting Description Default
proxy Set a proxy to use -
connect_timeout Timeout in seconds for establishing a connection to the API 10
read_timeout Stall detector: maximum seconds allowed between successive reads from the API before the request is aborted.
Streaming-safe; the clock resets on every chunk received, so long streaming responses are fine as long as data keeps flowing.
Set to 0 to disable entirely (e.g. for very slow local models or large non-streaming embedding calls).
300
clients:
  - type: openai
    extra:
      proxy: socks5://127.0.0.1:1080
      connect_timeout: 10
      read_timeout: 300

Note

Before read_timeout existed, a connection that stalled after connecting (e.g. a streaming response that silently stopped mid-stream) would hang Coyote indefinitely. The default now aborts any request that goes 300 seconds without receiving a single byte.