How It Works
How Agent AFK works: session lifecycle, Anthropic and OpenAI provider routing, tool dispatch, terminal states, and the ~/.afk/ state directory layout.
Session lifecycle
Every interaction — a chat, a REPL turn, a daemon tick, or a Telegram message — starts a session that bootstraps, sends your message, dispatches tools, and loops until it finishes.
A session:
- Bootstraps — loads the system prompt (framework base + any operator overlay from
AFK.md,afk.config.json, orAFK_SYSTEM_PROMPT), connects MCP servers in parallel, scans plugins. - Sends a message — the prompt and conversation history are sent to the configured model provider.
- Dispatches tools — when the model requests a tool call, the dispatcher routes it. Pre/PostToolUse
hooks fire sequentially;
decision: 'block'short-circuits execution. - Loops — tool results are fed back to the model, which continues until it stops calling tools or the turn limit is reached.
- Reaches a terminal state — the session emits a
done,error, or interrupted signal.
Provider routing
Agent AFK routes to one of two providers based on the model name:
Anthropic (direct) — default for claude-*, opus, sonnet, haiku, fable. Wraps the
@anthropic-ai/sdk Messages API. Supports extended thinking, prompt caching, and all Anthropic
model features. Two cache_control breakpoints are stamped per request to reduce cost on
long-running sessions.
OpenAI-compatible — default for gpt-*, o1*, o3*, o4*, codex-*, and HuggingFace-style
org/model IDs (e.g., mlx-community/..., Qwen/...). Talks directly to OpenAI's Chat
Completions API, or any compatible local endpoint via baseURL (MLX, llama.cpp, vLLM, Ollama).
Both providers are interchangeable — you can switch between them without changing anything else.
Override provider selection per session:
afk chat "..." --provider anthropic-direct
afk i --provider openai-compatibleTool dispatch
Each session has a fixed set of built-in tools available to the model:
bash,read_file,write_file,edit_file,glob,grep,list_directory— standard agentic toolsweb_scrape— one tool, three modes: fetch a page as markdown, fetch the untransformed response text, or run a web search. There is no separateWebFetch/WebSearch— those names are aliases that normalize toweb_scrape.browser_open,browser_observe,browser_act,browser_screenshot,browser_close— Playwright-backed browser control (navigate, observe, click/fill, screenshot)agent— forks a child session that inherits permissions and stops when the parent stopsskill— dispatches a named skill (built-in or plugin-discovered)compose— Structured multi-agent workflows — define which tasks depend on which; independent ones run in parallel, dependent ones wait. Up to 20 tasks per call; a failure cancels downstream work.memory_search,memory_update,procedure_write— cross-session memory backed by SQLite at~/.afk/state/memory/send_telegram— pushes a terminal-state notification to the operator; no-op if Telegram is unconfiguredconfig_get/config_set— read and edit AFK's own config (~/.afk/config/); secrets are always masked and credential/safety keys are human-gated (see Editing Configuration)- MCP tools — bridged as
mcp__<server>__<tool>from any configured MCP server
MCP servers are loaded from a layered config (plugin-contributed → ~/.afk/config/mcp.json →
<cwd>/.mcp.json → --mcp-config flag). The tool list refreshes in-place when a server emits
notifications/tools/list_changed — no restart needed.
Terminal states
Every turn advances toward one of four terminal states. They are defined by the framework's end-of-turn protocol and enforced on every interactive turn:
| State | Meaning |
|---|---|
| Done | Objective satisfied. Evidence is written to state the user can inspect. |
| Blocked | An external dependency prevents progress. The exact unblock condition is documented. |
| Asking | One precise question is required before the next action. |
| Interrupted | The user halted work. State is preserved for resumption. |
The agent is expected to reach one of these states per turn rather than trailing off. In the REPL, a card appears at the end of each turn showing the outcome.
System prompt layering
The system prompt is always composed of two parts:
- Framework base —
system-prompt.md, inlined at build time. Unconditional; always present. - Operator overlay — appended beneath an
# Operator configurationheader. Resolved in priority order:AFK_SYSTEM_PROMPTenv var (highest)afk.config.json(systemPromptfield)AFK.md(lowest) — additive across two locations:~/.afk/AFK.md(user-scope) and<cwd>/AFK.md(project-scope), both loaded and concatenated when both exist
An absent overlay means the model gets the framework base alone. Overlays append — they never
replace the base. Use --dump-prompt to inspect the fully composed prompt and provenance.
State under ~/.afk/
All AFK state lives under ~/.afk/ — independent of ~/.claude/:
~/.afk/
config/ afk.env, afk.config.json, mcp.json, schedules.json
state/ ($AFK_STATE_DIR overrides this tier)
sessions/ session-store sidecars + per-session event ledgers
todos/ todo-panel data
transcripts/ autosaved REPL session transcripts
daemon/ per-instance daemon state
memory/ cross-session memory (SQLite)
witness/ per-session trace/evidence files (trace.jsonl, prompts/, outputs/)
bg/ background job logs (one subdir per job)
queue/ pull-mode task queue
plugins/ user-installed plugins
skills/ user-authored and generated skills
farms/ Speculative Branch Farm worktrees
logs/
cache/
agent-framework/ telemetry, pattern cards, briefs (JSONL)You can delete ~/.claude/ entirely and Agent AFK still runs.
Permissions
Agent AFK does not prompt before each tool call — there is no per-tool approval flow. The model
runs bash, reads and writes files, fetches URLs, and calls MCP servers without asking each time.
This is intentional: afk is built for unattended work, where a permission prompt with no human
present wedges the session.
The one boundary enforced in the interactive default mode is path containment: a file tool
reaching outside the session's working directory triggers a one-time approval prompt before it
runs. Bypass mode (cycle with Shift+Tab, or the --dangerously-skip-permissions flag) turns containment off entirely;
the afk daemon runs in bypass by default. See Permissions for the
full model — path approval, bash restrictions, autonomous mode, and the env-var knobs.
Use afk on a machine and account you trust. To keep a session's changes contained, run it in an isolated git worktree — your main checkout stays untouched, and the worktree is removed automatically on a clean exit:
afk i --worktreeQuickstart
Install Agent AFK globally via npm, configure your Anthropic API key, and run your first agentic terminal session in under two minutes.
Build with the SDK
Use Agent AFK as a TypeScript library: drive the agent loop with query(), AgentSession, custom tools, subagents, and provider routing from your own code.