Operations¶
apply converges the host to agents.yaml and restarts exactly what changed. Run it after
editing agents.yaml, after apt upgrade agentctl, or to heal drift.
agentctl apply # the whole host
agentctl apply noor # one agent
agentctl apply --dry-run # print the plan, change nothing
apply semantics¶
Reconcilers render the desired output and write only on a diff, and the restart tail bounces
only the agents whose inputs moved. A second apply on an unchanged host is a true no-op: no
writes, no reloads, no restarts.
An agent restarts when its fingerprint moved this run: payload/version, ledger entry, overlay
hash, secrets. It also restarts when it is a local agent paired with a gateway that bounced
this run — the version-skew cascade, teams/slack by channel and webview by user_email.
| flag | effect |
|---|---|
| (none) | reconcile deltas, re-render env/hooks/crons, skip unchanged agents by fingerprint, restart what changed |
--force |
reconcile AND restart every agent and gateway regardless of fingerprint (full base-unit refresh) |
--fast |
deprecated no-op alias; the fingerprint skip is the default. Prints a deprecation note |
--dry-run |
print the plan, including the exact ↻ restart set, and apply nothing |
--prune |
list agents live on the host but no longer in the ledger (orphans) |
--prune --yes |
tear those orphans down: userdel -r plus unit/timer/socket cleanup. Destructive |
--json |
emit the plan or the result as JSON |
[<agent>] |
scope the run to one agent |
A deb-version bump moves every fingerprint and force-bounces the gateways, so a plain apply
after an upgrade reconciles and bounces the whole host on its own.
Host templates propagate to their instances¶
apply runs a host pass and then a per-agent pass, and each pass gates restarts on its own
changed files. A process-scoped record of the host-role dests changed earlier in the same run
carries into the per-agent pass. browser@<agent> declares the template, the private-display
drop-in and the display env as restart inputs.
The record is an event, not a state: it says "the template changed during this apply", not "this unit is older than its fragment".
| case | result |
|---|---|
a shared @ template changes during the run |
every instance restarts on the new command line |
apply dies between the host write and the agent phase |
a stale process the next apply does not correct |
agentctl converge <agent> |
runs no host pass, so it inherits no record |
Troubleshooting¶
agentctl doctor [<name>] is the first stop. It does not print a fixed set of named
states — diagnoseAgent emits a free-text problem string per finding, each with its own
generated fix: line:
⚠ scribe — 2 issue(s)
✗ unit failed/dead
fix: agentctl logs scribe --since '-10 min' ; agentctl agents restart scribe
✗ claude login dead (refresh token expired)
fix: agentctl login claude scribe (or wait for the plugin's self-serve re-login)
Common findings: unit not installed, unit <state>/<substate>,
crash-looping (NRestarts=…), <provider> login dead (…), and
activated MCP "x" is missing its required_env secret "K". Exit code is 1 on any FAIL,
2 on an unresolvable agent name, 0 on WARNs or a clean sweep.
agentctl logs <name> [-f] tails the agent's own output. For the fuller escalation — the raw
systemd unit, a host-wide failed-unit sweep, journal reads for non-agent units, and
cross-host reach — see Troubleshooting.