Autonomy, idle scanner, and safe automation
ContextRelay has an optional automation surface: a way for agents to dispatch read-only helper agents, a daemon-side scanner that can notice idle moments and surface (or, when fully armed, act on) opportunities, and a small ask-for-work nudge that keeps the idle non-coordinator from waiting silently while the coordinator is active. This is the part of ContextRelay where you could spend tokens or let an agent take an action on its own, so this page is deliberately conservative.
Everything described here is off by default. The recommended posture for normal work is to leave it that way. When you do want more automation, turn it up one notch at a time, watch what it surfaces, and never let it cross the human-authority boundary described at the bottom of this page.
- Backup-agent autonomy: off (
autonomy.enabled = false). - Idle scanner: off (
autonomy.idleScanner.mode = "off"). - Idle ask-for-work nudges: configured on by default, but inert until
autonomy.enabled = true. - Autonomous edits (
act:write): off, behind a separate layered gate (see Enabling act:write safely).
None of these turn the others on. Each is an independent, reversible opt-in.
If you have not yet read Read-only by default: safety and containment, start there - it explains the fail-closed model that this page builds on.
The autonomy ladder, at a glance
There are two related-but-separate switches, plus their budgets:
| Switch | Command | Default | What it unlocks |
|---|---|---|---|
| Backup-agent autonomy | ctxrelay autonomy on|off|status | off | Agents may explicitly request read-only backup analysis (ask_codex_backup / ask_claude_backup) and enables idle ask-for-work nudges. |
| Idle scanner | ctxrelay idle-scanner off|suggest|ask|act|status | off | The daemon may surface idle opportunities; ask/act additionally require autonomy on. |
The scanner's ask and act rungs are gated by backup-agent autonomy. Turning the scanner to ask or act while autonomy is off only records suggestions - the CLI will remind you to run ctxrelay autonomy on first.
The idle ask-for-work nudge is separate from the scanner mode. It lives under autonomy.idleScanner.askForWork because it uses the same agent-state model, but it is triggered by daemon state transitions rather than by ctxrelay idle-scanner ask.
Backup-agent autonomy (read-only helpers)
Backup-agent autonomy controls one thing: whether either agent may dispatch an explicit, read-only helper agent for a second opinion. With autonomy on, Claude can call ask_codex_backup and Codex can call ask_claude_backup; either side can inspect results with backup_status.
ctxrelay autonomy status # print the full autonomy config block
ctxrelay autonomy on # allow explicit read-only backup-agent requests
ctxrelay autonomy off # block all backup-agent requests
Backup agents are intentionally limited:
-
Read-only. They run with restricted toolsets and never write files, run git, or take outward actions. The configured
backupModeis"read-only"and there is no setting that makes a backup agent writable. -
Explicit. Nothing dispatches a backup agent on its own. An agent has to ask, in-band, using the documented trigger phrases:
[IMPORTANT] ASK_CODEX_BACKUP: <read-only help request>[IMPORTANT] ASK_CLAUDE_BACKUP: <read-only help request> -
Throttled and bounded. Repeated requests for the same target are rate-limited, and each run is bounded by the read-only idle-action budgets described below.
Enable autonomy when you genuinely want a second, independent read-only pass - for example, "have the other agent sanity-check this diff before I finalize." Leave it off for routine work; a normal handoff or deliberation is usually the better tool, because it keeps both agents in the same conversation rather than spawning a throwaway helper.
The idle scanner
The idle scanner is deterministic and lives in the daemon. Agents do not run it; the daemon derives opportunities from the shared ledger and runtime state when both agents are quiescent and the scanner is armed. It dedupes by opportunity fingerprint and only re-arms on a state change, so it does not chatter.
It has four rungs:
ctxrelay idle-scanner status # show mode, full scanner config, and whether autonomy is on
ctxrelay idle-scanner off # default - the scanner does nothing
ctxrelay idle-scanner suggest # record pull-visible idle_opportunity lanes only
ctxrelay idle-scanner ask # record pull-visible idle_opportunity lanes only (behaves like suggest today)
ctxrelay idle-scanner act # may also dispatch one bounded read-only worker (requires autonomy on)
What each rung does:
off(default): nothing happens.suggest: the daemon recordsidle_opportunitytask lanes in the ledger. These are pull-visible only - no live prompt is pushed at the agents. You (or an agent, when it next reads context) can review them on your own schedule.ask: records the same pull-visible lanes assuggest; no live prompt is pushed. The rung is reserved for a future one-question escalation and behaves likesuggesttoday.act: may additionally dispatch one bounded read-only worker to gather evidence. Requires autonomy on, and the worker is constrained by the idle-action budgets and per-action env caps below. (When the separateact:writesurface is fully enabled,actis also the rung that a contained writable worker can run on - but that is a different, independently gated feature; see Enabling act:write safely.)
The opportunity kinds the scanner can raise are failed_check_no_followup, dirty_tree_finalizable, and claimed_complete_unverified. You can suppress specific kinds with autonomy.idleScanner.disabledKinds, and tune emission with autonomy.idleScanner.advisoryTrigger (owner_waiting by default, or strict for the older dual-idle gate). See the config.json reference for the full structured shape.
Handling an idle-opportunity lane
Treat scanner lanes and any worker output as suggestions and evidence, not instructions. They never act on their own beyond the read-only worker that act may dispatch.
To handle or dismiss a lane, record a reply or note whose handles_handoff_id is set to that lane's id. That marks the opportunity as addressed so the scanner does not keep resurfacing it. An agent does this with reply / append_note (passing handles_handoff_id); you can inspect the open lanes any time with ctxrelay status or the Command Deck (ctxrelay viewer).
suggestBefore you ever move to ask or act, run the scanner in suggest for a while. It costs nothing, pushes nothing at the agents, and lets you see exactly what the scanner would surface in your workflow. Promote to ask/act only once you trust the signal - and remember those rungs need ctxrelay autonomy on as well.
Idle ask-for-work nudges
Ask-for-work is the daemon-side nudge that keeps the non-coordinator engaged.
When autonomy.enabled is true and autonomy.idleScanner.askForWork.enabled is true, the daemon checks whether:
- the configured coordinator is Claude or Codex, not
human; - the coordinator is actively working;
- the other agent is idle;
- no nudge has already been sent during the same idle stretch; and
- the cooldown has elapsed.
If those gates pass, ContextRelay sends this kind of system message to the idle agent:
[IMPORTANT] ASK_FOR_WORK: You appear idle while the coordinator is actively working.
Ask <Coordinator> for the next concrete task now, and include either what you just finished or that you are ready for work.
It works both directions:
- Claude idle + Codex coordinator busy → Claude is nudged to ask Codex.
- Codex idle + Claude coordinator active → Codex is nudged to ask Claude.
Delivery follows the normal live channel for the target: Codex receives an injected message, while Claude receives the nudge through ContextRelay's queued/push channel. The daemon also records an idle_ask_for_work artifact in the ledger.
The default config is enabled with a five-minute cooldown, but global autonomy is off by default, so the feature is inert until you opt into autonomy:
{
"autonomy": {
"idleScanner": {
"askForWork": {
"enabled": true,
"cooldownMs": 300000
}
}
}
}
To disable only this nudge:
{
"autonomy": {
"idleScanner": {
"askForWork": {
"enabled": false
}
}
}
}
Budgets for read-only idle actions
Any read-only idle work the scanner dispatches is bounded by per-daemon-session budgets so it can never run away with your token spend. The defaults are conservative:
| Budget | Default | Meaning |
|---|---|---|
autonomy.idleActionBudgets.tokenBudget | 120000 | Token budget for read-only idle actions in this daemon session. |
autonomy.idleActionBudgets.costBudgetUsd | 1 | USD cost budget for read-only idle actions in this daemon session. |
autonomy.idleActionBudgets.warningPct | 80 | Percentage at which budget-pressure warnings surface. |
Inspect the resolved budgets (config plus any env overrides) and reset the live usage counters:
ctxrelay idle-budget status # show resolved read-only idle-action budgets
ctxrelay idle-budget reset --confirm # reset live usage counters (guarded by --confirm)
reset requires --confirm and is blocked while an idle action is in flight. You can scope it with --runtime-session <id> or get machine output with --json.
Several environment variables override the config values or bound a single worker run. Set these when you want a tighter per-action ceiling than the session budget:
| Variable | Bounds |
|---|---|
CONTEXTRELAY_IDLE_ACTION_TIMEOUT_MS | Wall-clock timeout for one read-only idle act worker. |
CONTEXTRELAY_IDLE_ACTION_TOKEN_BUDGET | Override for idleActionBudgets.tokenBudget. |
CONTEXTRELAY_IDLE_ACTION_COST_BUDGET_USD | Override for idleActionBudgets.costBudgetUsd. |
CONTEXTRELAY_IDLE_ACTION_BUDGET_WARNING_PCT | Override for idleActionBudgets.warningPct. |
CONTEXTRELAY_IDLE_SCANNER | Set to 0 to hard-disable the scanner scheduler regardless of configured mode. |
See the environment variables reference for the complete list and defaults.
Value-probe evaluations (idle-eval)
ctxrelay idle-eval is a manual harness for asking a sharper question: is a parallel fleet actually worth more than a single agent for a given opportunity? It plans, and optionally runs, a single-vs-fleet probe and scores the result deterministically before any human VALUE judgment.
ctxrelay idle-eval status # show the gate env vars and that it is manual-only
# Plan a probe (dry-run by default - records intent, runs nothing live):
ctxrelay idle-eval compare \
--kind dirty_tree_finalizable --owner codex \
--action "summarize the uncommitted diff" \
--why-now "tree is dirty and finalizable" \
--evidence "git status"
compare is dry-run by default. Real, token-spending execution is fail-closed behind several gates at once:
- You must pass
--executeand--max-cost-usd <usd>(a dry run alone never spends). - The environment must opt in with
CONTEXTRELAY_IDLE_EVAL_ENABLED. - A nightly cap,
CONTEXTRELAY_IDLE_EVAL_NIGHTLY_CAP_USD, is required and enforced above the per-session budgets.
Scoring uses configurable thresholds - --quality-margin, --agreement-threshold, and --max-cost-ratio (defaulting to quality margin 0.20, agreement 0.80, and a maximum fleet/single cost ratio of 3.0). The deterministic score is evidence for your decision; it does not record a VALUE verdict on its own.
The dry-run plan is free. The --execute path is for human-approved, pre-registered probes only, and it stays fail-closed until both CONTEXTRELAY_IDLE_EVAL_ENABLED and a valid CONTEXTRELAY_IDLE_EVAL_NIGHTLY_CAP_USD are set. If you are not deliberately running a measurement, do not pass --execute.
The human-authority boundary
This is the line that the automation surface must never cross on its own.
Outside an explicitly dispatched, contained act:write worker, ContextRelay automation must not:
- edit files,
- run git writes (branch, commit, merge, push, PR),
- publish or release,
- kill or restart daemons,
- spend beyond the configured opt-in budgets, or
- take any destructive or outward-facing action,
without human authority. Scanner lanes and worker outputs are suggestions and evidence - treat them as such. Git writes in particular belong to the configured coordinator or the human; see Coordinator and git-write policy.
The only exception is a fully gated, contained writable worker, which lives behind its own separate chain of opt-ins (global autonomy, explicit act config, a positive daily spend cap, strict idle quiescence, and worktree containment). That is documented on its own page so it is never confused with the read-only surface here - see Enabling act:write safely.
Recommended posture
- Leave autonomy and the scanner off for normal work.
- If you want the scanner, enable
suggestfirst and observe what it surfaces before consideringask/act. - Enable backup-agent autonomy only when you specifically want explicit read-only second opinions; remember
ask/actneed it too. - Keep budgets conservative; tighten further with the per-action env caps when in doubt.
- Reserve
idle-eval --executefor deliberate, human-approved, capped measurement runs. - Never let any of this cross the human-authority boundary above.
Next steps
- Read-only by default: safety and containment - the fail-closed model this page builds on.
- Enabling act:write (autonomous edits) safely - the separate, layered gate for contained writes.
- Environment variables reference - every budget, cap, and kill-switch in one place.