Building a Cross-Device Claude Code Configuration
How I set up a symlink-based Claude Code config repo that syncs skills, memory, MCP servers, and settings across devices.
The starting point was a tarball in an AWS CodeCommit repo and a set of “instructions from the web” telling me to extract, copy, commit, and push without reading first. I paused. Blind execution is how you commit credentials. The scripts were clean — but the pause was worth building into a habit.
Symlinks, not copies
The repo holds skills, commands, agents, a global CLAUDE.md, and settings.json. install.sh symlinks all of it into ~/.claude/. Edit a skill on one machine, git push, git pull on others — the change is live. No deploy step, no copying, no drift.
Memory follows the same logic. Claude Code namespaces memory per working directory at ~/.claude/projects/<encoded-cwd>/memory/. The install script symlinks three of those dirs — ~/claude-config, /projects/workshop, /projects/harbor-app — to one shared memory/ in the repo. Memories written in any of those sessions are available in all three.
Skills as contracts
A Claude Code skill is a folder with a SKILL.md file. The frontmatter description is what Claude reads to decide when to auto-trigger it. That makes the description a contract: write it precisely and you never have to invoke the skill by name — Claude picks it up from context.
The investigate and refine skills were rewritten to target /projects/workshop instead of a ~/work/knowledge/ vault that doesn’t exist. Investigations become first-class garden notes. The skill asks “publishable: y/n?” before writing; sensitive material goes to _private/, which Astro silently ignores.
MCP setup
Four servers: filesystem for browsing /projects directly, git for reading history without dropping to shell, sequential-thinking for chain-of-thought scaffolding, and playwright for headless browser via NAS. The playwright entry required one fix — the original used a LAN IP that only resolved on the home network. Switching to Tailscale MagicDNS (truenas-scale:8931) made it reachable from the lab VM, the Mac, anywhere on the tailnet.
Twelve decisions, one session
After the first install I had eleven open questions: memory versioning, settings sync strategy, pre-commit hook, python portability, extra symlink dirs, MCP health-check, and more. Instead of deciding each one piecemeal, I ran the grill-me skill across all of them in one structured pass. Each branch resolved explicitly — yes, no, or defer with a stated reason. The outcomes: settings.json lives in the repo and symlinks back (device-local overrides use settings.local.json, gitignored); a pre-commit hook scans staged diffs for secrets; bin/cc-add-skill scaffolds new skill folders; install.sh warns on missing deps with OS-specific install hints.
workshop-ingest
The workflow I use with Claude Desktop — long conversation, then “summarise this” — had a gap: turning that summary into a workshop note still required manual frontmatter wrangling. A workshop-ingest skill closes it: paste the dump, it derives the title, proposes frontmatter, normalises the body, writes to notes/, and hands off to structural-editor.
Which is exactly how this note got here.