Skip to content

Configuration

Janus reads its configuration from a YAML file at ~/.janus/config.yaml. You can print the exact path with:

janus config-path

Generate a template with all sections commented out:

janus config-init

DB-driven configuration

On first startup, Janus seeds SQLite from your YAML file:

YAML section Seeded into
providers providers table
combos combos table
token_savers settings table (saver_* keys)
pricing pricing_overrides table
server.require_api_key settings table (server_require_api_key)

Seeding is idempotent — if a table already has rows, that section is skipped. After seeding, the database is the source of truth. Editing YAML and restarting will not re-apply providers, combos, savers, or pricing.

To manage runtime config:

  • Use the dashboard — changes hot-reload immediately
  • Export Config (GET /dashboard/api/export) — download current DB state as YAML
  • Reset to Defaults (Settings page) — wipe DB tables and re-seed from YAML

Static api_keys in YAML are not seeded — they remain in the config file and are checked at auth time alongside DB-managed keys. YAML static keys always have full access (dashboard login + all models). Scopes (can_login, allowed_models) apply only to DB-managed sk-janus-* keys — see API Reference and the Keys dashboard page.

Runtime settings stored in the settings table:

Key Description
server_require_api_key true / false — overrides YAML default
saver_rtk_enabled RTK token saver on/off
saver_caveman_enabled Caveman saver on/off
saver_ponytail_enabled Ponytail saver on/off
saver_ponytail_level lite, full, or ultra

Environment Variable Resolution

Any value in the YAML may reference environment variables using the ${VAR_NAME} syntax. Variables are resolved at startup — if the variable is unset it expands to an empty string.

providers:
  - id: openai
    api_key: ${OPENAI_API_KEY}

Set them in your shell or .env:

export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-ant-...

server

Controls the HTTP server.

Field Type Default Description
port int 20128 Server port
host str "127.0.0.1" Bind address
require_api_key bool false When true, all API endpoints require auth (except /health). Can be toggled at runtime from the dashboard Settings page (stored in DB).
data_dir Path ~/.janus Directory for the SQLite DB (data_dir/janus.db)
server:
  port: 20128
  host: 127.0.0.1
  require_api_key: false
  data_dir: ~/.janus

Binding to all interfaces

Set host: 0.0.0.0 to accept connections from other machines on your network. Always enable require_api_key when doing so.


providers

A list of provider configurations. Each entry registers one upstream account.

Field Type Default Description
id str (required) Unique provider/account identifier
prefix str (required) URL routing prefix. Multiple configs can share a prefix for multi-account.
api_type str (required) One of: openai_compat, anthropic, gemini, opencode_free
base_url str (required) Upstream API base URL
api_key str \| None None API key for the upstream provider
models list[str] [] Supported model suffixes (used without the prefix)
providers:
  - id: openai
    prefix: openai
    api_type: openai_compat
    base_url: https://api.openai.com/v1
    api_key: ${OPENAI_API_KEY}
    models: [gpt-4o, gpt-4o-mini, o3, o4-mini]

  - id: anthropic
    prefix: anthropic
    api_type: anthropic
    base_url: https://api.anthropic.com
    api_key: ${ANTHROPIC_API_KEY}
    models: [claude-sonnet-4-20250514, claude-opus-4-20250514]

Model naming

Clients reference models as {prefix}/{model} — for example openai/gpt-4o. The models list contains suffixes only (gpt-4o), not the full prefixed name.

See Providers for per-provider setup guides and the full list of supported api_type values.


combos

Named ordered model sequences. A client sends the combo name as the model value and Janus tries each model in order with all its accounts.

Field Type Default Description
name str (required) Combo name (client sends this as the model value)
models list[str] (required) Ordered list of {prefix}/{model} strings to try
combos:
  - name: best-effort
    models:
      - anthropic/claude-sonnet-4-20250514
      - openai/gpt-4o
      - gemini/gemini-2.5-pro

