Skip to content

Instantly share code, notes, and snippets.

@davidgibsonp
Created April 21, 2026 15:37
Show Gist options
  • Select an option

  • Save davidgibsonp/337be9b80b3f03eccd188235c287bb05 to your computer and use it in GitHub Desktop.

Select an option

Save davidgibsonp/337be9b80b3f03eccd188235c287bb05 to your computer and use it in GitHub Desktop.
Agent-Agnostic Repository Guide

Agent-Agnostic Repository Guide

A 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).


The Core Principle

Every piece of agent configuration falls into exactly one of three categories:

Category Strategy Examples
Portable (same format across agents) Store once in .agents/, symlink to agent dirs AGENTS.md, SKILL.md files
Generated (same data, different format) Canonical source in .agents/, sync script renders per-agent MCP config (JSON vs TOML)
Agent-specific (no cross-agent equivalent) Leave in agent-native directory .cursor/rules/*.mdc, .claude/settings.json

If you remember nothing else: portable things get symlinks, generated things get a sync script, agent-specific things stay put.


Part A: New Repo Template

A.1 Directory Layout

repo/
  AGENTS.md                           # Universal instructions (AAIF standard)
  CLAUDE.md                           # Pointer: "@AGENTS.md" + Claude-only overrides

  .agents/
    AGENTS.md                         # Self-management doc for this directory
    skills/                           # Shared skills (committed)
      <skill-name>/
        SKILL.md                      # agentskills.io spec format
        references/                   # Optional supporting docs
        scripts/                      # Optional automation
    skills-local/                     # Private skills (gitignored)
      .gitkeep
    mcp/
      servers.json                    # Canonical MCP server definitions
    scripts/
      link-skills.sh                  # Symlink skills to agent-native dirs
      sync-mcp.sh                    # Generate agent-native MCP configs

  .claude/                            # Generated + agent-specific
    skills/<name> -> ../../.agents/skills/<name>   # Symlinks
    settings.json                     # Agent-specific (hooks, etc.)
  .cursor/                            # Generated + agent-specific
    skills/<name> -> ../../.agents/skills/<name>   # Symlinks
    rules/                            # Agent-specific (MDC format, not portable)
    mcp.json                          # Generated from .agents/mcp/servers.json
  .codex/
    config.toml                       # Generated from .agents/mcp/servers.json
  .mcp.json                           # Generated: Claude project-level MCP

A.2 Layer 1: Instructions (AGENTS.md)

What: Project context, conventions, routing, coding standards. Portable? Yes. AGENTS.md is the AAIF/Linux Foundation standard, read by 20+ agents including Codex, Cursor, Copilot, Gemini CLI, Devin, and more. Sync mechanism: None needed. Most agents read it natively.

Setup:

  1. Create AGENTS.md at repo root with project overview, directory structure, setup commands, coding standards, git conventions.
  2. Create CLAUDE.md as a pointer:
@AGENTS.md

This repo keeps reusable agent assets in `.agents/` and syncs tool-specific
adapters with `.agents/scripts/`.
  1. 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.

Sources: AGENTS.md spec, AAIF / Linux Foundation

A.3 Layer 2: Skills (SKILL.md)

What: Reusable workflows agents can invoke — /rally, /learn, /deploy, etc. Portable? Yes. The Agent Skills spec defines a universal SKILL.md format adopted by 16+ agents. Canonical location: .agents/skills/<skill-name>/SKILL.md Sync mechanism: Symlinks from agent-native dirs.

SKILL.md format (agentskills.io spec):

---
name: my-skill
description: What this skill does and when to use it.
---

Step-by-step instructions for the agent...

Required fields: name (lowercase, hyphens, matches directory name), description. Keep SKILL.md under 500 lines. Use references/ for detailed docs.

The link script (.agents/scripts/link-skills.sh):

#!/usr/bin/env bash
set -euo pipefail

AGENTS_DIR="$(cd "$(dirname "$0")/.." && pwd)"
REPO_ROOT="$(cd "$AGENTS_DIR/.." && pwd)"
TARGETS=(".claude/skills" ".cursor/skills")
declare -A valid_skills

for target_dir in "${TARGETS[@]}"; do
    mkdir -p "$REPO_ROOT/$target_dir"

    for skill_dir in "$AGENTS_DIR"/skills/*/; do
        [ -d "$skill_dir" ] || continue
        name="$(basename "$skill_dir")"
        valid_skills["$name"]=1
        link_target="../../.agents/skills/$name"
        link_path="$REPO_ROOT/$target_dir/$name"

        if [ -L "$link_path" ]; then
            [ "$(readlink "$link_path")" = "$link_target" ] && continue
            rm "$link_path"
        elif [ -e "$link_path" ]; then
            echo "ERROR: $link_path exists but is not a symlink." >&2; exit 1
        fi

        ln -s "$link_target" "$link_path"
        echo "Linked: $link_path -> $link_target"
    done

    # Prune stale symlinks
    for link in "$REPO_ROOT/$target_dir"/*/; do
        [ -L "${link%/}" ] || continue
        link="${link%/}"
        target="$(readlink "$link")"
        if [[ "$target" == *"/.agents/"* ]]; then
            name="$(basename "$link")"
            [ -z "${valid_skills[$name]+x}" ] && rm "$link" && echo "Pruned: $link"
        fi
    done
done

Installing third-party skills (Vercel skills CLI):

npx skills add <repo>@<skill-name> -y
# Installs to .agents/skills/ AND auto-creates .claude/skills/ symlink

The 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.

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.

Sources: Agent Skills spec, Client implementation guide, npx skills, SSW Rules: symlink agents to claude

A.4 Layer 3: MCP Configuration

What: Model Context Protocol server definitions — which external tools the agent can call. Portable? No. Same data, different format per agent. Canonical location: .agents/mcp/servers.json Sync mechanism: Generation script renders per-agent files.

Why generation, not symlinks:

Agent File Format difference
Claude Code .mcp.json JSON. URL servers need "type": "http"
Cursor .cursor/mcp.json JSON. Direct copy, no type field needed
Codex .codex/config.toml TOML. [mcp_servers.<name>] tables

Canonical format (.agents/mcp/servers.json):

{
  "figma": {
    "type": "http",
    "url": "https://mcp.figma.com/mcp"
  },
  "stacks": {
    "type": "http",
    "url": "https://stacksmcp.int.stackoverflow.net/mcp"
  }
}

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).

Sources: MCP specification, AAIF

A.5 Layer 4: Agent-Specific (Leave As-Is)

These have no cross-agent equivalent. Do not try to abstract them.

File Agent Why not portable
.cursor/rules/*.mdc Cursor MDC format with glob scoping (globs: "**/*.py"), conditional loading (alwaysApply) — no equivalent elsewhere
.claude/settings.json Claude Code Hooks, metadata updaters — Claude-specific harness features
.claude/settings.local.json Claude Code Machine-local permissions — always gitignored
.claude/agents/*.md Claude Code Subagent definitions — Claude-specific feature

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.

A.6 Automation

Pre-commit hooks (.pre-commit-config.yaml):

- repo: local
  hooks:
    - id: link-agent-skills
      name: "Sync .agents/skills symlinks"
      entry: .agents/scripts/link-skills.sh
      language: script
      pass_filenames: false
      files: ^\.agents/skills/|^\.claude/skills/|^\.cursor/skills/
    - id: check-agent-mcp
      name: "Verify MCP configs are current"
      entry: .agents/scripts/sync-mcp.sh check
      language: script
      pass_filenames: false
      files: ^\.agents/mcp/

A.7 .gitignore

# Agent skills (machine-local)
.agents/skills-local/*
!.agents/skills-local/.gitkeep

# Agent settings (machine-local)
.claude/settings.local.json
.claude/worktrees/

For whitelist repos (meta workspace pattern where * ignores everything):

!.agents/
!.agents/**
!.claude/
!.claude/**
!.codex/
!.codex/**
!.cursor/
!.cursor/**
!.mcp.json
!AGENTS.md
!CLAUDE.md

A.8 .agents/AGENTS.md Template

This is the self-management doc that lets any agent maintain the directory:

# .agents/

Agent-agnostic configuration following the [Agent Skills](https://agentskills.io)
open standard and [AGENTS.md](https://agents.md) conventions.

## Layout

- `skills/` — Shared skills (committed). Each is a directory with `SKILL.md`.
- `skills-local/` — Private skills (gitignored).
- `mcp/servers.json` — Canonical MCP server config.
- `scripts/` — Sync and validation scripts.

## Adding a skill

1. Create `.agents/skills/<name>/SKILL.md` with `name` + `description` frontmatter
2. Run `.agents/scripts/link-skills.sh`
3. Commit the skill directory and the new symlink

## Installing third-party skills

    npx skills add <repo>@<skill> -y

## Adding an MCP server

1. Edit `.agents/mcp/servers.json`
2. Run `.agents/scripts/sync-mcp.sh`
3. Commit all generated files

## Rules

- Edit skills in `.agents/skills/`, never in `.claude/skills/` or `.cursor/skills/`
- Edit MCP in `.agents/mcp/servers.json`, never in `.mcp.json` or `.cursor/mcp.json`
- Pre-commit hooks enforce sync automatically

A.9 New Repo Checklist

  1. Create AGENTS.md at repo root
  2. Create CLAUDE.md with @AGENTS.md pointer
  3. Create .agents/ with skills/, skills-local/.gitkeep, mcp/servers.json, scripts/, AGENTS.md
  4. Create initial skills in .agents/skills/
  5. Run link-skills.sh to create symlinks
  6. Create or adapt sync script for MCP
  7. Run sync to generate .mcp.json, .cursor/mcp.json, .codex/config.toml
  8. Add pre-commit hooks
  9. Update .gitignore
  10. Verify: symlinks resolve, sync check passes, skills discoverable

Part B: Migration Guide

B.1 Assessment: Audit What You Have

# Find all agent config files
find . -maxdepth 3 \( \
  -name "AGENTS.md" -o -name "CLAUDE.md" -o \
  -name ".mcp.json" -o -name "mcp.json" -o \
  -name "*.mdc" -o -name "SKILL.md" -o \
  -name "settings.json" -o -name "settings.local.json" -o \
  -name "config.toml" \
\) -not -path "*/.venv/*" -not -path "*/node_modules/*"

For each file, classify as Portable, Generated, or Agent-specific.

B.2 Classification Matrix

Asset Category Action
AGENTS.md Portable Keep at root. Create if missing.
CLAUDE.md (full instructions) Portable Move content to AGENTS.md, replace with @AGENTS.md pointer
.claude/skills/*/SKILL.md (real files) Should be portable git mv to .agents/skills/, replace with symlinks
.agents/skills/*/SKILL.md Already portable No change needed
.cursor/commands/*.md (from skills) Generated Mark as generated output, or leave if hand-authored
.cursor/rules/*.mdc Agent-specific Leave in place. MDC format not portable.
.mcp.json Generated Create .agents/mcp/servers.json as canonical, generate from it
.cursor/mcp.json Generated Generate from canonical source
.codex/config.toml Generated Generate from canonical source
.claude/settings.json Agent-specific Leave (committed hooks)
.claude/settings.local.json Agent-specific Leave (gitignored permissions)

B.3 Migration Steps by Layer

Order matters. Start with the lowest-risk layer:

Step 1: Instructions (lowest risk)

  • If AGENTS.md exists: review, keep as canonical
  • If only CLAUDE.md exists with full instructions: rename to AGENTS.md, create pointer CLAUDE.md
  • If both exist with different content: merge into AGENTS.md, reduce CLAUDE.md to pointer + overrides

Step 2: Skills

  • Inventory: check .claude/skills/, .cursor/commands/, .agents/skills/
  • If real files in .claude/skills/: git mv to .agents/skills/, replace with symlinks
  • If already in .agents/skills/: add link-skills.sh and symlinks
  • Add pre-commit hook

Step 3: MCP

  • Find the most complete MCP config (usually .mcp.json)
  • Copy to .agents/mcp/servers.json as canonical
  • Create or adapt sync script
  • Run sync, diff outputs against originals to verify
  • Add to pre-commit or CI

Step 4: Cleanup

  • Add .agents/AGENTS.md and .agents/README.md
  • Update .gitignore
  • Verify with sync check

B.4 Archetype-Specific Guidance

Archetype 1: Code Project (already partially migrated)

Pattern: meta-stack, sofa — Python/UV repos with some .agents/ structure already.

Typical state: Has .agents/skills/, maybe a sync script that copies (not symlinks), AGENTS.md at root.

Migration:

  • Replace copy-based sync with symlinks for skills
  • Add link-skills.sh and pre-commit hook
  • Ensure MCP generation covers all agents
  • Single atomic commit

Reference implementation: sofa PR #94 demonstrates the full migration.

Archetype 2: Cursor-Heavy with Submodules

Pattern: meta-salley — .cursor/rules/ with MDC files, git submodules each with their own agent config.

Key decisions:

  1. 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.

  2. 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.

  3. 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.

Archetype 3: Meta Workspace / Coordination Hub

Pattern: iCloud Documents — portfolio coordination with 27+ sub-projects, not a code project.

Key decisions:

  1. Whitelist .gitignore needs explicit allows for every agent directory. When a new agent tool appears, add it to the whitelist.

  2. Skills are operational workflows, not code-generation — /rally triages tickets, /route dispatches to sub-projects. The SKILL.md format works identically for these.

  3. AGENTS.md is a router, not a code guide:

## Routing
- **gear tools**: See `gear/AGENTS.md`
- **Jira tasks**: Read `sherpa/guides/career-sherpa/gear/jira-ticket-template.md`
  1. MCP servers are workspace-wide. Individual sub-projects have their own repos with their own MCP configs.

B.5 Decision Tree

Is this file read identically by multiple agents?
  YES -> Portable. Move to .agents/ or root, symlink from agent dirs.

  NO -> Is the underlying data the same, just different format?
    YES -> Generated. Canonical source in .agents/, sync script renders.

    NO -> Agent-specific. Leave where it is.

B.6 Ongoing Maintenance

Task How
Add a skill Create in .agents/skills/, run link-skills.sh, commit both
Install third-party skill npx skills add <repo>@<name> -y
Add MCP server Edit .agents/mcp/servers.json, run sync, commit all generated files
Add new agent tool Add rendering to sync script, add target to link-skills.sh TARGETS array
Validate skills skills-ref validate .agents/skills/<name>
Check sync freshness sync-mcp.sh check (exits non-zero if stale)

Sources

Standard What it governs Link
Agent Skills spec SKILL.md format, skill discovery agentskills.io/specification
AGENTS.md / AAIF Universal agent instructions agents.md, AAIF (Linux Foundation)
Model Context Protocol MCP server definitions modelcontextprotocol.io
Vercel Skills CLI npx skills add, skill marketplace github.com/vercel-labs/skills
skills-ref Skill validation CLI github.com/agentskills/agentskills
SSW Rules Symlink best practices ssw.com.au/rules/symlink-agents-to-claude
Claude Code Skills Docs Claude-specific skill discovery code.claude.com/docs/en/skills
Client Implementation Guide How agents should scan .agents/skills/ agentskills.io/client-implementation
Claude Code .agents/ support request Community request for native scanning github.com/anthropics/claude-code#31005
@caioribeiroclw-pixel

Copy link
Copy Markdown

This guide is useful because it separates portable / generated / agent-specific config. One nuance I’d add: “portable” should probably mean tested on native discovery surfaces, not just “same markdown can be symlinked everywhere”.

A few cases where I’ve seen the distinction matter:

  • AGENTS.md can be broadly readable, but scope/precedence/debug output differs by harness.
  • SKILL.md may be a shared format, but discovery path and activation are not identical across .claude/skills, .cursor/skills, .codex/skills, etc.
  • .cursor/rules/*.mdc being agent-specific is the right call; converting that into a generic skill can silently lose glob/always-on semantics.
  • Symlinks prove the bytes are shared, not that the agent discovered them or preserved the same behavior.

A lightweight evidence block next to each portability claim would make the guide stronger, e.g.:

testedOn:
  - tool: Claude Code
    nativeDiscoveryPath: .claude/skills/<name>/SKILL.md
    activation: on-demand skill
  - tool: Cursor
    nativeDiscoveryPath: .cursor/skills/<name>/SKILL.md
    activation: dynamic skill discovery
knownLossyTargets:
  - target: Cursor rules -> SKILL.md
    loss: glob/alwaysApply semantics become procedural/on-demand
manualActivationRequired: []

I maintain Pluribus, and this is the exact wedge I’m trying to automate with audit --fidelity-report: generated file exists ≠ native discovery ≠ equivalent semantics. Even without using a tool, adding this kind of evidence checklist would help readers avoid overclaiming “agent agnostic” when something is actually a generic fallback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment