Configure models

Ninja is multi-role. Different agents can use different base URLs, API keys, and model IDs.

Roles

Role Purpose Default settings source
Planner (orchestrator) Plans, delegates tools, main chat OPENAI_* / openai_*
Coder Implements changes NINJA_SUBAGENT_*, else planner
Reviewer Reviews coder work subagent defaults or subagent_roles.reviewer
Final review Product / requirements pass subagent_roles.final_review
Researcher Web research tools only subagent defaults

Environment variables

# Planner
export OPENAI_BASE_URL="https://api.example.com/v1"
export OPENAI_API_KEY="sk-..."
export OPENAI_MODEL="planner-model"

# Default for all subagents (unless overridden per role)
export NINJA_SUBAGENT_BASE_URL="http://localhost:8080"
export NINJA_SUBAGENT_API_KEY="sk-local"   # optional
export NINJA_SUBAGENT_MODEL="coder-model"

Base URL tips

Use an OpenAI-compatible base URL (same idea as popular OpenAI SDKs):

  • Bare host (e.g. http://localhost:8080) — Ninja adds the usual /v1/... chat path
  • Already ending in /v1 — left as-is, then chat path is appended

Local servers often need no API key. Cloud providers need OPENAI_API_KEY (or the matching role key).

Per-role overrides (config.json)

{
  "openai_base_url": "https://api.example.com/v1",
  "openai_api_key": "REPLACE_PLANNER_KEY",
  "openai_model": "planner-model",

  "ninja_subagent_base_url": "http://localhost:8080",
  "ninja_subagent_model": "coder-model",

  "subagent_roles": {
    "coder": {
      "base_url": "http://localhost:8080",
      "model": "coder-model"
    },
    "reviewer": {
      "base_url": "https://api.example.com/v1",
      "api_key": "REPLACE_REVIEWER_KEY",
      "model": "review-model"
    },
    "final_review": {
      "base_url": "https://api.example.com/v1",
      "api_key": "REPLACE_FINAL_KEY",
      "model": "review-model"
    }
  }
}

Useful role fields

Field Meaning
base_url API base
api_key Bearer token (optional for local)
model Model id
max_turns Cap how long a subagent may run
context_window Hint for context sizing (0 = let the provider decide)
persistent Keep that role’s agent available across steps when true

Precedence: role override → NINJA_SUBAGENT_*OPENAI_*.

Interactive /model (TUI)

Command Effect
/model Interactive picker
/model list Text list
`/model set <target> <id\ label>` Override for this session (optionally save to config)

Multi-model plan panel

Optional plan_panel entries power multi-model planning when you use the plan-debate skill. Each model drafts from a different angle, then they critique each other; the planner synthesizes one plan.

Add this to config.json (alongside your normal openai_* / subagent settings):

{
  "plan_panel": [
    {
      "name": "risk-lens",
      "base_url": "https://api.example.com/v1",
      "api_key": "REPLACE_PANEL_KEY_1",
      "model": "strong-reasoner-model",
      "lens": "risk-first"
    },
    {
      "name": "simple-lens",
      "base_url": "https://api.example.com/v1",
      "api_key": "REPLACE_PANEL_KEY_2",
      "model": "another-strong-model",
      "lens": "simplicity-first"
    }
  ]
}
Field Required Meaning
name yes Label for this panel seat (shown in UI/catalog)
base_url yes OpenAI-compatible API base for that model
api_key yes* Bearer key (*optional only if that endpoint needs none)
model yes Model id
lens no Planning bias for that seat (see below)

Lenses

A lens is a short planning bias for one panel model in Round 1. It is not a model id — it only steers how that seat drafts (risk vs simplicity, etc.). Different lenses keep strong models from writing the same plan.

Five built-in defaults (used when lens is omitted — assigned round-robin, then wraps):

Lens Emphasis
risk-first Safety, failure modes, edge cases, rollback
simplicity-first Minimal surface, fewer moving parts
test-first Verification, acceptance checks, testability
performance-first Latency, throughput, resource cost
maintainability-first Clarity, structure, long-term change cost

You can set a custom string (e.g. cost-first); it is passed through as free text. The five names above are the recommended defaults, not a hard allow-list.

Notes:

  • You need at least two working panel models (or Ninja falls back to single-model planning).
  • Panel models can reuse the same gateway as the planner with different model names, or call different providers.
  • After config is saved, ask in chat, e.g. plan the auth refactor with the plan-debate skill.

First-run config.example.json on your machine includes a filled plan_panel block you can copy.

Goal Setup
All local Only OPENAI_* → localhost
Smart plan, fast code Cloud planner + local NINJA_SUBAGENT_*
Stronger review Different model for reviewer / final_review
One gateway (LiteLLM, etc.) Same base_url, different model names