ctl

Talk to a running agent: pause, silence, reload, trigger, fire.

nanook ctl is a thin client for the admin server of a running agent. Use it to pause a noisy collector, silence a rule during a deploy, or hot-reload the config without restarting.

How it connects

ctl reads the same nanook.toml to find the admin endpoint. Unix socket first (if [admin].socket is set), then HTTP.

Override per-invocation:

nanook ctl --addr 127.0.0.1:9091 state
nanook ctl --socket /run/nanook.sock state

Operations

state

Print the current engine state: every collector and its status, every rule and its trigger count, every silence in effect.

nanook ctl state

reload

Re-read nanook.toml from disk and apply the diff. Collectors, adapters, channels, and rules hot-swap. No process restart. reload refuses a config that fails validation; nanook check surfaces the same diagnostics without touching the running agent.

nanook ctl reload

silence <expr> [duration]

Mute a rule for the given duration (default 1h). Accepts s, m, h, d suffixes and combinations like 1h30m. The expr must match what's in nanook.toml (whitespace is normalized).

nanook ctl silence "cpu.usage > 90%"
nanook ctl silence "disk.usage > 95%" 10m

unsilence <expr>

Lift a silence early.

nanook ctl unsilence "cpu.usage > 90%"

pause <name>

Stop a collector from polling. Existing samples stay in the window store; no new ones come in. Rules whose selectors only reference this collector go quiet.

nanook ctl pause cpu

resume <name>

Bring a paused collector back.

nanook ctl resume cpu

trigger <name>

Fire one read manually, regardless of interval. Useful for confirming a config change without waiting.

nanook ctl trigger api

fire <name>

Force a rule to fire its action right now, regardless of the current metric state. Looks up the rule by its name field, falling back to the raw expression text. Bypasses eval, silences, and cooldown so the action layer runs even when the rule would not match. Use it to smoke-test a notification channel after wiring up a webhook, Discord ID, or exec script.

nanook ctl fire hot-cpu
nanook ctl fire "cpu.usage > 90%"

The fire counter on nanook ctl state ticks up, just as it does for an organic fire.

eval <expr>

Evaluate an expression against the engine's current state and print the typed result. Reuses the same parser, resolver, and window store the rule layer walks, so anything that works in a [[alerts]] expr is fair game — boolean comparisons, arithmetic, aggregates, label filters.

nanook ctl eval 'cpu.usage > 90'
nanook ctl eval 'avg(cpu.usage)[5m]'
nanook ctl eval 'env'                       # bare text-typed selector
nanook ctl eval 'nanook.engine.dropped'      # engine self-metric

Output groups the expression and the typed value:

eval:
  • expr  cpu.usage > 90
  • bool  true

The verb is read-only — no rule state is touched, no silences are evaluated, no triggers fire. Rule-context selectors (with_trigger, with_firing, firing("...")) have no meaning outside a rule pass and return runtime errors.

Parse errors surface miette spans against your expression. Runtime errors (missing metric, ambiguous selector, dimensional mismatch) propagate from the resolver unchanged.

Patterns

Maintenance window

# silence anything that might page during the deploy
nanook ctl silence "disk.usage > 95%" 30m
nanook ctl silence "api::http.status is \"false\"" 30m

# do the work...

# bring them back early if it went well
nanook ctl unsilence "disk.usage > 95%"
nanook ctl unsilence "api::http.status is \"false\""

Hot-edit the config

vim nanook.toml
nanook check && nanook ctl reload

Drain a collector before removing

nanook ctl pause flaky-probe
# observe, edit config, remove the collector
nanook ctl reload

Authorization

ctl signs every request with an Ed25519 key. Default key path is ~/.nanook/admin/id_ed25519, override with $NANOOK_IDENTITY or --identity (-i). The server gates signed requests against [admin].authorized / authorized_keys.

nanook keygen                                      # one-time, writes ~/.nanook/admin/id_ed25519{,.pub}
nanook ctl --identity ~/.nanook/ops_key state       # per-invocation override
NANOOK_IDENTITY=~/.nanook/ops_key nanook ctl state   # env var override

Hand id_ed25519.pub to whoever runs the agent so they can add it to [admin].authorized or append it to the authorized_keys file.

The Unix socket is a fine alternative for loopback: set [admin].socket and lock the parent directory with filesystem perms. See Admin server for the full auth scheme, headers, and error codes.