04651503d2
Retrofit playbook Step 0/Step 1 and the /retrofit guide now seed every new repo with the canonical .gitignore block and the inbox-check line, and Part 5 documents /capture, /triage, /roundup. portability.md and the portability-checker guide now scope the relative-symlink mandate to in-repo (committed) symlinks, so global ~/.claude/* links are no longer flagged. ROADMAP adds a high-priority cross-repo git-hygiene audit.
148 lines
10 KiB
Markdown
148 lines
10 KiB
Markdown
# Portability Protocol
|
|
|
|
**Purpose:** keep every layer of my agent setup hot-swappable across model providers. Any compliant tool dropped into one of my repos should be productive immediately; adopting a new tool should cost minutes; returning to a previous tool should cost nothing.
|
|
|
|
**Lives at:** `~/Projects/standards/portability.md`. The standards repo is laid out as:
|
|
|
|
```
|
|
~/Projects/standards/
|
|
AGENTS.md ← CLAUDE.md (relative symlink) ← agent-facing orientation to this repo
|
|
README.md how-i-work.md portability.md retrofit-playbook.md subagents-handbook.md
|
|
ROADMAP.md ← this repo's backlog (future agents, commands, standards)
|
|
INBOX.md ← cross-project capture buffer (/capture → here, /triage drains it)
|
|
guides/ ← neutral substance (vendor-agnostic): checklists, role knowledge
|
|
adapters/
|
|
claude/
|
|
commands/ ← ~/.claude/commands symlinks here (global commands, e.g. /handoff)
|
|
agents/ ← ~/.claude/agents symlinks here (global subagents)
|
|
```
|
|
|
|
Companions: `how-i-work.md` (the always-loaded user layer, ~50 lines), `retrofit-playbook.md` (the one-time conversion manual), and `subagents-handbook.md` (designing and running delegated agents). This document is reference material — never symlink it into anything always-loaded.
|
|
|
|
## The principle
|
|
|
|
**Knowledge lives in vendor-neutral files; vendor-named paths are thin adapters — symlinks or pointers — into them.**
|
|
|
|
Corollaries:
|
|
|
|
1. **Repos are self-contained.** Everything required to work on a project correctly lives in the repo. Global and user-level files add preferences, never requirements.
|
|
2. **Swap at session boundaries.** The close-out ritual (update Current state → commit → push) is the handoff protocol between providers, not just between sessions.
|
|
3. **Convert machinery, never knowledge.** At adoption time, an agent regenerates wrappers (subagents, commands, rule loaders). The substance they point at never moves. Every command and subagent is a thin wrapper in `adapters/<tool>/` whose substance lives in `guides/` — no inline exceptions, so any wrapper converts to a new tool by swapping its header.
|
|
4. **Session state is disposable by design.** Conversations and per-tool caches (e.g. Claude's auto memory) are conveniences. Anything important gets promoted into the files below.
|
|
5. **No secrets in any of these files.** Secrets live in gitignored .env files; documents reference env-var names only.
|
|
|
|
## The layers
|
|
|
|
| Layer | Neutral source of truth | Claude adapter | Portability status |
|
|
|---|---|---|---|
|
|
| Project knowledge | `<repo>/AGENTS.md` | symlink `CLAUDE.md` → `AGENTS.md` | Open standard — Cursor, Copilot, Codex, Gemini CLI, opencode read it |
|
|
| Project status (now) | `## Current state` section in AGENTS.md | (same symlink) | Fully portable; maintained by the close-out ritual |
|
|
| Project backlog (later) | `ROADMAP.md` at repo root | — (plain committed file, no symlink) | Fully portable; committed and pushed like any file, read only on demand |
|
|
| Scoped guides | `<repo>/docs/guides/<topic>.md` with `paths:` frontmatter, plus one index line each in AGENTS.md | symlinks from `.claude/rules/` (auto lazy-load) | Content fully portable; lazy-loading is per-tool. Other tools find guides via the index lines |
|
|
| User preferences | `~/Projects/standards/how-i-work.md` | symlink `~/.claude/CLAUDE.md` → it | No cross-tool standard above repo level; each tool's global file symlinks here at adoption |
|
|
| Skills (procedures) | folders of `SKILL.md` + plain bash/python scripts | `.claude/skills/` | Format is open markdown; a cross-tool home (`.agents/skills/`) is emerging. Worst case: a pointer line in AGENTS.md |
|
|
| Subagents (delegation) | guides folder at matching scope — `<repo>/docs/guides/` for project agents, `standards/guides/` for global | thin wrapper in `.claude/agents/` (project) or `standards/adapters/claude/agents/` (global, symlinked as `~/.claude/agents`) | No standard exists. Wrappers regenerated per tool at adoption |
|
|
| Commands (saved prompt shortcuts) | substance in `guides/` at matching scope, same rule as subagents | thin wrapper in `.claude/commands/` (project) or `standards/adapters/claude/commands/` (global, symlinked as `~/.claude/commands`) | No standard. Same treatment as subagents |
|
|
|
|
**Scope rule:** every artifact lives at the scope it describes — project-specific in that repo; universal in the standards repo. There, neutral substance goes in `guides/` and vendor machinery is quarantined under `adapters/<tool>/` (so a second provider's wrappers never intermix with Claude's or with the shared guides).
|
|
|
|
## What git tracks
|
|
|
|
Symlinks and `.claude/` raise a recurring question: what belongs in the repo, what stays
|
|
local, and how does the global `~/.claude` layer get backed up? One rule resolves all three
|
|
— **git tracks knowledge and the wiring that serves it; it ignores machine-local state and
|
|
secrets** — but it lands in three places.
|
|
|
|
**1. Relative symlinks are committed and travel.** Git stores a symlink as its target path.
|
|
Because every vendor path in this standard is a *relative* symlink (`CLAUDE.md → AGENTS.md`,
|
|
`.claude/rules/x.md → ../../docs/guides/x.md`), it commits and clones correctly on any
|
|
machine. This is the concrete payoff of the relative-symlink mandate: an absolute symlink
|
|
would commit too, but break on every other clone. Never commit an absolute symlink. This
|
|
mandate binds **in-repo** symlinks specifically — the ones git commits and clones. The
|
|
global `~/.claude/*` symlinks (point 3) are never committed, so the rule doesn't reach them:
|
|
they're per-machine glue, recreated on each machine by the adoption step, and may be absolute
|
|
without harm. A repo audit checks only the symlinks inside the repo.
|
|
|
|
**2. Inside a project repo — commit shared, ignore local.**
|
|
|
|
Committed (any agent or teammate needs them to work the repo correctly — corollary 1):
|
|
`AGENTS.md` and its `CLAUDE.md` symlink; `docs/guides/*.md` and their `.claude/rules/*.md`
|
|
symlinks; `ROADMAP.md`; `.claude/settings.json` (shared project settings and hooks —
|
|
deterministic behavior is part of the repo); `.claude/agents/*.md`, `.claude/commands/*.md`,
|
|
`.claude/skills/` (project-scoped wrappers).
|
|
|
|
Gitignored (per-user, per-machine, or secret): `.claude/settings.local.json` and any
|
|
`*.local.*` (personal permissions/overrides); `.env` and secrets (corollary 5); OS cruft.
|
|
|
|
Put these in the repo's **own committed `.gitignore`** — don't rely on a global
|
|
excludesfile, which a fresh clone or another machine won't have. Canonical block:
|
|
|
|
```
|
|
# Secrets & local env
|
|
.env
|
|
.env.*
|
|
!.env.example
|
|
|
|
# Claude Code — commit shared config, ignore personal/local
|
|
.claude/settings.local.json
|
|
.claude/*.local.json
|
|
|
|
# OS cruft
|
|
.DS_Store
|
|
```
|
|
|
|
**3. The global `~/.claude` layer is backed up *through the standards repo*, not on its
|
|
own.** `~/.claude` is not a git repo. Its durable, portable parts — `commands`, `agents`,
|
|
`CLAUDE.md` — are symlinks *into* this standards repo, so committing and pushing standards
|
|
backs them up. Everything else under `~/.claude` (the machine-local `settings.json`,
|
|
`projects/` session transcripts and auto-memory, history, todos, caches) is disposable
|
|
session state by design (corollary 4) and is neither committed nor backed up. What makes
|
|
this safe: promote anything durable out of auto-memory into a committed file (AGENTS.md or a
|
|
guide); audit with `/memory`.
|
|
|
|
So the answer to "are we backing up all of `.claude`?" is **no, by design**: knowledge and
|
|
shared wiring are committed per-repo or symlinked into a backed-up repo; machine-local state
|
|
and secrets never are.
|
|
|
|
## Swap protocol (between already-adopted tools)
|
|
|
|
1. Finish the task and run the close-out ritual; exit the session.
|
|
2. Open the other tool in the same repo.
|
|
3. It reads AGENTS.md (plus its own global file) and Current state, and continues.
|
|
|
|
Nothing else. If step 3 stumbles, the missing fact belongs in AGENTS.md — add it and commit.
|
|
|
|
## Adoption checklist (first time using a new provider)
|
|
|
|
Run by the new agent itself: *"Read ~/Projects/standards/portability.md and onboard yourself as a new provider."*
|
|
|
|
1. Install and authenticate the tool — the only human-heavy step.
|
|
2. Symlink (or copy) its global instruction file to `standards/how-i-work.md`.
|
|
3. Confirm it reads `<repo>/AGENTS.md`. If it expects a different filename, symlink that name to AGENTS.md.
|
|
4. If it supports path-scoped or lazy loading, wire its mechanism to `docs/guides/`; otherwise the AGENTS.md index lines suffice.
|
|
5. If it supports skills or procedures, point it at the skills folders; otherwise add a pointer line in its global file.
|
|
6. Regenerate the thin wrappers it supports (subagents, commands) from the guides they reference, placing global ones in `adapters/<tool>/` and symlinking the tool's config home to them.
|
|
7. **Record what was done in a new provider section at the bottom of this document.**
|
|
|
|
## Provider adapters
|
|
|
|
### Claude Code (current)
|
|
|
|
- `CLAUDE.md` → symlink → `AGENTS.md` at the root of every repo
|
|
- `.claude/rules/<topic>.md` → symlinks → `docs/guides/<topic>.md` (auto lazy-load via `paths:` frontmatter)
|
|
- `~/.claude/CLAUDE.md` → symlink → `standards/how-i-work.md`
|
|
- `.claude/agents/` — thin subagent wrappers pointing at docs/guides (project-specific agents only)
|
|
- `.claude/commands/` — thin command templates, regenerable (project-specific commands only)
|
|
- Global commands and agents: `~/.claude/commands` → symlink → `standards/adapters/claude/commands/`; `~/.claude/agents` → symlink → `standards/adapters/claude/agents/` (versioned and backed up with the standards repo)
|
|
- `.claude/skills/` — skills home for now; migrate to `.agents/skills/` if that convention solidifies
|
|
- Auto memory: local cache only (`~/.claude/projects/<project>/memory/`), outside git, not portable. Promote keepers into AGENTS.md or guides. Audit with `/memory`.
|
|
|
|
### Next provider — template
|
|
|
|
- Global file location: ___ → symlink → `standards/how-i-work.md`
|
|
- Reads AGENTS.md natively? ___ (if not: symlink its expected filename → AGENTS.md)
|
|
- Scoped/lazy loading mechanism: ___ (wired to docs/guides, or relying on index lines)
|
|
- Skills support: ___
|
|
- Delegation/subagent equivalent: ___ (wrappers regenerated on: ___)
|
|
- Notes and quirks: ___
|