Source map
This page is for contributors. It lists what each part of src/kraft/ holds, and
where to make each kind of change. For how those parts fit together, see
Architecture.
Module map
Every path below is under src/kraft/.
Serving
| Path | What it does |
|---|---|
cli/ | The kraft command: item, view, repo and admin verb groups, and starting the server. cli/verify.py is kraft repo connect --verify. |
client/ | The one HTTP client. transport.py is the wire, actions.py changes things, reads.py reads, context.py knows which item a worker stands in. |
mcp.py | kraft admin mcp: the MCP tools, each a call into client/. |
api/__init__.py | Builds the FastAPI app, installs middleware, serves the SPA. |
api/startup.py | The lifespan: opens the database, reattaches sessions, starts the pollers. |
api/deps.py | Helpers shared by routes, including spawn, which starts a walk. |
api/perimeter.py | Who may call the API at all. |
api/apidocs.py | The /docs and /redoc pages, with their scripts pinned to one release and checked by hash. |
api/routes/ | One module per resource: work_items, lifecycle, gates, review, board, artifacts, sessions, repos, settings, harnesses, search, auth, check, admin, drafts. |
api/routes/lifecycle.py | Pause, resume, retry, skip, abandon, complete, cancel, escalate. |
api/routes/sessions.py | Logs, permission requests, the WebSocket. |
api/routes/admin.py | Pending changes, restart, update. |
api/routes/drafts.py | The Templates editor's unpublished edits. |
api/config_check.py | Checks a config file the way saving it would. |
drafts/, apply.py | Unpublished config and item-chain edits kept server-side, and what is saved but not yet running (reload and restart items). |
ws.py | Fans committed events out to WebSocket clients. |
render.py | Terminal formatting for the CLI. |
Running a chain
| Path | What it does |
|---|---|
executor/entry.py | Intake, attachments, and closing an item's issues in beads when it completes. |
executor/walk.py | The walk: node by node, with recovery, the fix loop, escalation and every stop. |
executor/dispatch.py | Runs a node's steps and tasks, measures the result, collects findings, and asks the fix-loop judge. |
executor/gates.py | Opening gates, approval and rejection, agent gate review, and automatic escalation of stuck stops. |
executor/stops.py | Writes each kind of stop, and guards every claim so an active item always has a walk behind it. |
executor/resuming.py | Resuming after a restart, and addressing a steer to paused tasks. |
executor/retry.py, store/forks.py, templates/forks.py | A retry forks the run at a task, step or node path. |
executor/prompts.py | The text Kraft adds to an agent's prompt: steers, failures, findings, review threads, progress. |
executor/context.py | Walk results and the Steer object. |
executor/fallback.py | Moving a rate-limited or unavailable agent task to its next fallback: entry. |
executor/read_only.py | Checks that a read_only step changed nothing. |
builtins.py | Work Kraft does itself: the worktree, setup, rebases, changed-test scopes. |
waits.py | External waits and the scheduler that re-enters them. |
rate_limit_retry.py | Re-enters a rate_limited item after its reset. |
mr_poller.py | Notices a merge request closed on the forge without merging. |
caps.py, cap_levels.py | Time caps per scope, and the poller that stops parked items. |
policy.py | Loads policy.yaml: loops, caps, budget, concurrency, escalation settings. |
findings.py | The finding schema reviewers report, and its identity across rounds. |
escalate.py | Escalation turns: the agent a stopped item hands to. |
auto_escalate_delay.py | Fires a delayed automatic escalation. |
gate_review.py | An agent reviewing a gate before a person sees it. |
review.py | The one producer of "what changed" for the gate viewer and review agents. |
review_reply.py | The agent that answers review threads. |
node_runs.py | Pins the commit each node run started and ended on. |
progress.py | Reads a plan's ## Task N headings for "Task 3 of 6". |
Templates
| Path | What it does |
|---|---|
templates/models.py | The typed chain schema: tasks, steps, nodes, chains, canonical paths. |
templates/library.py | Loads library.yaml and chains/ from the config directory and resolves extends. |
templates/environment.py | Workspaces, areas, targets and harness profiles a chain runs against. |
templates/revision.py | Plan-driven chain revision. |
templates/retry.py | Policy-bounded overrides a retry may carry. |
templates/catalogue.py, templates/positions.py | The library as a list for the UI, and YAML positions for editor errors. |
overrides.py | Validates per-item model and per-node overrides. |
skill.py, skills/ | The method an agent follows (spec, plan, code review, and so on), injected through its system prompt. |
Add-ons
| Path | What it does |
|---|---|
addons/manifest.py | The models for collection.json and addon.json, and the fixed layout of an add-on's files. |
addons/config.py | The models for addons.yaml and addons.lock. |
addons/fetch.py | Fetches a collection into a bare mirror, extracts one add-on under the size and content limits, computes the digest and writes the store. |
addons/review.py | What an install or update would change, split into reach and content. |
addons/update.py | Installs and updates: check, lint, review, accept, write. Also the update lock and auto-update. |
addons/load.py | The installed add-ons as the library and the agent-profile table read them, the load-time checks, restoring a missing store and collecting unused ones. |
cli/addon.py | The kraft admin addon verbs. |
Agents and workers
| Path | What it does |
|---|---|
harness.py, harnesses/*.yaml | A harness: how to launch one agent CLI, described as data. |
adapters/agent.py, adapters/profiles.py | Resolve an agent task to a harness profile and an agent profile, and build its command line and context. |
adapters/subprocess.py | Launch a session, watch its log, read its result file, settle its status. |
adapters/artifact_notes.py | What each document kind is for, in the prompt. |
adapters/hook_install.py, permission_hooks.py, permission_rules.py, grants.py, registration.py | The permission gate across harnesses: hook install, tool policy written into each CLI's config, named grants, and the permission tool's name. |
usage.py, logs.py | Token, cost and time per session, and reading a session's log. |
worker/env.py, worker/steering.py | A worker's environment, and the standards injected into its prompt. |
worker/reattach.py | Adopting sessions that survived a restart. |
worker/worktree_read.py | Reading a file an agent wrote, safely. |
worker/backends/, worker/sandbox.py | Sandboxed sessions in Docker or Podman, and host git hardening. |
worker/egress.py, worker/channel.py, worker/ca.py, worker/inject.py, worker/callback.py | The egress proxy for sandboxed sessions: per-session channels, its CA, injected credentials, and what a worker's callbacks may reach. |
worker/refstore.py | A sandboxed worker's private ref store. |
worker/kit.py | Reads one Docker Sandbox Kit you wrote and lowers it onto the docker backend's policy. |
worker/session_mcp.py, worker/shim.py, worker/bin/kraft | The MCP server and kraft shim a sandboxed worker calls back through. |
Forge and trackers
| Path | What it does |
|---|---|
adapters/forge/run.py | Picks the backend and runs a forge node against one or several repos. |
adapters/forge/gh.py, adapters/forge/glab.py | GitHub through gh, GitLab through glab. |
adapters/forge/git.py, adapters/forge/mr.py, adapters/forge/ci.py, adapters/forge/models.py | Local git, the merge request's title and body, reading a pipeline, and the shared types. |
automated_review.py | Which automated reviewer a repo expects. |
detect.py | What kraft repo connect proposes as a repository's setup and test commands. |
adapters/beads.py, intake.py | bd calls, and auto-intake from bd ready. |
triggers.py | Cron schedules from intake.yaml. |
State and configuration
| Path | What it does |
|---|---|
db.py | The schema, its migrations, and the single-writer Database. |
events.py | Appending to and reading the events table. |
store/ | Every query, by table: work_items, chain, gates, sessions, counters, budget, review, repos, forks, intake. _common.py holds the rule that an ended item never becomes runnable. |
paths.py | $KRAFT_HOME and the run/ layout. |
config.py, config_schemas.py | Reading and writing the YAML files, and their JSON Schemas for editors. |
capabilities.py | What this version can do that an older seeded config cannot. |
index/ | The search index: chunking, local embeddings, ingest, and the query service. |
analytics.py | The numbers behind the Analytics view. |
archive.py | Auto-archive of old ended items. |
notify.py | Outbound notifications. |
auth.py | Password login and sessions for off-localhost access. |
doctor.py, update.py, init.py | kraft admin doctor, update and init. |
pidfile.py | run/kraft.pid: which process is this run dir's server, held under a lock. |
intent.py | Checks the intent tree in docs/intent/ (a CI check, not part of the server). |
Outside src/kraft/: the web UI is in frontend/src/ng/ (a folder per area),
the shipped default configuration is in config/, the agent plugins are in
plugins/, the VS Code extension is in vscode/, and contributor scripts are
in dev/.
Workspace members
A sandbox covers a workspace's members as it covers the root. A member is a
worktree of its connected repository (_setup_submodules in builtins.py), so
host git in it reads that repository's config, not a git directory under the
root's worktree. It also reads the member's own config.worktree when that
repository sets extensions.worktreeConfig.
| What a sandboxed container sees of a member | Enforced by |
|---|---|
| Its refs go through a ref store of its own. | prepare_stores in worker/refstore.py |
Its .git, and the commondir, gitdir and config.worktree of its admin directory, are read-only. They are mounted from paths derived from the connected repository, never read from the member's .git. | _gitdir_mounts in worker/backends/docker.py |
Each directory from the worktree down to the member is mounted onto itself, so no container can rename it and put another .git in the member's place. | _pin_path in worker/backends/docker.py |
Before host git runs in a member, Kraft checks it against the checkout Kraft made:
- For a sandboxed item,
refuse_planted_reposinexecutor/stops.pyruns the check (foreign_membersinworker/sandbox.py). A task's launch mounts exactly the checkout that check returned. - Every other sandboxed launch takes its checkout from
sandbox_checkout. These are a gate review, an escalation turn, a review reply and the setup command. It runs the same check and leaves out any member that fails it, so the launch does not start.
Where to change things
| To | Change |
|---|---|
| Add a CLI verb or MCP tool | A function in client/actions.py or client/reads.py, its verb in cli/item.py or cli/view.py, its tool in mcp.py, and the CLI reference. |
| Add an API route | A handler on api_router in the matching api/routes/*.py. A new module is imported in api/__init__.py. |
| Add a harness | A YAML file in harnesses/. See Add or override a harness. |
| Add a builtin action | A member of BuiltinAction in templates/models.py, its branch in executor/dispatch.py, and the work in builtins.py. |
| Add a forge action or backend | ForgeAction in templates/models.py and adapters/forge/run.py; a backend beside gh.py and glab.py. |
| Change what a Kraft add-on may carry | LIMITS and problems in addons/update.py, the layout and limits in addons/manifest.py and addons/fetch.py, and Add-ons and collections. |
| Change a shipped chain or library component | config/chains/*.yaml and config/library.yaml at the repo root. Run kraft admin templates lint. |
| Change what an agent is told | The skill in skills/<name>/SKILL.md, or Kraft's own notes in executor/prompts.py. |
Add a policy.yaml key | PolicyInput and Policy in policy.py, the default in config/policy.yaml, and policy.yaml. |
Add a repos.yaml key | RepoEntry in config.py, and repos.yaml. |
| Change the database | A new numbered migration in db.py, and the queries in store/. |
| Change how a stop is handled | executor/walk.py and executor/stops.py. |
| Add a status transition | The write in store/, through write_status in store/_common.py, and the door in api/routes/lifecycle.py. |
Add a doctor check | doctor.py. |
| Change a screen | Its area's folder under frontend/src/ng/ (board/, item/, review/, templates/, settings/ and so on). |
Related
- Architecture: how these parts fit together, and where each trust boundary is enforced.
- Contributing: the steps to take before you open a pull request.