{"slug": "agent-agnostic-repository-guide", "title": "Agent-Agnostic Repository Guide", "summary": "Here is a 2-3 sentence factual summary of the article:\n\nThis guide explains how to configure software repositories to work with any AI coding agent without vendor lock-in by organizing agent configurations into three categories: portable instructions (AGENTS.md), shared skills, and agent-specific settings. The recommended approach uses symlinks to share portable skills across agent directories, sync scripts to generate agent-native configurations from canonical sources, and keeps agent-specific files in their native locations without modification. The system relies on the AAIF/Linux Foundation AGENTS.md standard for universal instructions and the agentskills.io SKILL.md format for reusable workflows, both supported by multiple AI coding agents.", "body_md": "# Agent-Agnostic Repository Guide\n\nA practical guide for making any repository work with any AI coding agent without vendor lock-in. Covers creating new repos agent-agnostic from day one (Part A) and transforming existing repos (Part B).\n\n---\n\n## The Core Principle\n\nEvery piece of agent configuration falls into exactly one of three categories:\n\n| Category | Strategy | Examples |\n|----------|----------|----------|\n| **Portable** (same format across agents) | Store once in `.agents/`, symlink to agent dirs | `AGENTS.md`, `SKILL.md` files |\n| **Generated** (same data, different format) | Canonical source in `.agents/`, sync script renders per-agent | MCP config (JSON vs TOML) |\n| **Agent-specific** (no cross-agent equivalent) | Leave in agent-native directory | `.cursor/rules/*.mdc`, `.claude/settings.json` |\n\nIf you remember nothing else: **portable things get symlinks, generated things get a sync script, agent-specific things stay put.**\n\n---\n\n## Part A: New Repo Template\n\n### A.1 Directory Layout\n\n```\nrepo/\n  AGENTS.md                           # Universal instructions (AAIF standard)\n  CLAUDE.md                           # Pointer: \"@AGENTS.md\" + Claude-only overrides\n\n  .agents/\n    AGENTS.md                         # Self-management doc for this directory\n    skills/                           # Shared skills (committed)\n      <skill-name>/\n        SKILL.md                      # agentskills.io spec format\n        references/                   # Optional supporting docs\n        scripts/                      # Optional automation\n    skills-local/                     # Private skills (gitignored)\n      .gitkeep\n    mcp/\n      servers.json                    # Canonical MCP server definitions\n    scripts/\n      link-skills.sh                  # Symlink skills to agent-native dirs\n      sync-mcp.sh                    # Generate agent-native MCP configs\n\n  .claude/                            # Generated + agent-specific\n    skills/<name> -> ../../.agents/skills/<name>   # Symlinks\n    settings.json                     # Agent-specific (hooks, etc.)\n  .cursor/                            # Generated + agent-specific\n    skills/<name> -> ../../.agents/skills/<name>   # Symlinks\n    rules/                            # Agent-specific (MDC format, not portable)\n    mcp.json                          # Generated from .agents/mcp/servers.json\n  .codex/\n    config.toml                       # Generated from .agents/mcp/servers.json\n  .mcp.json                           # Generated: Claude project-level MCP\n```\n\n### A.2 Layer 1: Instructions (AGENTS.md)\n\n**What:** Project context, conventions, routing, coding standards.\n**Portable?** Yes. [AGENTS.md](https://agents.md) is the AAIF/Linux Foundation standard, read by 20+ agents including Codex, Cursor, Copilot, Gemini CLI, Devin, and more.\n**Sync mechanism:** None needed. Most agents read it natively.\n\n**Setup:**\n\n1. Create `AGENTS.md` at repo root with project overview, directory structure, setup commands, coding standards, git conventions.\n2. Create `CLAUDE.md` as a pointer:\n\n```markdown\n@AGENTS.md\n\nThis repo keeps reusable agent assets in `.agents/` and syncs tool-specific\nadapters with `.agents/scripts/`.\n```\n\n1. For nested packages, create sub-`AGENTS.md` files (e.g., `src/package/AGENTS.md`). Both Claude Code and Codex support hierarchical AGENTS.md — deeper files provide directory-scoped context.\n\n**Sources:** [AGENTS.md spec](https://github.com/agentsmd/agents.md), [AAIF / Linux Foundation](https://aaif.io/)\n\n### A.3 Layer 2: Skills (SKILL.md)\n\n**What:** Reusable workflows agents can invoke — `/rally`, `/learn`, `/deploy`, etc.\n**Portable?** Yes. The [Agent Skills spec](https://agentskills.io/specification) defines a universal SKILL.md format adopted by 16+ agents.\n**Canonical location:** `.agents/skills/<skill-name>/SKILL.md`\n**Sync mechanism:** Symlinks from agent-native dirs.\n\n**SKILL.md format** ([agentskills.io spec](https://agentskills.io/specification)):\n\n```yaml\n---\nname: my-skill\ndescription: What this skill does and when to use it.\n---\n\nStep-by-step instructions for the agent...\n```\n\nRequired fields: `name` (lowercase, hyphens, matches directory name), `description`.\nKeep SKILL.md under 500 lines. Use `references/` for detailed docs.\n\n**The link script** (`.agents/scripts/link-skills.sh`):\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\n\nAGENTS_DIR=\"$(cd \"$(dirname \"$0\")/..\" && pwd)\"\nREPO_ROOT=\"$(cd \"$AGENTS_DIR/..\" && pwd)\"\nTARGETS=(\".claude/skills\" \".cursor/skills\")\ndeclare -A valid_skills\n\nfor target_dir in \"${TARGETS[@]}\"; do\n    mkdir -p \"$REPO_ROOT/$target_dir\"\n\n    for skill_dir in \"$AGENTS_DIR\"/skills/*/; do\n        [ -d \"$skill_dir\" ] || continue\n        name=\"$(basename \"$skill_dir\")\"\n        valid_skills[\"$name\"]=1\n        link_target=\"../../.agents/skills/$name\"\n        link_path=\"$REPO_ROOT/$target_dir/$name\"\n\n        if [ -L \"$link_path\" ]; then\n            [ \"$(readlink \"$link_path\")\" = \"$link_target\" ] && continue\n            rm \"$link_path\"\n        elif [ -e \"$link_path\" ]; then\n            echo \"ERROR: $link_path exists but is not a symlink.\" >&2; exit 1\n        fi\n\n        ln -s \"$link_target\" \"$link_path\"\n        echo \"Linked: $link_path -> $link_target\"\n    done\n\n    # Prune stale symlinks\n    for link in \"$REPO_ROOT/$target_dir\"/*/; do\n        [ -L \"${link%/}\" ] || continue\n        link=\"${link%/}\"\n        target=\"$(readlink \"$link\")\"\n        if [[ \"$target\" == *\"/.agents/\"* ]]; then\n            name=\"$(basename \"$link\")\"\n            [ -z \"${valid_skills[$name]+x}\" ] && rm \"$link\" && echo \"Pruned: $link\"\n        fi\n    done\ndone\n```\n\n**Installing third-party skills** ([Vercel skills CLI](https://github.com/vercel-labs/skills)):\n\n```bash\nnpx skills add <repo>@<skill-name> -y\n# Installs to .agents/skills/ AND auto-creates .claude/skills/ symlink\n```\n\nThe Vercel CLI natively understands the `.agents/skills/` convention and creates symlinks to `.claude/skills/` automatically. The link script is a safety net for manual skill creation.\n\n**Private skills:** `.agents/skills-local/` is gitignored. The link script creates symlinks for these too, but those symlinks are machine-local and should not be committed.\n\n**Sources:** [Agent Skills spec](https://agentskills.io/specification), [Client implementation guide](https://agentskills.io/client-implementation/adding-skills-support.md), [npx skills](https://github.com/vercel-labs/skills), [SSW Rules: symlink agents to claude](https://www.ssw.com.au/rules/symlink-agents-to-claude)\n\n### A.4 Layer 3: MCP Configuration\n\n**What:** Model Context Protocol server definitions — which external tools the agent can call.\n**Portable?** No. Same data, different format per agent.\n**Canonical location:** `.agents/mcp/servers.json`\n**Sync mechanism:** Generation script renders per-agent files.\n\n**Why generation, not symlinks:**\n\n| Agent | File | Format difference |\n|-------|------|-------------------|\n| Claude Code | `.mcp.json` | JSON. URL servers need `\"type\": \"http\"` |\n| Cursor | `.cursor/mcp.json` | JSON. Direct copy, no `type` field needed |\n| Codex | `.codex/config.toml` | TOML. `[mcp_servers.<name>]` tables |\n\n**Canonical format** (`.agents/mcp/servers.json`):\n\n```json\n{\n  \"figma\": {\n    \"type\": \"http\",\n    \"url\": \"https://mcp.figma.com/mcp\"\n  },\n  \"stacks\": {\n    \"type\": \"http\",\n    \"url\": \"https://stacksmcp.int.stackoverflow.net/mcp\"\n  }\n}\n```\n\n**Codex special case:** Codex does not auto-load repo-local `.codex/config.toml`. The sync script should support an `install-codex` command that merges a managed block into `~/.codex/config.toml` with sentinel comments (`# BEGIN <repo> managed MCP` / `# END <repo> managed MCP`).\n\n**Sources:** [MCP specification](https://modelcontextprotocol.io), [AAIF](https://aaif.io/)\n\n### A.5 Layer 4: Agent-Specific (Leave As-Is)\n\nThese have no cross-agent equivalent. Do not try to abstract them.\n\n| File | Agent | Why not portable |\n|------|-------|-----------------|\n| `.cursor/rules/*.mdc` | Cursor | MDC format with glob scoping (`globs: \"**/*.py\"`), conditional loading (`alwaysApply`) — no equivalent elsewhere |\n| `.claude/settings.json` | Claude Code | Hooks, metadata updaters — Claude-specific harness features |\n| `.claude/settings.local.json` | Claude Code | Machine-local permissions — always gitignored |\n| `.claude/agents/*.md` | Claude Code | Subagent definitions — Claude-specific feature |\n\n**If you want the same knowledge available in multiple agents**, put it in `AGENTS.md` (universally read) rather than trying to sync between `.cursor/rules/` and `.claude/` formats.\n\n### A.6 Automation\n\n**Pre-commit hooks** (`.pre-commit-config.yaml`):\n\n```yaml\n- repo: local\n  hooks:\n    - id: link-agent-skills\n      name: \"Sync .agents/skills symlinks\"\n      entry: .agents/scripts/link-skills.sh\n      language: script\n      pass_filenames: false\n      files: ^\\.agents/skills/|^\\.claude/skills/|^\\.cursor/skills/\n    - id: check-agent-mcp\n      name: \"Verify MCP configs are current\"\n      entry: .agents/scripts/sync-mcp.sh check\n      language: script\n      pass_filenames: false\n      files: ^\\.agents/mcp/\n```\n\n### A.7 .gitignore\n\n```gitignore\n# Agent skills (machine-local)\n.agents/skills-local/*\n!.agents/skills-local/.gitkeep\n\n# Agent settings (machine-local)\n.claude/settings.local.json\n.claude/worktrees/\n```\n\nFor **whitelist repos** (meta workspace pattern where `*` ignores everything):\n\n```gitignore\n!.agents/\n!.agents/**\n!.claude/\n!.claude/**\n!.codex/\n!.codex/**\n!.cursor/\n!.cursor/**\n!.mcp.json\n!AGENTS.md\n!CLAUDE.md\n```\n\n### A.8 `.agents/AGENTS.md` Template\n\nThis is the self-management doc that lets any agent maintain the directory:\n\n```markdown\n# .agents/\n\nAgent-agnostic configuration following the [Agent Skills](https://agentskills.io)\nopen standard and [AGENTS.md](https://agents.md) conventions.\n\n## Layout\n\n- `skills/` — Shared skills (committed). Each is a directory with `SKILL.md`.\n- `skills-local/` — Private skills (gitignored).\n- `mcp/servers.json` — Canonical MCP server config.\n- `scripts/` — Sync and validation scripts.\n\n## Adding a skill\n\n1. Create `.agents/skills/<name>/SKILL.md` with `name` + `description` frontmatter\n2. Run `.agents/scripts/link-skills.sh`\n3. Commit the skill directory and the new symlink\n\n## Installing third-party skills\n\n    npx skills add <repo>@<skill> -y\n\n## Adding an MCP server\n\n1. Edit `.agents/mcp/servers.json`\n2. Run `.agents/scripts/sync-mcp.sh`\n3. Commit all generated files\n\n## Rules\n\n- Edit skills in `.agents/skills/`, never in `.claude/skills/` or `.cursor/skills/`\n- Edit MCP in `.agents/mcp/servers.json`, never in `.mcp.json` or `.cursor/mcp.json`\n- Pre-commit hooks enforce sync automatically\n```\n\n### A.9 New Repo Checklist\n\n1. Create `AGENTS.md` at repo root\n2. Create `CLAUDE.md` with `@AGENTS.md` pointer\n3. Create `.agents/` with `skills/`, `skills-local/.gitkeep`, `mcp/servers.json`, `scripts/`, `AGENTS.md`\n4. Create initial skills in `.agents/skills/`\n5. Run `link-skills.sh` to create symlinks\n6. Create or adapt sync script for MCP\n7. Run sync to generate `.mcp.json`, `.cursor/mcp.json`, `.codex/config.toml`\n8. Add pre-commit hooks\n9. Update `.gitignore`\n10. Verify: symlinks resolve, sync check passes, skills discoverable\n\n---\n\n## Part B: Migration Guide\n\n### B.1 Assessment: Audit What You Have\n\n```bash\n# Find all agent config files\nfind . -maxdepth 3 \\( \\\n  -name \"AGENTS.md\" -o -name \"CLAUDE.md\" -o \\\n  -name \".mcp.json\" -o -name \"mcp.json\" -o \\\n  -name \"*.mdc\" -o -name \"SKILL.md\" -o \\\n  -name \"settings.json\" -o -name \"settings.local.json\" -o \\\n  -name \"config.toml\" \\\n\\) -not -path \"*/.venv/*\" -not -path \"*/node_modules/*\"\n```\n\nFor each file, classify as Portable, Generated, or Agent-specific.\n\n### B.2 Classification Matrix\n\n| Asset | Category | Action |\n|-------|----------|--------|\n| `AGENTS.md` | Portable | Keep at root. Create if missing. |\n| `CLAUDE.md` (full instructions) | Portable | Move content to `AGENTS.md`, replace with `@AGENTS.md` pointer |\n| `.claude/skills/*/SKILL.md` (real files) | Should be portable | `git mv` to `.agents/skills/`, replace with symlinks |\n| `.agents/skills/*/SKILL.md` | Already portable | No change needed |\n| `.cursor/commands/*.md` (from skills) | Generated | Mark as generated output, or leave if hand-authored |\n| `.cursor/rules/*.mdc` | Agent-specific | **Leave in place.** MDC format not portable. |\n| `.mcp.json` | Generated | Create `.agents/mcp/servers.json` as canonical, generate from it |\n| `.cursor/mcp.json` | Generated | Generate from canonical source |\n| `.codex/config.toml` | Generated | Generate from canonical source |\n| `.claude/settings.json` | Agent-specific | Leave (committed hooks) |\n| `.claude/settings.local.json` | Agent-specific | Leave (gitignored permissions) |\n\n### B.3 Migration Steps by Layer\n\n**Order matters.** Start with the lowest-risk layer:\n\n#### Step 1: Instructions (lowest risk)\n\n- If `AGENTS.md` exists: review, keep as canonical\n- If only `CLAUDE.md` exists with full instructions: rename to `AGENTS.md`, create pointer `CLAUDE.md`\n- If both exist with different content: merge into `AGENTS.md`, reduce `CLAUDE.md` to pointer + overrides\n\n#### Step 2: Skills\n\n- Inventory: check `.claude/skills/`, `.cursor/commands/`, `.agents/skills/`\n- If real files in `.claude/skills/`: `git mv` to `.agents/skills/`, replace with symlinks\n- If already in `.agents/skills/`: add `link-skills.sh` and symlinks\n- Add pre-commit hook\n\n#### Step 3: MCP\n\n- Find the most complete MCP config (usually `.mcp.json`)\n- Copy to `.agents/mcp/servers.json` as canonical\n- Create or adapt sync script\n- Run sync, diff outputs against originals to verify\n- Add to pre-commit or CI\n\n#### Step 4: Cleanup\n\n- Add `.agents/AGENTS.md` and `.agents/README.md`\n- Update `.gitignore`\n- Verify with sync check\n\n### B.4 Archetype-Specific Guidance\n\n#### Archetype 1: Code Project (already partially migrated)\n\n**Pattern:** meta-stack, sofa — Python/UV repos with some `.agents/` structure already.\n\n**Typical state:** Has `.agents/skills/`, maybe a sync script that copies (not symlinks), AGENTS.md at root.\n\n**Migration:**\n\n- Replace copy-based sync with symlinks for skills\n- Add `link-skills.sh` and pre-commit hook\n- Ensure MCP generation covers all agents\n- Single atomic commit\n\n**Reference implementation:** [sofa PR #94](https://github.com/StackEng/sofa/pull/94) demonstrates the full migration.\n\n#### Archetype 2: Cursor-Heavy with Submodules\n\n**Pattern:** meta-salley — `.cursor/rules/` with MDC files, git submodules each with their own agent config.\n\n**Key decisions:**\n\n1. **Do NOT migrate Cursor rules.** The `.cursor/rules/*.mdc` files use MDC-specific features (glob scoping, `alwaysApply`, `description` for context-aware loading) that have no cross-agent equivalent. Leave them in `.cursor/rules/`. If you want Claude Code to see the same knowledge, put it in `AGENTS.md` — don't create a new abstraction layer.\n\n2. **Each submodule manages its own config.** Don't centralize submodule agent config in the parent repo. Apply the migration independently to each submodule that needs it. The parent's `.cursor/rules/` handles meta-level navigation only.\n\n3. **MCP across submodules.** If submodules need different MCP servers, each gets its own `.agents/mcp/servers.json`. If they share the same set, the parent's config applies in the multi-root workspace context.\n\n#### Archetype 3: Meta Workspace / Coordination Hub\n\n**Pattern:** iCloud Documents — portfolio coordination with 27+ sub-projects, not a code project.\n\n**Key decisions:**\n\n1. **Whitelist `.gitignore`** needs explicit allows for every agent directory. When a new agent tool appears, add it to the whitelist.\n\n2. **Skills are operational workflows**, not code-generation — `/rally` triages tickets, `/route` dispatches to sub-projects. The SKILL.md format works identically for these.\n\n3. **`AGENTS.md` is a router**, not a code guide:\n\n```markdown\n## Routing\n- **gear tools**: See `gear/AGENTS.md`\n- **Jira tasks**: Read `sherpa/guides/career-sherpa/gear/jira-ticket-template.md`\n```\n\n1. **MCP servers are workspace-wide.** Individual sub-projects have their own repos with their own MCP configs.\n\n### B.5 Decision Tree\n\n```\nIs this file read identically by multiple agents?\n  YES -> Portable. Move to .agents/ or root, symlink from agent dirs.\n\n  NO -> Is the underlying data the same, just different format?\n    YES -> Generated. Canonical source in .agents/, sync script renders.\n\n    NO -> Agent-specific. Leave where it is.\n```\n\n### B.6 Ongoing Maintenance\n\n| Task | How |\n|------|-----|\n| Add a skill | Create in `.agents/skills/`, run `link-skills.sh`, commit both |\n| Install third-party skill | `npx skills add <repo>@<name> -y` |\n| Add MCP server | Edit `.agents/mcp/servers.json`, run sync, commit all generated files |\n| Add new agent tool | Add rendering to sync script, add target to `link-skills.sh` TARGETS array |\n| Validate skills | `skills-ref validate .agents/skills/<name>` |\n| Check sync freshness | `sync-mcp.sh check` (exits non-zero if stale) |\n\n---\n\n## Sources\n\n| Standard | What it governs | Link |\n|----------|----------------|------|\n| Agent Skills spec | SKILL.md format, skill discovery | [agentskills.io/specification](https://agentskills.io/specification) |\n| AGENTS.md / AAIF | Universal agent instructions | [agents.md](https://agents.md), [AAIF (Linux Foundation)](https://aaif.io/) |\n| Model Context Protocol | MCP server definitions | [modelcontextprotocol.io](https://modelcontextprotocol.io) |\n| Vercel Skills CLI | `npx skills add`, skill marketplace | [github.com/vercel-labs/skills](https://github.com/vercel-labs/skills) |\n| skills-ref | Skill validation CLI | [github.com/agentskills/agentskills](https://github.com/agentskills/agentskills) |\n| SSW Rules | Symlink best practices | [ssw.com.au/rules/symlink-agents-to-claude](https://www.ssw.com.au/rules/symlink-agents-to-claude) |\n| Claude Code Skills Docs | Claude-specific skill discovery | [code.claude.com/docs/en/skills](https://code.claude.com/docs/en/skills) |\n| Client Implementation Guide | How agents should scan `.agents/skills/` | [agentskills.io/client-implementation](https://agentskills.io/client-implementation/adding-skills-support.md) |\n| Claude Code .agents/ support request | Community request for native scanning | [github.com/anthropics/claude-code#31005](https://github.com/anthropics/claude-code/issues/31005) |\n", "url": "https://wpnews.pro/news/agent-agnostic-repository-guide", "canonical_source": "https://gist.github.com/davidgibsonp/337be9b80b3f03eccd188235c287bb05", "published_at": "2026-04-21 15:37:04+00:00", "updated_at": "2026-05-22 16:08:16.055863+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence", "large-language-models", "open-source"], "entities": ["Claude", "Cursor", "Codex", "MCP", "AGENTS.md", "AAIF", "agentskills.io"], "alternates": {"html": "https://wpnews.pro/news/agent-agnostic-repository-guide", "markdown": "https://wpnews.pro/news/agent-agnostic-repository-guide.md", "text": "https://wpnews.pro/news/agent-agnostic-repository-guide.txt", "jsonld": "https://wpnews.pro/news/agent-agnostic-repository-guide.jsonld"}}