Configuration files¶
Loadout uses TOML for source selection and permission rules, Markdown for instructions, and JSON for native configuration fragments.
Global manifest¶
A global source contains loadout.toml:
[[source]]
name = "personal"
path = "."
[all]
instructions = ["workflow"]
[claude]
settings = "claude"
[codex]
defaults = "codex"
[opencode]
[pi]
This example also requires instructions/workflow.md, settings/claude.json, and
defaults/codex.json in the source. Remove a named selection if you do not need it.
Source entries¶
| Field | Meaning |
|---|---|
name |
Name used to qualify fragments and templates |
path |
Source directory; relative to the manifest, or an absolute/home-relative path |
use |
Optional list of slices this source contributes |
Source order matters where the slice uses ordered merging. Permission conflicts use deny/ask/allow priority instead. See composition.
Agent blocks¶
| Key | Value |
|---|---|
instructions |
Ordered list of Markdown fragment names |
settings |
JSON settings fragment name or ordered list |
defaults |
Codex defaults fragment name or ordered list |
hooks |
Hook fragment name or ordered list |
plugins |
Plugin fragment name or ordered list, for supporting agents |
substitute |
Map from selected instruction name to replacement name |
preserve |
Foreign top-level keys to carry forward where the target supports them |
[all] provides defaults to declared agents. Each agent's explicit key replaces that
default. A key that an agent does not support is rejected when named directly in its block.
Permissions, MCP policy/definitions, skills, and module files are automatic for agents that
offer those slices. Set the relevant key to false to opt out. For example:
permissions = [] selects no permission rules for that target but still renders the target.
It is different from disabling the slice with false.
Fragment layout¶
source/
├── loadout.toml
├── focused.toml
├── permissions.toml
├── mcp.toml
├── instructions/
├── settings/
├── defaults/
├── hooks/
├── plugins/
├── skills/
├── module-config/
└── templates/
Only create the directories your configuration uses. Profiles live beside loadout.toml;
slice directories belong under the selected source paths.
Machine configuration¶
source = "~/agent-config/loadout"
profile = "default"
harnesses = ["claude", "codex"]
When XDG_CONFIG_HOME is set, the location is $XDG_CONFIG_HOME/loadout/config.toml.
source is required. profile and harnesses are optional. The harness list supplies defaults
for fresh project init when no --harness option is given. It must be non-empty, contain no
duplicates, and use supported harness names. Other keys are rejected.
Project configuration¶
harnesses = ["claude", "codex"]
instructions = ["project", "testing"]
templates = ["python"]
| Field | Meaning |
|---|---|
harnesses |
Non-empty list of supported harness names |
instructions |
Ordered project instruction fragment names |
templates |
Ordered template names |
[template.NAME].vendored |
Content hash maintained by template vendoring/sync |
The project file has no source-path list or profile inheritance. Shared sources reach projects through templates.
Project permissions live in loadout/permissions.toml and
loadout/permissions.local.toml. See project setup.
Permission rules¶
[shell]
default = "ask"
allow = ["git status", "git diff"]
ask = ["git commit"]
deny = ["git push"]
[mcp]
allow = ["docs/search"]
ask = ["docs/update"]
deny = ["docs/delete"]
- Shell entries are command strings. The renderer adapts their representation to each harness.
- MCP entries use
server/toolorserver/*. allow,ask, anddenyare lists; omitted lists are empty.- The strictest decision wins when the same entry appears in several tiers.
- An omitted shell default casts no vote in composition. An explicitly stated default does.
[shell] defaultis rendered for OpenCode and Pi. Claude and Codex use native settings; Droid uses session autonomy.- A bare
"*"shell entry is invalid. Use thedefaultkey for a catch-all. - A plain shell entry is a prefix:
"git status"also matchesgit status --short. An entry starting with=is exact:"=git status"matches that command and nothing longer. An exact entry may not contain*.
Exact entries render exactly for Claude, OpenCode, and Pi. Codex and Droid cannot match a whole
command, so Loadout omits an exact allow or ask for them, leaving the command to their own
approval, and renders an exact deny as its prefix, which blocks more rather than less.
loadout sync reports each one.
Trailing shell globs can be represented by Claude, OpenCode, and Pi. Loadout skips them for Codex's literal prefix rules and Droid's literal permission lists. Different matching behavior remains visible in the harness reference.
Harness-specific entries¶
Native additions can be carried alongside portable rules:
These entries are specific to their harness. Keep portable rules in the shared shell/MCP sections whenever those sections express the behavior you need.
Explicit output targets¶
Agent blocks use built-in destinations. The older explicit-target form is also accepted:
[[source]]
name = "personal"
path = "."
[instructions.claude]
output = "generated/CLAUDE.md"
destinations = ["${CLAUDE_CONFIG_DIR:-~/.claude}/CLAUDE.md"]
order = ["workflow"]
[permissions.claude]
output = "generated/settings.json"
render = "claude"
Outputs are relative to the manifest root and cannot escape it. Destinations resolve to absolute
machine paths. ${VAR} requires a non-empty environment variable; ${VAR:-fallback}
uses the fallback for an unset or empty variable.
Permission targets can specify a JSON base file or settings fragments, but not both.
A base must be authored input, never another generated output.
Use agent blocks for ordinary setups. The repository's full manifest reference covers the explicit form in greater detail.