In this example, Janus first tries claude-sonnet-4-20250514 on every Anthropic account. If all are rate-limited or down, it falls back to gpt-4o, then gemini-2.5-pro.


api_keys

A list of static API key strings. These are checked at auth time in addition to DB-managed keys created via the CLI or dashboard.

api_keys:
  - sk-janus-my-static-key
  - sk-janus-another-key

When server.require_api_key is true, requests must include one of these keys (or a DB-managed key) in the Authorization: Bearer <key> header. See API Reference - Authentication for details.

Tip

DB-managed keys (created with janus keys create) are the recommended way to manage keys — they support per-key usage tracking and budgets. Static keys in the config are simpler for single-user setups.


token_savers

Configures token-saving transformations applied to each request after parsing and before provider routing. Savers stack — all enabled ones run in sequence.

Saver Field Type Default Description
rtk enabled bool true Compresses tool output (git diffs, file listings, logs)
caveman enabled bool false Prepends a terse-output system prompt
ponytail enabled bool false Prepends a lazy-dev system prompt
ponytail level str "full" Ponytail verbosity: "lite", "full", or "ultra"
token_savers:
  rtk:
    enabled: true          # default — compresses tool_result content
  caveman:
    enabled: false
  ponytail:
    enabled: false
    level: full            # lite | full | ultra

Fail-safe

Savers are fail-safe — if a saver throws an exception it is caught and logged, never breaking the request.


pricing

User pricing overrides. Keys are model names; values are dicts with per-million-token rates (in USD). On first startup, this section seeds the pricing_overrides table. After that, manage overrides via the dashboard Pricing page or CLI — the YAML section is not re-read on restart.

Rate Key Description
input_per_mtok $ per million input tokens
output_per_mtok $ per million output tokens
cache_creation_per_mtok $ per million cache-creation tokens
cache_read_per_mtok $ per million cache-read tokens
pricing:
  my-custom-model:
    input_per_mtok: 1.0
    output_per_mtok: 3.0
    cache_creation_per_mtok: 0.0
    cache_read_per_mtok: 0.25
  gpt-4o:
    input_per_mtok: 2.5
    output_per_mtok: 10.0
    cache_creation_per_mtok: 0.0
    cache_read_per_mtok: 1.25

Unknown models

Models not found in builtin pricing or overrides cost $0.0 — this is not an error. Add an override if you need cost tracking for an unlisted model.

Pricing uses progressive prefix matching: claude-sonnet-4-20250514 will match a key claude-sonnet-4 if the full name isn't present.


Full Example

server:
  port: 20128
  host: 127.0.0.1
  require_api_key: false
  data_dir: ~/.janus

providers:
  - id: openai
    prefix: openai
    api_type: openai_compat
    base_url: https://api.openai.com/v1
    api_key: ${OPENAI_API_KEY}
    models: [gpt-4o, gpt-4o-mini, o3, o4-mini]

  - id: anthropic
    prefix: anthropic
    api_type: anthropic
    base_url: https://api.anthropic.com
    api_key: ${ANTHROPIC_API_KEY}
    models: [claude-sonnet-4-20250514, claude-opus-4-20250514]

  - id: gemini
    prefix: gemini
    api_type: gemini
    base_url: https://generativelanguage.googleapis.com
    api_key: ${GEMINI_API_KEY}
    models: [gemini-2.5-pro, gemini-2.0-flash]

combos:
  - name: best-effort
    models:
      - anthropic/claude-sonnet-4-20250514
      - openai/gpt-4o
      - gemini/gemini-2.5-pro

api_keys:
  - sk-janus-my-static-key

token_savers:
  rtk:
    enabled: true
  caveman:
    enabled: false
  ponytail:
    enabled: false
    level: full

pricing:
  my-custom-model:
    input_per_mtok: 1.0
    output_per_mtok: 3.0
    cache_creation_per_mtok: 0.0
    cache_read_per_mtok: 0.25