Config reference (ffleet.toml)
Every ffleet.toml setting. This file is a per-project, personal dev-tool
preference — not team config. ffleet init writes it by default under
~/.forge-fleet/{project-id}/ffleet.toml ("home mode"), so nothing needs to be
committed into the repo it configures. In-repo ("local mode") is supported as an
explicit opt-in.
Most CLI flags mirror a key here; where they overlap the flag wins for that run
(see config precedence). The canonical,
fully-commented template is ffleet.toml.example at
the repo root.
What init sets, and everything else
ffleet init runs a short wizard for the settings most worth choosing up front —
the default coding agent, the base image (python or go variant),
the git mode, and whether sandboxes get host Docker access (DooD). Each
question is pre-selected at its default, so pressing enter through them keeps
today's behavior; your choices are written as active keys. Every other
setting is written commented-out at its default, so the generated file
doubles as a menu — uncomment and edit what you need.
init -y accepts every default without prompting. Non-default values for any
other setting are configured by editing the generated ffleet.toml.
init is create-only: it never overwrites an existing config. To change
settings later, edit the ffleet.toml directly — init prints its path when
it writes it, and re-running init on a configured project just points you back
at that file.
Global keys
| Key | Type | Default | Meaning |
|---|---|---|---|
project_name |
string | — (required) | Logical project name; used to name containers and worktrees. |
source_dir |
string | — | Absolute path to the source repo. Required in home mode; in local mode it's derived from where this file lives (set it only if the file isn't colocated with the repo). |
worktree_root |
string | — (required) | Where per-environment worktrees are created (absolute, or relative to the repo root). Inside the checkout (e.g. .forge-fleet/worktrees) or a separate folder under $HOME. |
image |
string | ghcr.io/grzegorz-aniol/forge-fleet-python:latest |
Docker image the agent container runs. Use ghcr.io/grzegorz-aniol/forge-fleet-go:latest for the Go-dev variant. |
git_mode |
string | auto |
Git integration: auto | off | worktree | clone. off needs no git repo — ffleet up then runs in-place over the project root (no worktree, no --here). See git modes. |
git_local_main |
bool | false |
Base the worktree on the local main branch and keep completion local-only (no push/PR). |
docker_host_bind |
bool | false |
Let the agent inside the container drive the host Docker daemon (binds the host docker socket; agent-started containers become siblings). See DooD. |
uv_cache_dir |
string | ~/.cache/uv |
Shared uv cache mounted into the container for faster installs. |
extra_mounts |
list | — | Extra bind mounts as source:target[:ro\|:rw]. Target must be an absolute container path; a relative source resolves against the repo root; ~ expands to the host home. An optional :ro/:rw suffix sets the mode (default read-write). |
extra_hosts |
list | — (may be omitted) | Host-to-address mappings passed to docker run --add-host, each host:address. host-gateway resolves to the host itself. |
docker_env_file |
string | — | Additional env file passed to docker run --env-file (runtime secrets/keys). A relative path resolves against this config file's own directory. |
copy_files |
list | — | Gitignored files to snapshot from the main repo into each new worktree (globs allowed), so e.g. .env appears at the same relative path inside. One-time copy at creation, not a live link. |
default |
string | — | Which coding-agent ffleet up runs when none is named on the CLI. Must be one of the [section] names below (e.g. claude, codex). |
pm |
string | github |
Issue tracker for -t templates: github (via gh CLI) | linear (needs LINEAR_API_KEY) | none (don't fetch; raw ref exposed as {id}). On any fetch failure ffleet warns and continues as pm=none. |
check_image_period_days |
int or "off" |
30 |
How often ffleet up checks whether a newer image exists in the registry (see image freshness check). Any positive integer sets the period in days; "off" disables the check entirely. |
Image freshness check (check_image_period_days)
Whenever ffleet up actually builds or (re)starts a container, and at least
check_image_period_days have elapsed since the last check for this project, it
does a best-effort comparison of the configured image against its remote
counterpart. It compares two registry manifests: the one the tag resolves to
right now, and the one behind the digest the local copy was pulled under. They
differ only when the tag has actually moved, so the answer doesn't depend on
which image store (classic or containerd) your Docker daemon uses:
- Interactive session — if a newer image is found, ffleet prompts before pulling and pulls only on explicit approval, then starts the container from the freshly pulled image. The pull reports Docker's own outcome, so you can see whether anything was downloaded or the local copy was already current.
ffleet up -y/--yes— warn-only: ffleet prints a notice that a newer image exists but never prompts and never pulls. Pull it yourself withdocker pull <image>(or runffleet upinteractively).
The check never blocks or fails ffleet up: if the registry is unreachable, or
the image was built locally and so has no registry digest to compare, ffleet
silently skips the comparison and starts the container as usual. The last-check
timestamp is stored per project in ~/.forge-fleet/registry.json (not in
ffleet.toml), so a project that was never checked is treated as due on its
next up. Set
check_image_period_days = "off" to disable the whole flow.
[git] — identity injected into the container
Both keys must be set together; otherwise identity resolves from host git config.
| Key | Type | Meaning |
|---|---|---|
user_name |
string | Git author/committer name inside the container. |
user_email |
string | Git author/committer email inside the container. |
[claude] / [codex] — per-coding-agent config
| Key | Type | Default | Meaning |
|---|---|---|---|
dir |
string | ~/.claude / ~/.codex |
Host directory mounted as the agent's config/credentials, so it's authenticated inside the container. |
auth |
string | auto |
(Claude) Credential source ffleet injects. See the table below. |
cmd |
string | the section name | Override the binary invoked in the container (e.g. claude). |
extra_args |
list | — | Flags appended to the agent's launch command, after ffleet's own flags (e.g. ["--agent", "myagent"]). |
[claude].auth values
| Value | Behaviour |
|---|---|
auto |
Try keychain, then token, then api-key, then credentials-file; first available wins (default). |
keychain |
macOS only; pin the Keychain-derived credential (fails fast if the lookup fails). |
token |
Pin CLAUDE_CODE_OAUTH_TOKEN (from claude setup-token). |
api-key |
Pin ANTHROPIC_API_KEY (API billing, not subscription). |
credentials-file |
Pin the ~/.claude mount's .credentials.json (Linux only). |
external |
Skip the auth preflight entirely — you provide credentials another way (e.g. docker_env_file). |
See container configuration for how these mounts and credentials fit together.
[templates.<id>] — prompt templates
Looked up by ffleet up -t <id> <ref>: ffleet fetches issue <ref> from the
configured pm source, derives the slug from the issue title, and renders
prompt_template with the issue's fields.
| Key | Type | Meaning |
|---|---|---|
prompt_template |
string | Template rendered with {number}, {title}, {body}, {url}, {id} (raw ref), plus any extra key=value tokens passed on the CLI. |
subagent |
string | Optional subagent for envs seeded from this template. Translated to the agent's own subagent flag (Claude only: --agent <name>; using it with another agent errors). The up --subagent NAME flag is the per-invocation, template-independent equivalent and overrides this key when both are set — see starting. |
Full walkthrough: advanced/templates.md.
Environment variables and dotenv
Most ffleet.toml keys have an environment-variable equivalent, and Forge Fleet
also loads a dotenv file from the current working directory if present. An env var
(or dotenv entry) overrides the matching ffleet.toml key; a CLI flag overrides
both (see config precedence).
Dotenv discovery order in the current working directory (only the first existing file is loaded):
.env.forge-fleet.forge-fleet/.env
Env var mapping:
Identity (project_name, source_dir, worktree_root) is config-only: it is
read straight from ffleet.toml and has no env-var or CLI-flag override. Run
ffleet init to create the config; without it, the env commands fail with a
no ffleet config found — run 'ffleet init' error.
| Env var | Maps to |
|---|---|
SLUG |
slug positional argument |
IMAGE_NAME |
--image |
CODING_AGENT |
--coding-agent (on up; set only when first creating an env). The legacy AGENT / --agent names still work, each with a one-time deprecation notice. |
CLAUDE_DIR |
--claude-dir |
CLAUDE_AUTH |
--claude-auth (auto, keychain, token, api-key, credentials-file, external) |
CODEX_DIR |
--codex-dir |
UV_CACHE_DIR |
--uv-cache-dir |
EXTRA_MOUNTS |
--extra-mounts (source:target,source:target) |
EXTRA_HOSTS |
--extra-hosts (host:address,host:address; each becomes a docker run --add-host, e.g. host.docker.internal:host-gateway) |
DOCKER_ENV_FILE |
--docker-env-file |
GIT_MODE |
--git-mode (auto, off, worktree, clone) |
GIT_LOCAL_MAIN |
local-branch mode when first creating an env (true/false) |
DOCKER_HOST_BIND |
--docker-host-bind (true/false) |
FORGE_FLEET_GIT_USER_NAME |
explicit git identity name override |
FORGE_FLEET_GIT_USER_EMAIL |
explicit git identity email override |
LINEAR_API_KEY |
Linear personal API key, read directly when pm = "linear"; no CLI flag equivalent |
Example .env.forge-fleet:
IMAGE_NAME=forge-fleet:latest
CODING_AGENT=claude
CLAUDE_DIR=~/.claude
CODEX_DIR=~/.codex
UV_CACHE_DIR=~/.cache/uv
EXTRA_MOUNTS=~/.agents:/home/buddy/.agents,~/.ssh:/home/buddy/.ssh:ro
DOCKER_ENV_FILE=/path/to/docker.env
GIT_MODE=auto
DOCKER_HOST_BIND=false
FORGE_FLEET_GIT_USER_NAME=Jane Developer
FORGE_FLEET_GIT_USER_EMAIL=jane@example.com
# Only needed when pm = "linear":
LINEAR_API_KEY=lin_api_xxxxxxxx
EXTRA_MOUNTS format rules:
- comma-separated entries:
<source>:<target>[:ro|:rw] sourcesupports~expansion- relative
sourceis resolved from the current working directory targetmust be an absolute container path (start with/)- an optional trailing
:roor:rwsets the mount mode (default is read-write); any other trailing segment is rejected - entries are bind-mounted as
-v <source>:<target>(read-write) or-v <source>:<target>:ro(read-only) - if an extra mount uses the same target as an existing mount, the later extra mount can shadow the earlier one
Config discovery order
For a given directory, Forge Fleet locates the ffleet.toml to use in this order:
- an explicit config path (
FFLEET_CONFIGenv var) - an explicit project config dir (
FFLEET_PROJECT_DIRenv var) - the
~/.forge-fleet/registry.jsonlookup by the directory's project id - legacy in-repo search:
ffleet.toml, then.forge-fleet/ffleet.toml
The project id is derived from git structure — the main checkout's
git rev-parse --git-common-dir plus its origin remote, or a path hash when there
is no remote — never from the current directory's name. That's why every worktree of
a project resolves to the same config.
Related
- Full command/flag list: command reference.
- Why some keys only apply after
remove: config precedence.