Dotfiles as a Shared Agent Brain

James Phoenix
James Phoenix

Most dotfiles repos sync your shell. Mine syncs my agents. The same Claude and Codex brain runs on both my machines because their global instructions live in a git-tracked symlink.

Author: James Phoenix | Date: May 2026


The Two-Machine Problem

I work across two Macs. A MacBook Pro for travel and meetings, a Mac Studio for heavy local builds and overnight runs. Both run the same dev stack. Both run Claude Code and Codex. Both need to know the same things about how I work.

For years I solved this the lazy way. I would set up the laptop properly, then half-configure the Studio when I needed it, then realise three months later that an alias I rely on does not exist there. Or worse, I would teach Claude a new convention on one machine and watch the other machine’s Claude blunder into the same mistakes a week later because it never got the memo.

That second problem is the one nobody talks about. Cross-machine sync is solved for code, dotfiles, and secrets. It is not solved for agent context. And agent context is now the most valuable thing on the machine.

What the Repo Contains

Just-Understanding-Data-Ltd/dotfiles is a private repo with a deliberately small footprint:

dotfiles/
├── install.sh          # Idempotent symlink installer
├── claude/CLAUDE.md    # Global Claude Code instructions
├── codex/AGENTS.md     # Global Codex instructions
├── zshrc/.zshrc.shared # Shared aliases, env vars, service tokens
├── skills/             # Reusable Claude/Codex skills
├── services/           # Shared MCP server config fragments
└── tax/scenario.json   # Single source of truth for my UK tax model

The shell side is unremarkable. The interesting bit is everything above zshrc/.

claude/CLAUDE.md is the global instructions file Claude Code reads at startup, on every project, on every machine. It contains my 1Password vault layout, my secrets convention, my Cloudflare credential pattern, my onboarding runbook, and a workflow for editing my personal tax scenario. Anything I want both machines’ Claude to know lives here.

codex/AGENTS.md is the equivalent for Codex. Same content, slightly different format because the two harnesses parse instructions differently.

zshrc/.zshrc.shared holds aliases (ai, cai), env vars (MAX_THINKING_TOKENS, OP_SERVICE_ACCOUNT_TOKEN), and PATH additions that should be identical everywhere. Each machine’s real ~/.zshrc is a one-liner: source ~/.zshrc.shared.

The Kicker: Symlinks, Not Copies

The install script does not copy these files into place. It symlinks them.

ln -sf "$DOTFILES_DIR/claude/CLAUDE.md" "$HOME/.claude/CLAUDE.md"
ln -sf "$DOTFILES_DIR/codex/AGENTS.md" "$HOME/.codex/AGENTS.md"
ln -sf "$DOTFILES_DIR/zshrc/.zshrc.shared" "$HOME/.zshrc.shared"

The difference matters. With copies, an edit means: change the file, then remember to also push to the repo, then remember to pull on the other machine, then run a sync script to overwrite the local copy. Four steps, three of which I will forget.

With symlinks, an edit on either machine is an edit to the repo. git add tax/scenario.json && git commit && git push. On the Studio, git pull and the change is live immediately because the path Claude reads from already points into the working tree. There is no “deploy” step. The symlink is the deploy step.

This means I can finish a Claude session on the laptop where I have just refined a workflow, codify it into claude/CLAUDE.md, push, walk to the Studio, and the Studio’s Claude already knows. My agent’s brain is a git remote.

What Stays Machine-Specific

The trap most people fall into is putting too much in the shared file. Then it breaks on the other machine because of a path or a hostname.

I split it strictly. Anything portable goes in ~/.claude/CLAUDE.md (the symlink). Anything machine-specific goes in ~/CLAUDE.md (a regular file, not synced). The two are loaded together but live separately.

Examples of machine-specific content:

  • SSH details for the other machine (because they are not symmetric)
  • Hostnames, IPs, usernames (they differ: jamesaphoenix on the Pro, jamesphoenix on the Studio)
  • Per-machine API keys for things that need different auth per device
  • Conda init paths and homebrew prefixes if they ever drift

The same split applies to the shell. ~/.zshrc.shared is portable; ~/.zshrc holds whatever is unique to this Mac.

This separation is what makes the symlink approach work without surprise blowups when something machine-specific leaks into shared config.

Why This Compounds

Three reasons this beats the obvious alternatives.

One. Every conversation on either machine starts with the same priors. I do not have to re-teach Claude about my 1Password layout, my tax workflow, or my secrets convention. I taught it once, in the repo, and both agents read it at startup forever. The cost of teaching the agent is paid once, not per machine and not per session.

Two. Updates are git operations, not deploy operations. Improving a workflow is the same gesture as committing code. Push, pull, done. There is no separate “agent config deployment” step because the symlink collapses deployment into the file system. This means I actually do it, instead of letting drift accumulate.

Three. Diffs are reviewable. Because the agent’s instructions live in git, every change has a commit message, a diff, and a history. When I change how Claude handles secrets, I can read back the commit and remember why. When I want to see what the Studio’s Claude knows, I git log claude/CLAUDE.md. This is the same advantage dotfiles repos give you for shell config, applied to the much more valuable layer above it.

The Onboarding Test

The clearest sign this works is bootstrapping a new Mac. From a clean install:

brew install --cask 1password 1password-cli
brew install claude-code just
npm install -g @openai/codex
mkdir -p ~/Desktop/projects/just-understanding-data
cd ~/Desktop/projects/just-understanding-data
git clone [email protected]:Just-Understanding-Data-Ltd/dotfiles.git
cd dotfiles && ./install.sh
echo 'source ~/.zshrc.shared' >> ~/.zshrc

Eight commands. The new machine now has my aliases, my secrets convention, my Claude brain, my Codex brain, and a working shell. The only remaining step is creating the machine-specific ~/CLAUDE.md with the SSH and hostname bits.

If I sit down at a borrowed Mac, I am productive in under five minutes because the most expensive thing to recreate, my agent’s accumulated context, was never on the old machine in the first place. It was always in the repo.

Leanpub Book

Read The Meta-Engineer

A practical book on building autonomous AI systems with Claude Code, context engineering, verification loops, and production harnesses.

Continuously updated
Claude Code + agentic systems
View Book

The Generalisation

Most engineers think of dotfiles as a way to keep their shell tidy. After agents, dotfiles are how you keep your agents tidy. The shell only ever knew about you. The agent knows about you, your projects, your conventions, your tax setup, your secret vaults, your way of writing code. Losing that context is much more expensive than losing a .zshrc.

The pattern is: anything an agent should know across machines, sessions, or projects belongs in version control, symlinked into the location the harness reads from. Everything else is local state.

Related

Topics
Ai AgentsCross Machine SyncDotfilesGit SymlinksTlm Configurations

Newsletter

Become a better AI engineer

Weekly deep dives on production AI systems, context engineering, and the patterns that compound. No fluff, no tutorials. Just what works.

Join 306K+ developers. No spam. Unsubscribe anytime.


More Insights

Cover Image for Three Ways to Track Experiment Config Upstream

Three Ways to Track Experiment Config Upstream

If I cannot answer “what exactly was running when this experiment scored 0.74”, I do not have an experiment. I have an anecdote.

James Phoenix
James Phoenix
Cover Image for The Six Evergreen Levers of Agent Performance

The Six Evergreen Levers of Agent Performance

Whenever I am stuck in an agent loop chasing the same failure mode for the third time, the bug is rarely the agent. The bug is that I have not stepped back to ask which lever I should actually be pulling.

James Phoenix
James Phoenix