Skip to content

Glossary

The canonical terms used throughout AFK. This is the source of truth for the project’s vocabulary; implementation details live in the Backend docs.

The unit of work in this system. A Run is one ephemeral execution of a developer-defined command (typically, but not necessarily, an AI agent) inside a container in the cloud.

A Run has a bounded lifetime: it starts when its entrypoint command begins and ends when that command exits. While alive, a developer may optionally attach to observe or intervene; attach is not required for a Run to be useful.

A Run is backed by exactly one compute primitive in the active Backend: an EC2 instance on AWS, a Container instance on Cloudflare, etc. The Run’s workload executes as one or more containers — on the VM’s host Docker daemon on AWS, or inside rootless dind on Cloudflare. When the Run ends its compute primitive is either reclaimed immediately or, on Backends that support Retention, held in a retained state until resumed or reclaimed. The compute primitive is the implementation; the Run is the concept the developer interacts with through the CLI (afk run, afk attach <run>, afk logs <run>, afk kill <run>).

Not to be confused with: an EC2 instance / Container instance (provider resources), a TodoWrite task (work item inside an agent), or an agent sub-task (delegated work inside Claude).

A Run launched with no developer command, for the purpose of being attached into and driven by hand rather than executing an autonomous workload. Started by afk session — the interactive counterpart to afk run <command>, which executes a developer-defined command to completion.

An Interactive Run is a Run in every structural sense: backed by exactly one compute primitive, owned by its launcher, cloning source into /workspace, streaming logs, bounded by a timeout, reclaimed by afk kill. It differs only in what occupies its command slot and therefore in how it ends. An ordinary Run carries the developer’s command and ends when that command exits; an Interactive Run carries an afk-supplied keep-alive in that slot, so nothing exits on its own — it stays live until the developer ends it with afk kill or its timeout backstop fires. afk attach is the entire point of an Interactive Run, not the optional observation it is for an ordinary Run.

Because it is just a Run, an Interactive Run inherits the capacity and end-of-life story of its Backend — with one default flipped: a Spot reclaim would kill a session mid-keystroke, so an Interactive Run defaults to On-Demand (see Spot).

Not to be confused with a retained Run (post-mortem inspection of a Run that has already ended) — an Interactive Run is live the whole time it is attachable; its command never ran to completion because there was no command to run.

The fully-resolved description of a Run before any compute primitive is launched: the resolved image, Ref, command, timeout, environment, secret references, and (if present) the linted Compose Contract graph. A Run Plan is the output of resolving a developer’s request against afk.config.json and the built image — deterministic and side-effect-free to compute.

It is the thing afk run --dry-run prints: the developer sees exactly what would launch without anything being launched. The Backend is split so this resolution (prepare) is separable from the irreversible launch step, and the backend-neutral core of the plan (env, secrets, timeout, compose) is assembled identically regardless of Backend; only the launch-vehicle specifics (instance type/tier, boot script, registry coordinates) are filled in per-Backend.

Not to be confused with the launch itself: a Run Plan describes intent; launching it creates the compute primitive that makes it a live Run.

After a Run ends, a Backend may retain its compute primitive instead of reclaiming it: the primitive is stopped but preserved, holding the finished workload’s state. A retained Run does no work — its command has already exited — but can be resumed: afk attach on a retained Run brings the compute primitive back up and drops the developer into it to inspect the post-mortem state. Resume lasts only for the duration of that attach session — when the developer detaches, the primitive returns to the retained state, so a finished Run’s one resting state is always retained.

Resuming revives only the compute primitive, never the workload — the Run has already ended, so resume re-animates the host so attach has something to enter; it does not re-run the developer’s command. A retained Run is reclaimed explicitly by afk kill, or automatically once it is older than the configured retention period (default 7 days) — so retained is a bounded grace window, not permanent storage.

Realized automatically on the Local Backend, where every Run is retained — Local runs on no capacity-pricing model, so retaining a finished container is free. On AWS and GCP retention is available but opt-in and On-Demand-only: afk run --retain stops the instance instead of terminating it when the Run ends, preserving its disk for later afk attach. It requires On-Demand capacity because Spot cannot be stopped without losing its disk — so --retain implies On-Demand, and a Spot Run can never be retained. Because a stopped instance still bills for its disk, retention is off by default and bounded by the retention period. Cloudflare cannot retain at all — its Container instances are ephemeral, so a restarted one is a clean slate rather than preserved post-mortem state, the opposite of what retention promises.

Post-mortem inspection of a finished cloud Run is therefore available only when it was launched with --retain (AWS/GCP); otherwise, and always on Cloudflare, afk attach enters only a Run that is still live (its command has not yet exited). To carry state past a non-retained cloud Run’s end, declare a Session Artifact.

Not to be confused with a suspended or paused Run (there is no such state — a Run that has ended has ended) or with afk kill (which reclaims, the opposite of retain).

The capacity model a cloud Run launches under. Spot is interruptible, heavily discounted capacity the provider may reclaim at any time (an AWS Spot instance, a GCP SPOT VM); On-Demand is full-price capacity the provider does not reclaim. A cloud Run defaults to Spot — the common case is cheap and disposable — and --on-demand opts up to On-Demand.

The choice changes two things: interruption risk and retention eligibility. Interruption risk: a Spot reclaim kills a live Run mid-flight, so a long or fragile Run pays for On-Demand to avoid that. Retention eligibility: only On-Demand capacity can be stopped without losing its disk, so Retention (post-mortem afk attach via --retain) is available only on an On-Demand Run — a Spot Run can never be retained and always self-terminates on exit. By default neither is retained; On-Demand additionally permits --retain. Spot is a cloud-only concept; the Local Backend has no capacity model.

