afk-mode: autonomous agents & ops surface #29
No reviewers
Labels
No labels
agent
blocked
agent
new
agent
review
agent
working
complexity
high
complexity
low
priority
high
priority
low
priority
medium
risk
high
risk
low
risk
medium
type
bug
type
chore
type
feature
type
security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
tfks/fjx!29
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/afk-mode"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Lands the full afk-mode change: agents can run unattended on adaptive cadences with a supervisor daemon, telemetry that survives crashes, per-language container images, and a read-only mobile-first ops dashboard backed by the on-disk telemetry. Spec deltas are folded into
openspec/specs/and the change is archived atopenspec/changes/archive/2026-06-20-afk-mode/.What's new
Supervisor (
fjx supervise) — long-running daemon that drivespm/dev/qaticks across one or more project dirs on adaptive cadences via per-cycle Docker containers. Strict serial execution (one tick in flight, ever), unique per-tick container names, crash recovery, SIGTERM-drains-then-exits, SIGHUP/supervise reloadre-reads each project'sfjx.json. Control socket exposesstatus,pause,resume,kill,reload.Per-project config (
fjx.json) — JSON file at each project root declaringimages.<role>overrides. Forward-compatible: unknown fields preserved.Per-language agent images —
fjx-baseplus language-specific variants, all multi-stage, run as the host user so writes into the mounted repo land with the right ownership; full Claude state is mounted in.Mgmt service (
fjx-mgmt) — Fresh app + MCP endpoint serving cross-project runs, run-detail with stats and avatars, issue browser, dashboards over the per-project telemetry. Read-only at MVP. Auth deferred — deploy on a Tailscale tailnet or VPN-only host. Image built and published by the existingimages.yamlworkflow.Telemetry — JSONL shards per project, optional SQLite index, role/event taxonomy stable enough to drive the mgmt UI. Backfill script for older messages.
Workflow polish —
pm next(renamed frompm tick), four-guard QA handoff trigger, surfaces comments + context when the planner holds an issue, codex one-shot driver for the agent container.Docs
doc/supervise-setup.md— systemd / launchd / tmux recipes for keepingfjx supervisealive, control-socket notes.doc/fjx-json.md— schema reference for the per-project config.doc/mgmt-deploy.md—fjx-mgmtdeployment recipe (env vars, volume mounts, healthcheck, auth-deferral note).doc/cli-reference.md— regenerated forsupervise,telemetry *,<role> release.doc/roadmap.md— autonomous-agents and mobile-UI items marked in flight with back-links.doc/setup.md— links to supervisor setup andfjx.jsonschema from the per-repo install step.Test plan
just validateclean on the branchfjx supervise start <dir>boots, schedules apmtick, drains cleanly on SIGTERMfjx supervise reloadre-reads a modifiedfjx.jsonwithout restartfjx-mgmtcontainer with a read-only mount of a projects dir renders dashboard, runs list, run detail, issue viewfjx-recent-activity,fjx-failed-runs,fjx-token-usage,fjx-stuck-work§10 (backend): Fresh 2 scaffold under top-level mgmt/ with env-driven FJX_PROJECTS_DIR; per-project SQLite reads with on-the-fly JSONL fallback so the operator surface stays honest even when fjx telemetry rebuild hasn't been run; pure marker extractors for the pm:brief and agent-role:ledger HTML-comment markers over the existing ForgejoClient; cross-project discovery from FJX_PROJECTS_DIR. 23 unit tests cover both fallback and indexed reads asserting identical projections, plus marker extraction and config validation. §11 (UI): Tailwind via @fresh/plugin-tailwind + dark-themed Shoelace via CDN. Dashboard rolls active runs, recent failures, stuck runs (telemetry proxy until per-project Forgejo creds land), and tokens-today across discovered projects. Runs list is SSR-only with status/role/since filters; run detail page renders the event timeline and mounts the one justified island — a live-tail that polls an SSE endpoint while the run is still running. Issue view groups briefs and per-role ledgers separately from the other-comments bucket. Four mobile-viewport smoke tests assert width=device-width, the max-width container, no wide fixed-pixel widths, and that the runs list ships no island markers. Tooling: mgmt.just module (just mgmt::{check,test,dev,build}), scoped root just test::units to src/ + scripts/ so the Fresh tree doesn't leak into the CLI's type check, gitignored mgmt/_fresh/ build artifacts. Decision capture: wiki/ard/afk.md records why per-project SQLite stays the right primary — fan-out across projects is cheap at this scale and the rebuildable-from-durable-raw invariant lives naturally inside one project; the supervisor is a writer and has no use for a SQLite at all. Deferred from §11 to follow-ups: stuck-work via canonical agent/working Forgejo label, CI-health panel, mgmt-service auth shape beyond Tailscale + FJX_TOKEN. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>`--name fjx-${role}` collided across concurrent projects and on retry when a previous container hadn't `--rm`'d cleanly, causing `exit 125 — Conflict. The container name "/fjx-pm" is already in use`. Names now include the project name and the tick's runId suffix, so each tick gets a unique container while still being readable in `docker ps`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>Switches the AFK agent runtime from interactive `claude` to one-shot `codex exec`. The container itself is the sandbox boundary, so codex runs with `--dangerously-bypass-approvals-and-sandbox` (skips its bubblewrap layer) + `--skip-git-repo-check`. Auth flows through the existing `~/.codex` bind mount. Also in this commit, because debugging the rollout surfaced them: - Role bootstrap prompts (pm/dev/qa) now lead with an "unattended — stop and report, never wait for Erik" line so codex knows to record a blocker rather than ask a question. - `dockerSpawnFn` dumps the exact `docker run` invocation plus the container's full stdout/stderr to `<project>/telemetry/<container>.{cmd,out,err}` after each tick, so a misbehaving tick is replayable by hand. - `discoverProjects` resolves `project.path` to an absolute path. Relative paths in `-v <name>:/work` are interpreted by docker as named volumes, not bind mounts — which silently mounted an empty volume and made `/work` look like a non-git directory to the agent. - Dockerfile CMD comment updated to reflect the new codex invocation. Adaptive backoff still loses the cycle verb's `code 3 = no-op` signal under the codex wrapper, same caveat as under claude — already documented inline. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>First cut at an AFK mode that utilizes a supervisor to launch agents in a containerto afk-mode: autonomous agents & ops surface