Onboarding · your config lives in your repo

Two files tell AFK
the rules.

AFK's configuration is versioned with your code. You commit a .afk/ folder; AFK reads it from your base branch at the start of every task — code-enforced, never guessed. Here's the shape of it.

The .afk/ folder

Two files, one contract.

One is machine-parsed and enforced in code. The other is prose for the model. They're deliberately separate — a hard limit never belongs in the advisory file.

your repository
.afk/
├── config.yml      # required — machine-parsed, enforced in code
└── rules.md        # optional — prose, handed to the model
.afk/config.yml required

Machine-parsed, code-enforced. Carries the toolchain image, the commands AFK may run, path allow/block lists, limits, the default model, and PR labels. It feeds seven pipeline stages — this is where every guardrail actually lives.

.afk/rules.md optional

Prose handed to the model — conventions, domain context, "never do X". Advisory; it enforces nothing. Point it at your AGENTS.md / CLAUDE.md rather than duplicating them.

.afk/config.yml

A complete sample.

Drop this into .afk/config.yml, adjust for your repo, and commit it. Every limit here is checked against the final diff in code — not suggested to the model.

.afk/config.yml — version controlled, code-enforced
version: 1

image: node:22                     # your repo's toolchain — reuse the CI image where one exists

commands:
  install: npm ci                  # CI-appropriate; add --ignore-scripts if a prepare hook wires git hooks
  test: npm test                   # the verify oracle AFK runs to check the change (no secrets in v0)
  lint: npm run lint
  typecheck: tsc --noEmit
  build: npm run build

paths:
  allowed: ["src/**", "tests/**", "docs/**", "README.md"]   # the only paths the agent may write
  blocked: ["infra/prod/**"]                                # never writable, on top of the platform deny list
  ignore: ["**/*.lock", "pnpm-lock.yaml"]                   # never read — keeps the context lean

limits:
  maxCost: 2.00                    # hard $ ceiling — the run stops dead at the cap
  maxFilesChanged: 8               # blast radius: no sprawling rewrites
  maxDiffLines: 500
  maxIterations: 10
  timeoutMinutes: 20

model:
  default: anthropic/claude-sonnet-5   # from the allow-list; a request may override per task

pr:
  labels: ["afk"]                  # AFK opens a draft PR with this label — it never merges

Two optional blocks go further — screenshot: (before/after captures in the PR) and preview: (per-PR deploy previews). Both are inert unless enabled: true:

optional blocks — preview: + screenshot:, the full surface
# ── optional: per-PR deploy previews (Dokploy) ──────────────────────────────
preview:
  enabled: false                 # spin up a preview deployment for each PR
  requireLabel: afk-preview      # only PRs carrying this label get one (mandatory on public repos)

# ── optional: before/after screenshots in the PR body ───────────────────────
screenshot:
  enabled: false                 # everything below is inert unless this is true
  framework: next-app            # "next-app" derives routes from changed app-router pages; else "none"
  routes: ["/dashboard"]         # explicit URLs — fallback when a change maps to no route, or the only source when framework is "none"
  maxRoutes: 3                   # capture at most this many routes per task
  port: 3000                     # the port your app listens on
  readySeconds: 240              # how long to wait for the app to answer (allow for a prod build)
  viewport:
    width: 1280
    height: 800
  env:                           # applied to the APP container only — never the agent's job container
    NEXT_PUBLIC_API_URL: "http://localhost:3000"
  services:                      # disposable sibling containers on the task network; they die with the task
    - image: postgres:17-alpine
      alias: db
      env:
        POSTGRES_USER: afk
        POSTGRES_PASSWORD: afk
  commands:                      # run in the app container before it serves, against the services above
    migrate: pnpm db:push
    seed: pnpm seed:demo
  login:                         # capture authenticated routes by signing in first (seeded demo account only)
    path: /login
    email: "demo@example.com"
    password: "demo-password"
    selectors:                   # override if your sign-in form isn't standard
      email: "input[name=email]"
      password: "input[name=password]"
      submit: "button[type=submit]"

screenshot: is live; preview: is planned. Every field here is optional (each has a default) — you only declare what differs from it.

Getting started

Onboard a repo in three steps.

01

Install the GitHub App

Install AFK's GitHub App on the repositories you want it to work on. That's what lets it clone, push a branch, and open a draft PR — as afkgnt-app[bot], never as you.

02

Commit the .afk/ folder

Add .afk/config.yml (and optionally .afk/rules.md) to your default branch. AFK reads them from there at task start — so your rules are versioned right alongside your code.

03

Register the repo

Point AFK at it once — it reads your committed config live via the App. Then fire tasks from the control room, a terminal, or Telegram, and come back to draft PRs.

Go deeper

The full reference is on GitHub.

This is the overview. For every field, the policy model, the security model and the deploy runbook, read the documentation in the repo.