Not to be confused with Retention itself: capacity is what makes retention possible, but a plain On-Demand Run without --retain still self-terminates on exit. Orthogonal to the Golden Image (the boot artifact, independent of how the instance is purchased).

A provider-specific implementation of the operations a Run depends on: launching a container, attaching an interactive shell, streaming logs, terminating. The CLI is written against a Backend interface so the user-facing surface (afk run, afk attach, …) stays identical across providers.

The persisted Backend in afk.config.json (set by afk init --provider <name>) is the default for every command. The Local Backend is special in being reachable through two channels: it can be the persisted Backend (afk init --provider local) like any other, and a per-command --local flag selects it for that invocation only regardless of the persisted Backend.

The four shipped Backends — AWS EC2, GCP Compute Engine, Cloudflare Containers, and Local — plus the anticipated Azure Backend are detailed in the Backends overview.

The developer principal that launched a Run. The form of the principal is Backend-specific — an IAM userid on AWS, a Cloudflare Access service-token client-id on Cloudflare, the authenticated gcloud account on GCP — but the role is the same: it scopes what the developer can see, attach to, or terminate. The Owner is recorded on the underlying compute primitive (an afk:owner EC2 tag on AWS, a metadata field on the launcher Worker’s run registry on Cloudflare, an afk-owner label on the Compute Engine instance on GCP). A developer is normally only permitted to act on Runs whose Owner matches their own principal; team-wide views (afk ls --all) are a separate, broader permission.

The set of rules a developer’s afk.Dockerfile must follow for their image to be usable as a Run. The file lives at the repo root and is named afk.Dockerfile to namespace it away from any other Dockerfile the project uses for its own deployment. It installs the toolchain and dependencies needed by the Run’s command, but does not copy the source code (the source is cloned at Run start by the entrypoint). The entrypoint script is owned by the CLI and injected at build time — the developer’s afk.Dockerfile does not declare it.

See Consumer contract for the full rules and an example.

The (optional) rules a developer’s afk.compose.yml must follow when a Run needs sidecar services (e.g. a Postgres, a Redis the agent talks to). The compose file lives at the repo root and declares a graph of services; one of them — the “main service,” named in afk.config.json (default: agent) — is the agent itself, and its image is the one built from afk.Dockerfile. The Run’s lifetime is the main service’s lifetime: when it exits the Run ends and its sidecars stop with it. Their containers and volumes are reclaimed with the compute primitive — immediately, or, where Retention applies, preserved until the retained primitive is reclaimed so the whole stack can be inspected post-mortem.

The compose file is portable across Backends without dev changes. Some Backends impose structural addenda that the CLI applies automatically at submit time — e.g. on the Cloudflare Backend, every service is augmented with network_mode: host and extra_hosts cross-mappings so service-name DNS keeps working under rootless dind. The only Compose Contract rule the CLI cannot auto-fix is port collision between sidecars of the same Run, which remains a hard error.

The per-account, per-Backend boot artifact used by every Run. Its sole purpose is to pre-cache the Docker engine plus a developer-specified list of sidecar images (e.g. postgres:16, redis:7), so per-Run cold-starts don’t re-pull them.

The concrete artifact type is Backend-specific:

  • On AWS EC2, the Golden Image is an AMI (a VM disk image) containing Amazon Linux + Docker + the pre-pulled images in /var/lib/docker.
  • On Cloudflare Containers, the Golden Image is a Container image (pushed to CF managed registry) containing rootless dockerd + the pre-pulled images baked into /var/afk/cache/.
  • On Local, the Golden Image is a Container image of the same shape as Cloudflare’s, built into the developer’s own Docker daemon rather than pushed to a registry.
  • On GCP (Compute Engine), the Golden Image is a custom image (a VM disk image, the AMI analog) built by snapshotting a short-lived builder instance’s disk after it pre-pulls the list.

Golden Images are built explicitly by afk golden build, which reads the pre-pull list from the active Backend’s section of afk.config.json. A Run refuses to start if no Golden Image exists for the active Backend; there is no implicit on-demand build.

The git reference a Run executes against — a branch name, tag, or commit sha. Resolved against the project’s configured AFK_GIT_URL at Run start. Passed via afk run --ref <ref>; defaults to the developer’s current local branch name. A Run refuses to start if the resolved ref isn’t reachable on origin.

A developer-declared file (or glob of files) produced inside the Run’s main service container that afk collects when the Run ends and persists for later review — the motivating case being an AI agent’s structured session transcript (e.g. Claude Code’s ~/.claude/projects/**/*.jsonl), so a developer can reconstruct what the agent did after the fact.

afk is agent-agnostic and therefore knows nothing about the artifact’s shape or meaning: the developer names the path(s) in afk.config.json, and afk treats the contents as an opaque blob. Collection is scoped to the main service only — never sidecars — which is what distinguishes a Session Artifact from general file exfiltration out of an arbitrary container.

Distinct from logs: logs are the per-service stdout/stderr stream tailed live by afk logs; a Session Artifact is a file collected once, at Run end, from the agent’s own on-disk state. The single collection point — the Run command’s graceful exit — also bounds what is captured, on every Backend: a Session Artifact is the artifact of the Run’s own execution, not of any later attach session. Running a fresh agent inside an afk attach shell and then exiting happens outside that one collection moment, so it is never captured.