Skip to content

Troubleshooting

For anyone whose af is not behaving. After this page you will know which command answers which kind of question, what af doctor can fix on its own, and what to attach when you file an issue.

Start with af doctor

One command covers both halves of "something is wrong":

af doctor --setup   # can this machine create a session at all?
af doctor           # what has accumulated on a machine already running af?

--setup is the first-run profile. It checks AF home writability, config materialization and parsing, git and the current repo, git identity, tmux, your configured agent commands, state and log storage, daemon health, and remote-hook setup when this repo configures one. Run it after installing, and any time a session refuses to start.

Without a flag, doctor runs the maintenance sweep instead — the problems that accumulate silently rather than failing loudly:

  • orphaned processes from sessions that no longer exist, processes that escaped a live session's pane, and processes pegging a CPU core for hours;
  • af_ tmux sessions with no backing session record;
  • abandoned agent-factory homes and daemons under the temp dir, and temp directories holding nothing but a socket nobody answers on;
  • daemon health: control socket, autostart unit, pid file, binary freshness;
  • client/daemon version skew, and the ways a stale daemon survives an upgrade — a second daemon on this home, an autostart unit launching a different af binary than yours, several installs at different versions, sockets left behind with nobody answering;
  • remote-hook setup for the current repo, and pinned host-key directories under hook-hosts/ that no session owns.

af doctor exits 1 when unresolved actionable issues remain or any check stopped before finishing, and 0 when neither is present. An incomplete-only run previously exited 0; it now fails a plain-exit-code health probe without an opt-in flag. The human summary still names unfinished checks after INCOMPLETE. With af doctor --json, inspect data.summary: unresolved > 0 means actionable issues remain; exit status 1 with unresolved == 0 means checks did not finish. summary.incomplete names those checks and can be non-empty in either exit-1 case. It is omitted when empty. Advisory warnings alone still allow exit 0.

Two flags are worth knowing:

  • --verbose shows per-process findings instead of collapsed summaries.
  • --fix applies the safe remediations — killing verified orphans and leaked daemons, removing stale temp homes and dead-socket directories. It is deliberately conservative: a daemon whose binary is merely missing is reported and not stopped, because af upgrade replaces the file in place and every healthy daemon looks that way until it restarts.

--json emits each check in the {data, error} envelope if you want to gate a script on it.

Common situations

A session says Lost or Dead. Its process or worktree went away — after a crash, a reboot, or a worktree someone deleted by hand. Select it and press r, or run af sessions restore <title>. Restore is the right move first; af sessions kill is permanent and takes uncommitted work with it.

A session is idle and you cannot tell why. Every idle row carries the reason the daemon can mechanically establish — usage limit, process exited, no change after delivery, pane changed · 12m ago. It never claims the agent finished or asked a question, because those render identically in a terminal; read the pane to decide. The vocabulary is in the HTTP API guide.

A session is parked on a usage limit. It carries a [limit] badge. Retry it with c in the TUI or af sessions retry-limit <title>, hand the work to a different agent, or turn on auto-resume. See accounts and usage limits. af quota reports what each agent CLI exposes — and says not reported where a provider exposes no quota API, which is af declining to guess rather than a ceiling of zero.

An account handoff says mission delivery could not be confirmed. Inspect the replacement pane because the mission may already have landed. If it did not, choose Retry in the TUI, Retry handoff in the web pane header, or run af sessions retry-limit <title>. af never retries this ambiguous submission on its own, and later prompts do not change that decision.

The web client will not load. The daemon serves it at http://127.0.0.1:8443 by default. Check the daemon is up (af daemon status), that network.listen_addr is not set to "" (which turns the web client off), and that nothing else holds the port. Reaching it from another machine is a different problem — see remote daemon access.

Config edits do not seem to apply. af daemon status reports whether the running daemon has applied the config on disk. af config get <key> --explain shows every candidate layer, whether it was present and allowed, and why it won or lost. Note that a bare af config get reads the current repository's effective config, and falls back to global outside a git repo.

The daemon is wedged, or you upgraded and the old one is still serving. af daemon restart restarts the process and re-adopts existing tmux sessions from persisted state; af daemon adopt hands a detached daemon back to the installed autostart unit. Do not kill -9 a daemon with live sessions.

Where the details are

af debug         # config paths and the effective global config
af version       # client version
af daemon status # liveness, supervision ownership, config freshness

The application log is ~/.config/agent-factory/agent-factory.log (and moves into $AGENT_FACTORY_HOME when that variable is set); per-task watch logs are ~/.agent-factory/logs/task-<id>.log. Both rotate on log_max_size_mb and log_max_backups. The full list is in configuration → where state lives.

Filing a bug

af bug-report

That bundles the daemon log tail, versions, configured tasks, session state, the daemon health snapshot, and your global config — redacted — into one file (~/af-bug-report-<timestamp>.txt), and opens a pre-filled GitHub issue draft against sachiniyer/agent-factory. The draft is never submitted for you: review it, attach the bundle, and click Submit yourself.

Registered account labels (af accounts list) are redacted from both halves of the bundle — the account field on each session record, and the daemon log and config sections that name the same label as text — so a report is no less private through its log than through its records. Your own agent-factory.log is untouched; the labels come out when the bundle is built. If af cannot read the accounts registry it says so in the bundle's collection errors rather than shipping a bundle that only looks redacted.

Include repro steps and expected vs. actual behaviour alongside it.