Environment variables

Model endpoints

Variable Purpose
OPENAI_BASE_URL Planner API base (default http://localhost:8080)
OPENAI_API_KEY Planner API key
OPENAI_MODEL Planner model id
NINJA_SUBAGENT_BASE_URL Default subagent base
NINJA_SUBAGENT_API_KEY Default subagent key
NINJA_SUBAGENT_MODEL Default subagent model

Prefer NINJA_SUBAGENT_* for workers. (Legacy subagent_* names exist only as config.json keys, not env vars.)

Tool / integration keys

Variable Purpose
NINJA_SERPER_API_KEY Web search (preferred)
SERPER_API_KEY Web search (fallback)

Install / update (optional)

Variable Purpose
NINJA_VERSION Pin version when using install.sh
NINJA_CDN_BASE Force install/update CDN origin (default https://ninja-cli.btaskee.work)
NINJA_NO_UPDATE_CHECK Set to 1 to disable the interactive startup update prompt and headless cache refresh (same as "update_check": false). Does not block ninja update.

The update check is a plain GET of latest.json — no query parameters or identifying payload.

Precedence

Non-empty environment variables override the general config.json fields (openai_*, ninja_subagent_*) for that shell.

OPENAI_MODEL=other-model ninja

Target-specific config beats env: a planner block, subagent_roles.<role> entry, or plan_panel entry always wins over these variables. ninja doctor warns when an env var shadows a config field and shows where each resolved value came from.

Pinning the planner

To stop OPENAI_* from silently overriding your saved planner, put endpoint fields under planner in config.json (not only under openai_*):

{
  "planner": {
    "base_url": "https://api.example.com/v1",
    "api_key": "REPLACE_PLANNER_KEY",
    "model": "planner-model"
  }
}

That block outranks OPENAI_*. Details and the full ladder: config.json → Pinning the planner and Configure models → Pinning the planner.