Last week I diagnosed the disease: six AI coding tools, six proprietary config formats, zero interoperability. CLAUDE.md invisible to Cursor. .cursor/rules meaningless to Copilot. Weeks of accumulated team intelligence locked inside whichever vendor's parser happens to read it.
Every response to that piece agreed the lock-in is real — and then asked the same question: "So what do I do about it?" Fair. Diagnosing a hostage situation without a rescue plan is just commentary. Here's the rescue plan.
Why "choose wisely" stopped being enough
The ground shifted three times in the past week alone. GitHub froze all individual Copilot signups on April 20 because agentic compute blew past what a flat subscription can cover — VP of Product Joe Binder admitted that "agentic workflows have fundamentally changed Copilot's compute demands." On April 15, Zed shipped parallel subagents and a universal LLM gateway. On April 14, Anthropic rebuilt Claude Code into a desktop app with cloud-triggered Routines. OpenAI updated its Agents SDK on April 15 with sandboxed execution and MCP integrations. Tools mutate weekly. Your rules shouldn't be trapped inside whichever one you picked six months ago.
You already know the problem. This guide gives you a working solution you can commit today.
The fix: one canonical file, five vendor copies
The concept is offensively simple. Keep one source-of-truth rules file in a vendor-neutral directory. Sync it to every vendor format with a shell script. Never edit the vendor files directly.
Step 1: Create .ai/rules.md
Pick a directory name no vendor has claimed. .ai/ works.
.ai/
├── rules.md # Canonical project rules
├── architecture.md # System design context
├── patterns.md # Code conventions
└── sync.sh # The script that sets you free
Your rules.md is plain Markdown:
---
project: my-app
lang: [typescript, python]
updated: 2026-04-21
---
# Project Rules
## Code Style
- Strict TypeScript. No `any`. Ever.
- Python: Black formatter, 88-char lines.
- All functions get docstrings. No exceptions.
## Architecture
- Monorepo: apps/ for services, packages/ for shared libs.
- API routes in `src/routes/`, logic in `src/services/`.
- Never import across apps directly. Use packages.
## Testing
- Unit tests co-located: `foo.ts` → `foo.test.ts`.
- Integration tests in `__tests__/integration/`.
- 80% branch coverage minimum on services/.
## Deployment
- Main branch auto-deploys to staging.
- Production: manual approval + passing E2E.
- Env vars in Vault, never in .env files.
## Gotchas
- Payments service uses legacy Stripe v2 client. Don't refactor — vendor contract.
- GraphQL types generate at build time. Run `make codegen` after schema changes.
Source of truth. Any tool can read it. Any human can read it. No vendor magic, just Markdown.
Step 2: The sync script
#!/usr/bin/env bash
set -euo pipefail
CANONICAL=".ai/rules.md"
[ ! -f "$CANONICAL" ] && echo "No ${CANONICAL} found." && exit 1
HEADER="# Auto-generated from .ai/rules.md — do not edit directly"
BODY=$(printf '%s\n\n%s' "$HEADER" "$(cat "$CANONICAL")")
echo "$BODY" > CLAUDE.md # Claude Code
mkdir -p .cursor && echo "$BODY" > .cursor/rules # Cursor
mkdir -p .github && echo "$BODY" > .github/copilot-instructions.md # GitHub Copilot
echo "$BODY" > GEMINI.md # Gemini
mkdir -p .windsurf && echo "$BODY" > .windsurf/rules # Windsurf
echo "Synced to 5 vendor configs."
Twenty lines. Five vendors. One source. Run it after every edit. That's the whole trick.
Step 3: Automate it because you won't remember
You know yourself. Add a pre-commit hook:
#!/usr/bin/env bash
# .git/hooks/pre-commit (or husky / lefthook)
if git diff --cached --name-only | grep -q "^\.ai/"; then
echo "Changes in .ai/ — syncing vendor configs..."
bash .ai/sync.sh
git add CLAUDE.md .cursor/rules .github/copilot-instructions.md \
GEMINI.md .windsurf/rules
fi
Edit the canonical file, commit, vendor copies update themselves. The # Auto-generated header tells teammates to keep their hands off the generated files.
Step 4: Architecture context
Rules alone aren't enough. AI tools also consume architecture docs and component maps. Same pattern — keep them in .ai/, concatenate during sync:
<!-- .ai/architecture.md -->
# System Architecture
## Services
- **api-gateway**: Express.js — auth + routing
- **user-service**: Python/FastAPI — owns user data
- **payments**: Node.js — Stripe integration (legacy v2)
- **notifications**: Go — async via SQS
## Data Flow
Requests → api-gateway → service → own DB.
Cross-service: SQS events only. Never direct HTTP.
Extend sync.sh to concatenate rules.md + architecture.md + patterns.md. Claude Code handles multiple context files natively; for tools that don't, one big file works fine.
What you can't make portable
Here's where the vendors earn their lock-in, and where I stop pretending this fixes everything.
Agent runtime configs. Claude Code's Routines — cloud agents triggered by schedules or GitHub events — have no Cursor equivalent. Cursor's parallel agent orchestration works nothing like Zed's subagents. These are runtime behaviors, not static context. No config file captures them because they aren't config. They're product features you're renting.
Accumulated memory. Claude Code builds MEMORY.md over time — a log of past decisions, mistakes, learned patterns. Knowledge the AI generates during use, not something you author. You can't sync it because it doesn't exist until the AI creates it. Switch tools, lose the memory. Like changing therapists and starting from session one, except the therapist also forgot your name.
Model-tuned wording. "Always use descriptive variable names" works everywhere. But if you've spent weeks tuning rules to exploit how Claude handles ambiguity or dodge GPT's tendency to over-abstract, those nuances don't port. Different models, different quirks, different failure modes.
The portable layer covers roughly 80% of what makes your AI tool useful on your project. The remaining 20% is genuinely vendor-specific. Knowing the boundary matters more than pretending it doesn't exist.
CI: trust nobody, especially yourself
Add drift detection to your pipeline:
# .github/workflows/ai-rules-check.yml
name: AI Rules Sync Check
on: [pull_request]
jobs:
check-sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify vendor configs match source
run: |
bash .ai/sync.sh
if ! git diff --quiet; then
echo "Vendor configs drifted from .ai/rules.md"
git diff --stat
exit 1
fi
Someone edits CLAUDE.md by hand? CI kills the PR. Drift gone. A machine that doesn't care about your feelings or your deadline enforces compliance.
Why no vendor will build this for you
MCP gave us a universal protocol for tool connections. Nobody's done the same for project context. No ai-rules.json standard, no interoperability spec, no working group. Every vendor benefits from the incompatibility — accidental lock-in that costs nothing to maintain and pays in retention.
JetBrains surveyed 10,000+ developers in April 2026 and found Claude Code sitting at 91% satisfaction with a +54 NPS. Impressive numbers that measure sunk cost as much as quality. Teams fifty CLAUDE.md files deep across their repos don't switch. Not because Claude is irreplaceable, but because the migration math is brutal enough to kill the conversation before it starts.
Your .ai/rules.md turns that math from "two weeks of manual rewriting" into "run the script, check the diff." It won't port everything. That 20% — the memory, the runtime behaviors, the model-specific tuning — still costs real effort. But it's the difference between being locked in by choice and locked in by negligence.
The tools don't want you to build this. They don't prevent it either. They just count on you not bothering.
Bother.



