Operations, recovery, and resilience¶
The Control Center makes Collie's durable background state inspectable in one place. Open
collie web, then choose Control Center to move between Connected Mode, recovery, Automation Studio, memory,
budgets, and permissions. These views summarize metadata and counts; notification bodies, prompts,
credentials, and private model output are not copied into health reports.
Diagnose before repairing¶
doctor checks packaged/backend version drift, runner compatibility evidence, stale services,
notification backlog age and dead letters, credential expiry metadata, and durable work waiting for
recovery. It is read-only unless --repair names one bounded action. Retrying a dead-letter queue
requires --yes; Collie does not infer that an uncertain external action is safe to replay.
collie doctor --repair test_notifications
collie doctor --repair retry_dead_notifications --yes
collie doctor --repair reprobe_workers
collie recovery ls
collie recovery show <session>
collie recovery reconcile <session> --resolution not_fired --note "checked target" --yes
Recovery reconciliation is an evidence statement made by the operator. completed, not_fired,
and cancel do not mean “try again”; they record what inspection established at the uncertain
boundary so the session can move forward without a blind duplicate effect.
Automation Studio¶
Automation Studio provides reviewable recipes, JSON preview, enable/disable, and manual-run actions
over the same durable automation store used by collie automations. Every recipe freezes its
trigger, context policy, workspace mode, budgets, notification policy, and exact permissions before
it is enabled. A crashed read-only execution can be reclaimed within its retry budget; an expired
lease that may have written externally moves to Needs You. Stale lease tokens cannot publish a
late result.
A finished execution in Needs You keeps asking until somebody says they read it. Mark
reviewed — offered next to Open automation in the recovery lane and next to the run in
Execution history — records that acknowledgement durably for that one execution
(POST /api/automations/review with its execution_id; authenticated, no confirmation dialog,
because it changes nothing outside Collie). It runs, retries and resumes nothing, and the run keeps
its state, error, receipt, saved conversation and history row; only the attention projection stops
counting it. Acknowledgement is per execution on purpose: two daily runs can strand two different
pieces of work, so a later success never speaks for an earlier incident and each new Needs You
arrives unreviewed. A run that is still pending, claimed or running cannot be marked reviewed.
Automation budgets¶
An automation is bounded by its budget, and every key is frozen into the spec when it is saved:
| Key | Default | Meaning |
|---|---|---|
max_wall_s |
1800 | Hard wall-clock ceiling; the child process tree is killed at it. |
max_model_tokens |
200000 | Run token budget, checked against reported usage. |
max_cost_usd |
25 | Run cost budget, checked against reported spend. |
max_actions |
100 | Hard ceiling on tool calls. |
max_runs_per_day |
24 | How often the trigger may start a run. |
max_retries |
1 | Reclaim attempts after a crashed read-only execution. 0 disables retries. |
max_turns |
0 | Optional hard ceiling on model turns. 0 = no turn ceiling. |
The first five must be positive: they are what actually bounds an unattended run, so "unlimited
turns" is only safe while they stay mandatory. Four of them — max_wall_s, max_model_tokens,
max_cost_usd and max_actions — are metered against observed usage during the run. Metered is
not the same as rate-limited: max_runs_per_day bounds how often the trigger may start a run and
is never consumed inside one. Only max_turns and max_retries accept 0. A model response can
cross a token or cost budget before its usage is known. That run stops as Needs You, keeping
its result and usage receipt, including any usage above the configured value.
A separate turn ceiling can stop a task while wall, token and cost budgets remain available:
stop_reason: turn_limit, status Needs You. New automations therefore default to max_turns: 0, and the Automation
Studio editor carries a stored cap through untouched instead of rewriting it. An automation that
already has an explicit positive cap keeps it exactly as written; nothing migrates existing values.
An accepted cap is applied as written, including values above the Settings panel's interactive
turn-cap range, which bounds keyboard surfaces rather than accepted automation budgets.
The Automation Studio editor shows max_runs_per_day, max_model_tokens, max_cost_usd,
max_wall_s and max_actions, and its help names every ceiling that can end a run — including a
turn cap set outside the panel, with the number it carries. max_actions is a tool-call ceiling,
not a turn ceiling: a run that exhausts it stops the same way, so it is editable rather than
implied.
Saving replaces the whole stored record, so the editor starts from the automation exactly as it was
accepted and overlays only the fields the person changed. Everything the form does not show —
context, execution (a plan automation stays a plan automation), notifications, workspace
options, permissions.write_roots/tools/desktop_targets, the remaining budget keys, and the
trigger's predicate and scheduling fields — is carried through unchanged. Choosing a different
trigger type replaces the entire trigger with that type's form values; old predicates and scheduling fields are discarded. Authority follows
the choice that grants it: picking the current workspace or a webhook trigger authorizes it, and
leaving either alone keeps exactly the authority that was accepted, neither widened nor dropped.
Separately from all of this, the loop uses a soft convergence target (50 turns when no cap is set) to decide when to stop exploring, nudge toward a commit, and withdraw exploration tools. That target only changes how the run is steered; it never terminates the work.
Memory review shows proposed, attested, verified, and rejected claims separately. Budget views show limits alongside observed usage rather than treating unknown usage as zero. The permissions view shows authority by surface and target; package publisher trust and package scope approval remain separate decisions.
Failure matrix¶
The deterministic matrix uses only private temporary stores and Collie-owned child processes. It does not contact a model, open the network, modify settings, or kill an unrelated process.
collie resilience scenarios
collie resilience matrix
collie resilience matrix --json --report resilience-matrix.json
The current scenarios exercise:
- notification disconnect, bounded retry, dead letter, explicit retry, and reconnect drain;
- daemon restart, expired automation leases, replay-safe recovery, unsafe-work parking, and stale owner fencing;
- corrupt durable JSON being parked before claim;
- simulated disk-full failure preserving the prior atomic update journal, followed by startup failure escalation to a declared rollback plan;
- extension bytes changing after review and being refused by the exact digest pin;
- an App Server peer ignoring native interrupt, followed by owned process-tree extinction.
Restartable soak¶
# short local qualification
collie resilience soak --duration 10m --interval 30s --report ~/.collie/soak.json
# release qualification
collie resilience soak --duration 12h --interval 5m --report ~/.collie/soak-12h.json
# after a reboot or sleep, repeat the same command/path to resume
collie resilience status --report ~/.collie/soak-12h.json
Every cycle is atomically checkpointed. Reopening an unfinished report resumes it, and a long gap is
counted as a sleep/restart observation. The final status is PASS only when every completed cycle
passed. Implementing this harness is not itself evidence of a 12-hour run; attach the finished JSON
report to a release qualification when that run has actually completed.
Completion and integration contracts¶
Every Mission status response contains summary.completion with exactly five fields:
status, summary, evidence, artifacts, and next_action. A durable done_verified state is
projected as verified only when its stored goal-verification event contains positive independent
evidence; older or incomplete records are shown as accepted. Artifact references come from the
Mission's artifact ledger, not from activity labels or model prose.
The integration library includes two fail-closed boundaries for hosts that embed Collie:
SignedWebhookClientsends bounded JSON only to one exact allowlisted HTTPS host, rejects credential-bearing URLs, redirects, and private/link-local DNS answers, and signs timestamp, nonce, body digest, and idempotency key with HMAC-SHA256.DelegationEnvelopesigns an audience-bound, expiring child scope and refuses any tool, path, network, token, or cost authority broader than its parent.LiveSessionSupervisoradds a bounded pause/resume/cancel/steer/follow-up queue and heartbeat lease without retaining audio, transcripts, credentials, or native process handles.
These are library contracts, not an automatically opened webhook, voice, or A2A network service. An embedding surface must supply the secret, destination allowlist, replay store, and transport explicitly; Collie does not infer or advertise new network authority from their presence.
Update channels¶
collie update --channel stable excludes prereleases. --channel beta considers both prerelease
and stable tags using semantic-version precedence, so a later stable release still supersedes an
older beta. Downloads retain the existing digest and platform-signature checks. A stable release tag
also publishes the wheel and source distribution through PyPI Trusted Publishing once the repository
and workflow are registered as that project's Trusted Publisher and the repository variable
PYPI_PUBLISH is set to true; until then the pypi job is skipped rather than failed. No PyPI API
token is stored in the repository.
The desktop reads the last check from ~/.collie/update-status.json (GET /api/update, which never
waits on the network). A check happens on POST /api/update/check or, with UPDATE_CHECK=on, at
most about once a day in the background; a failed check keeps the last answer and records the error
instead of reporting "up to date". POST /api/update/install is accepted only from a loopback,
non-relayed request on a Windows installer copy. It runs collie update --yes --expect <version>
as a child process, logging to ~/.collie/logs/update-install.log; --expect makes the CLI refuse
(exit 3) unless that exact newer release is still the latest. The Windows handoff then proceeds as
for collie update --yes, and the update journal records the target version so the restarted
server can tell an installed update from one that did not take effect.