Models and provider fallback
Configure Codex and OpenRouter with explicit privacy and spending limits.
Documentation for Nookins 0.42.1-alpha.1 · Public alpha
Nookins keeps the default model chain, provider permissions and spending limits
in ~/.nookins/config/nookins.yaml. Agent files are in ~/.nookins/config/agents.d/.
The operator interface exposes the same settings in Settings → Overview →
Default reasoning and Settings → Agents. Changing the listening address
requires a restart; changing model policy applies to subsequent work.
OpenRouter starts disabled. A populated example does not send prompts to a new provider. You choose which serving providers may receive prompts and tool results.
1. Store your API key
Create an API key in your OpenRouter account. Edit ~/.nookins/secrets.env locally
and add or replace this entry:
NOOKINS_OPENROUTER_API_KEY=YOUR_ACTUAL_KEYThis is the only key setting Nookins needs for OpenRouter. Keep the file private
(mode 600). Do not put the key in nookins.yaml, an agent file, a chat message,
a screenshot, or a Git commit. Restart Nookins after adding or changing it.
2. Choose serving providers
provider: openrouter selects Nookins’ adapter. model: openrouter/free is the
native router model ID. allowed_providers is different: it lists the companies
behind OpenRouter that you permit to process the request.
Use OpenRouter's provider list
for exact slug values. On an individual model's page, the provider-name copy
button also supplies its exact endpoint slug; see
provider routing.
For the free router, select serving providers that currently offer eligible free
models. A slug is not a model ID: do not put openrouter/free in this list.
To let the free router choose across providers without maintaining a list, set
allowed_providers: ["*"]. The wildcard must appear alone. It explicitly permits
any serving provider that meets the request's privacy, capability and cost
requirements; it does not allow paid inference when both budgets are "0".
Empty lists are invalid. Use named slugs when you want to restrict which companies
receive context. REPLACE_WITH_SERVING_PROVIDER_SLUG below is a placeholder, not
a working provider; replace it with a real slug or "*".
3. Set the main policy and chain
Replace the existing reasoning section in ~/.nookins/config/nookins.yaml with the
following, after replacing the provider placeholder. Do not append a second
reasoning key; Nookins rejects duplicate keys.
reasoning:
model_chain:
- provider: codex
model: default
reasoning_effort: medium
- provider: openrouter
model: openrouter/free
openrouter:
allowed_providers: [REPLACE_WITH_SERVING_PROVIDER_SLUG]
data_collection: deny
zero_data_retention: true
max_run_cost_usd: "0"
max_daily_cost_usd: "0"This attempts Codex first and the free router on eligible availability failures. Both budgets are zero: Nookins allows only requests quoted at zero cost. The daily budget covers all agents combined. The router may choose a different underlying free model for each request; see OpenRouter's free-router contract. Leave the router's reasoning effort at Provider default unless you know an eligible model supports the requested effort.
A free route may not satisfy your provider, tool-support, context-size and privacy
requirements. Nookins fails closed in that case. Changing data_collection or
zero_data_retention changes your privacy policy; it is not a required setup step.
For a paid model, explicitly choose its native model ID and nonzero budgets.
To keep OpenRouter disabled, use the materialized default:
reasoning:
model_chain:
- provider: codex
model: default
reasoning_effort: medium
openrouter: null4. Apply the chain to an agent
Existing agents keep the explicit chains they had before migration. Updating the main default does not replace those chains.
For an agent that should use the main chain, select Use main defaults under Settings → Agents, or set this in that agent's YAML:
model_chain: []An agent with no model_chain also inherits. Remove its openrouter override if
you want it to inherit the main provider policy. Keep a narrower override if that
restriction is intentional. A nonempty agent chain replaces the entire main
chain; to retain an agent's existing Codex choice, append the OpenRouter entry to
that agent's chain instead of choosing inheritance.
Do not change all agents merely to test the integration. Start with the agent whose conversation you want to use.
5. Validate and activate
After editing YAML files:
nookins config validate
nookins config apply
nookins service restart
nookins service status
nookins config statusValidation must succeed before activation. The restart loads the host key; expect all configured roles ready and every configuration projection in sync. In the UI, review and activate the draft, then restart for a changed key.
For a different Nookins home, pass --home /path/to/home before the command. For a
nondefault listening port, pass --url http://127.0.0.1:PORT to commands that talk
to the control API. With an IPv6 wildcard bind, use http://[::1]:PORT. A concrete
non-loopback bind uses that concrete address instead.
6. Test the free router directly
In an owner/trusted conversation with the configured agent:
/model
/model list
/model openrouter openrouter/free/model must show the router in the effective chain. After selecting it, send a
small text request such as “Reply with the word ready.” This makes a real provider
request under your configured policy. No need to exhaust Codex quota to test it.
Restore your normal configured order afterward:
/model autoSelection affects subsequent turns, not a turn already in progress. Automatic fallback stops on refusals, invalid requests, uncertain failures, exhausted Nookins budgets, cancellation, or any failure after a tool was dispatched.
Troubleshooting
| Symptom | What to check |
|---|---|
| OpenRouter is disabled | Main reasoning.openrouter is absent/null. Enable it with real provider slugs and explicit limits. |
/model says the target is unavailable/not authorized | The agent still has an explicit Codex-only chain. Inherit main defaults or add the router to that chain. |
| Authentication fails | Check the key locally in secrets.env, restart, and explicitly activate configuration after repairing credentials to reset the provider circuit. |
| No qualified route / incompatible provider | Check available free models, allowed providers, privacy constraints, tools and context size. Do not silently relax privacy to bypass this. |
| A zero-budget request is rejected | A fixed selected model may be paid, or zero pricing/cost could not be verified. Keep zero budgets for free-only use. |
| The endpoint is rate-limited | Free access still has rate limits. Wait or choose another explicitly authorized target; a restart does not erase provider limits. |
| Changing main defaults had no effect | An agent chain or sticky conversation override still applies. Check /model, the agent file, and /model auto. |
Listener configuration
The complete address belongs in the same main file:
listen: 127.0.0.1:8790Use 0.0.0.0:8790 to bind all IPv4 interfaces, [::]:8790 for IPv6, or a specific
local interface address. Quote IPv6 values in YAML. A wildcard changes which
interfaces accept connections; it does not disable login, bearer authentication
or CSRF protection. Direct HTTP does not encrypt traffic; use an HTTPS reverse
proxy or a protected tunnel when accessing the operator outside a trusted network.
An authored listen value wins. For older files that omit it, Nookins still uses
--listen, then NOOKINS_LISTEN, then 127.0.0.1:8790. Once materialized in YAML,
edit the YAML value. Review and activate the change, then restart; a browser on
the old address will need to open the new one. If changing ports through the CLI,
use the old running URL for config apply and the new URL after restart.
Free models and structured answers
Nookins uses openrouter-rs protocol types and complete JSON responses, with bounded
HTTP reads. For openrouter/free, a final answer may be a private function call
or a JSON object matching the requested schema. Nookins validates the presentation
before publishing it. The private function cannot execute an action; mixing it
with ordinary actions is rejected.
An invalid final format gets at most one formatting-only request, with action tools removed. It keeps the original deadline, privacy rules, and spending limits, and does not repeat completed actions. If that fails, the warning identifies an invalid response format instead of an unknown interruption. Do not replay a request whose actions need reconciliation.
Free capacity and upstream rate limits still apply. An unsupported permitted route fails without relaxing privacy or spending policy. A completed acknowledgement reaction alone is not reported as completed requested work.