Tutorial: one dotfiles directory for every harness
Claude Code, Codex and Pi each keep instructions, skills and MCP servers in
their own files and formats. With tongs-agents you write them once, in one
harness-agnostic directory, and tongs-agents config apply writes them into
the config home of every harness and every profile.
In this tutorial you create that directory, preview and apply it, change a file by hand to see drift, and capture an existing setup back into a dotfiles directory. It assumes the profiles from your first workspace.
1. Create the dotfiles directory
Section titled “1. Create the dotfiles directory”mkdir -p ~/src/agent-dotfiles/instructions ~/src/agent-dotfiles/skills/release-notescd ~/src/agent-dotfilesCreate agentic.toml:
schema = "tongs-agents-dotfiles/1"
[instructions]files = ["instructions/common.md"]
[instructions.harness.codex]files = ["instructions/codex.md"]
[skills]dirs = ["skills"]
[mcp_servers.issues]command = ["example-issues-mcp", "--stdio"]env = ["EXAMPLE_ISSUES_TOKEN"] # names only, never valuesprofiles = ["claude-main", "codex-review"]Then the files it names:
printf 'Run the tests before you say a change is done.\n' > instructions/common.mdprintf 'Prefer small commits.\n' > instructions/codex.mdcat > skills/release-notes/SKILL.md <<'EOF'---name: release-notesdescription: Draft release notes from the git log since the last tag.---
Read `git log` since the last tag and group the changes by type.EOFWhat each part does:
instructionsare always-on instructions. Every harness getscommon.md; Codex also getscodex.md.- Every directory under
skills/with aSKILL.mdis one skill in the Agent Skills format. Its directory name must equal thenamein the front matter. mcp_serversare MCP servers.envlists the variable names a server needs; their values come from the agent’s environment and are never written anywhere.profiles = [...](orharnesses = [...]) narrows an item to some targets.
The directory holds no secrets, so you can keep it in a public dotfiles
repository. agentic.toml must belong to you and must not be writable by
group or others.
2. Point tongs-agents at it
Section titled “2. Point tongs-agents at it”Add to ~/.config/tongs-agents/config.toml:
[dotfiles]path = "~/src/agent-dotfiles"Every config verb also takes --source DIR instead. Keep your profiles in
config.toml: the workspace reads them from there, and the config layer
reads them too, so claude-alt’s ~/.claude-alt is a target.
3. Preview
Section titled “3. Preview”tongs-agents config statustongs-agents config apply --dry-runstatus lists every managed entry per target (each Claude, Codex and Pi
config home) with its state; new entries are pending, and the exit status
is 3 until everything is in sync. apply --dry-run prints the unified diff
that apply would write, and writes nothing.
4. Apply
Section titled “4. Apply”tongs-agents config applytongs-agents config applyThe first run writes every pending entry as one change set. A failed write
restores every file it touched. Shared files such as settings.json are
edited by key, and a one-time .tongs-agents.bak copy is kept before the
first edit. After the files are written, apply registers MCP servers with
each harness’s own CLI (claude mcp add --scope user, and pi mcp add on Pi
0.99.0 or newer); Codex servers are written straight into config.toml. A
harness whose CLI is not on PATH is reported as skipped, and a failed
step exits 1 naming the step and is retried by the next apply
(apply --dry-run lists these steps as would run). The second run prints
Nothing to change.: apply is idempotent.
Where things land, in short: Claude Code gets an owned
tongs-agents/instructions.md plus one import line, Codex and Pi get a
managed block in AGENTS.md; skills and MCP servers go where each harness
looks for them. Restart running agents to pick the changes up.
5. See drift
Section titled “5. See drift”Edit a file that apply wrote, for example the managed block in
~/.codex/AGENTS.md, then:
tongs-agents config statustongs-agents config applytongs-agents config apply --forcestatus reports the entry as drifted (exit 3). A plain apply leaves a
drifted entry alone and exits 3. --force overwrites it after keeping your
version as <name>.tongs-agents.drift.bak. A comment or whitespace edit in a
TOML table is not drift. tongs-agents doctor shows the same drift report
while [dotfiles] path is set.
Removing an item from agentic.toml makes its entry orphaned: the next
apply removes a file tongs-agents owns when it is unchanged.
6. Capture harness-side edits
Section titled “6. Capture harness-side edits”Changed something that apply wrote, directly in a harness? Capture that
harness’s managed entries into a new directory, review it, and copy what you
want back into your dotfiles directory:
tongs-agents config capture claude --into ~/src/captured-claudecapture reads the managed entries of that harness from every target and
writes only inside --into. It round-trips what tongs-agents applied; it does
not import a setup you wrote by hand yet. Your own CLAUDE.md, skills and MCP
servers are not read, so a harness that tongs-agents never managed gives an
empty agentic.toml; describe those in agentic.toml yourself (step 1).
It never reads environment values: a server’s environment entry becomes its
variable name, and a literal value is skipped with a warning. A non-empty --into directory needs --force.
What you learned
Section titled “What you learned”- One
agentic.tomldescribes instructions, skills and MCP servers for every harness, without secrets. config status,config apply --dry-runandconfig applyshow, preview and write it; drift is reported, never silently overwritten.config capturecopies the entries tongs-agents manages in a harness back into a dotfiles directory.
Reference: config layer.
Next: driving agents.