AI Coding Project Migration: One Asset Source, Two Thin Adapters
When developers move a project from one AI coding assistant to another, the intuitive move is to copy the entire configuration directory and rename it. What looks like a quick migration actually leaves you maintaining two rule sets, two memory stores, and two workflows: a convention adjusted on one side this week, a silent failure to sync it, and within a few weeks the two sides quietly disagree about the same project. The right approach is to keep exactly one copy of the project assets and add a very thin adapter layer for each assistant. This article lays out a complete dual-assistant compatibility scheme — the asset/adapter split, the target directory structure, example files and scripts, the step-by-step migration path, and drift-prevention checks — that can be adopted as-is.
1. Don’t Copy First: Where the Real Cost of Migration Sits
The first instinct of most developers on this kind of migration is “copy the whole directory and rename it.” Files do land in place quickly, and that is exactly when the problems start accumulating:
- Two rule sets. Architecture conventions and coding standards get written twice. Add a constraint in one assistant and the other one simply “doesn’t know” it exists.
- Two memory stores. Project status, to-dos, and hard-won lessons are recorded separately on each side. Over time the two sides no longer agree on how far the project has actually gotten.
- Two workflows. The same repetitive task is maintained as two scripts or two process documents; you fix a bug in one and the other still carries it.
- Synchronization by memory. “Remember to sync” works for a few days; it does not survive weeks of normal work. Divergence is close to inevitable.
This is the core of the problem: copying buys you “it works,” not “it’s compatible.” Compatibility means both assistants share one understanding of the project; copying manufactures two competing understandings that drift apart. The goal of migration is not to make another assistant “able to read the files” — it is to make it work from the same facts on either side.
2. First, Separate What You Are Actually Migrating
A long-lived AI coding assistant project directory usually contains two fundamentally different kinds of content.
First kind: project assets — everything independent of the tool.
- Project conventions and architecture rules: module boundaries, code style, dependency management principles;
- Long-term context: project purpose, current progress, next steps;
- Decision records and pitfall lists: why an approach was chosen, which traps not to step in again;
- Domain knowledge and reference documents;
- Repeatable workflows: process descriptions and scripts for build, checks, release, regression verification, and so on.
These things merely “happen to live in a particular assistant’s config directory.” They belong to the project itself.
Second kind: tool adaptation — the runtime conventions of each assistant.
- Which entry file is read automatically at startup;
- Where custom capability modules (Skills) are discovered from, and in what format they are declared;
- Where tool and external-service connection settings live, and how their fields are organized;
- Which events the hooks listen to, what protocol their output follows, and how that output is fed back to the model;
- What permission and approval model applies to command execution;
- How context is loaded in layers, and which length limits apply.
The test: if it still holds after you switch assistants, it is a project asset; if it only serves one assistant’s runtime mechanics, it is tool adaptation. Skip this split and the easy “copy everything” route becomes the most expensive option to maintain.
3. Target Structure: Single Asset Source, Extremely Thin Adapters
Organize the project into three areas, with a single root entry that “walks” both assistants to the same assets:
project-root/├── shared/ # Project assets: the only source of truth, shared by both assistants│ ├── README.md # Asset overview, reading order, maintenance rules│ ├── context.md # Long-term context: purpose, status, next steps│ ├── decisions.md # Decision records (append-only, by date)│ ├── pitfalls.md # Pitfall records (archived by topic)│ ├── domain/ # Domain knowledge and reference docs│ └── workflows/ # Reusable process docs and scripts├── skills/ # Capability definitions: tool-agnostic "what to do, how to do it"│ └── <skill-name>/SKILL.md├── adapters/ # Tool adaptation layer: one directory per assistant, as thin as possible│ ├── agent-a/ # The assistant used originally│ │ ├── ENTRY.md # Startup entry for this side (pointers only)│ │ ├── skills.registry.json # Capability discovery configuration│ │ ├── tools.json # Tool and external service connection config│ │ └── hooks/ # Event hook scripts│ └── agent-b/ # The newly adopted assistant│ ├── ENTRY.md│ ├── skills.registry.json│ ├── tools.json│ └── hooks/├── ENTRY.md # Generic root entry: the directory map shared by both sides└── checks/└── verify-assets.sh # Asset consistency check script
Three structural rules:
- One copy of the assets.
shared/andskills/must never contain any “duplicate version.” - Adapters only reference, never copy. Files under
adapters/only describe “where to look and how to connect”; they carry no rule text. - The check script is permanent. Structure and conventions are enforced by a script, not by someone remembering.
4. Entry Layer: Thin Entries to Carry the Instruction Chain
Before starting a task, every assistant automatically reads its own entry file and then rolls project instructions up the directory tree according to a set of rules — and the whole instruction chain has a default length cap. A bloated entry file stuffed with a full protocol quickly approaches that cap and pushes the genuinely important constraints out.
The right approach is a thin, precise entry: pointers only, no rule text.
Root entry ENTRY.md:
# Project Entry (Generic)This file is the common entry point for all AI coding assistants on this project.It only describes "where to look"; it carries no rule text.## Reading Order1. `shared/context.md` —— project purpose, current progress, next steps2. `shared/decisions.md` —— key technical decisions and their rationale3. `shared/pitfalls.md` —— known issues and forbidden zones## Directory Map- `shared/` project assets (single source of truth)- `skills/` capability definitions- `adapters/` per-assistant adaptation configuration- `shared/workflows/` reusable processes and scripts## Hard Rules- When project rules, memory, or processes need to change, edit only `shared/` and `skills/`;- `adapters/` may hold adaptation configuration only; copying asset text is forbidden;- When the two sides disagree, `shared/` wins, and the other side is fixed immediately.
Agent A entry adapters/agent-a/ENTRY.md:
# Agent A EntryBefore starting, read `ENTRY.md` in the project root in full, and follow itsreading order and hard rules exactly. No rule text is repeated here.
Agent B entry adapters/agent-b/ENTRY.md:
# Agent B EntryBefore starting a task, read `ENTRY.md` in the project root and load contextfollowing its "Reading Order".If this directory contains more specific adaptation notes, they take precedenceover the generic description in `ENTRY.md`.
This matches the common “nearest wins” rule: the closer a rule file is to the working directory, the higher its priority. The root entry sets direction; subdirectory entries add local detail; and the rule set both sides load ends up identical.
5. Memory Layer: From “Conversation Memory” to a File-Based Ledger
Long-term context has two failure modes: it lives in chat history and disappears when you switch assistants, or it gets updated by rewriting the whole document, burning a large slice of the context budget every time. A better model is a structured, incrementally maintained ledger.
shared/context.md example:
# Project Context## PurposeOrder fulfillment service for an internal team, responsible for order statetransitions and exception handling.## Current StageFulfillment state machine refactor is 60% complete; the payment callback pathhas not been switched over yet.## Next Steps1. Fill in unit tests for the state machine2. Roll out the payment callback gradually3. Clean up the old path after a week of observation## Update Rules- Before each session ends, update only the "Current Stage" and "Next Steps" sections;- Major design changes go into `decisions.md`; do not write long arguments here.
shared/decisions.md uses one uniform record format so both sides read information at the same granularity:
## 2025-03-12 Fulfillment state machine moved to explicit state enums- Background: status was assembled from several boolean fields; the combinationsexploded and caused missed cases.- Decision: a single state enum plus a legal-transition table.- Cost: a one-time data migration.
shared/pitfalls.md is archived by topic, and each entry contains “symptom — cause — how to avoid it,” so the record is reusable rather than a bare conclusion.
6. Capability Layer: Define Once, Register in Many Places
Custom capability modules are the accumulated value of any long-lived project. The most common migration mistake is copying the capability text into both assistants’ directories, after which every change has to be made twice.
Split it into two layers:
- Definition layer:
skills/<name>/SKILL.mddescribes the capability’s goal, when it applies, its steps, and its inputs and outputs — independent of any assistant; - Registration layer: each adapter directory uses a manifest to declare “which capabilities to discover, and how to connect them.”
skills/release-check/SKILL.md example:
# Pre-Release Checks## When to UseWhen the user asks to release, create a tag, or prepare to merge into the main branch.## Steps1. Run `shared/workflows/preflight.sh` and confirm everything passes;2. Summarize the modules and risk points touched by this change set;3. Output the check conclusion; if any item failed, fix it and retry.## OutputA short conclusion plus a list of failed items (if any).
Agent A’s registry adapters/agent-a/skills.registry.json:
{"formatVersion": 1,"searchRoots": ["skills"],"entryFile": "SKILL.md","skills": [{ "name": "release-check", "path": "skills/release-check", "enabled": true }]}
Agent B’s registry keeps the same structure; if that assistant requires different field names or directory layout, only the manifest under adapters/agent-b/ changes. The capability body always exists once, and adding a capability means adding one directory plus one line in each of the two manifests.
7. Tool Connections and Hooks: Per-Side Config, Shared Logic
Tool and external service connections. Different assistants often differ in field naming, nesting depth, and how credentials are passed. The rule is “parameters from one source, formats per side”: extract endpoints, timeouts, retries, and permission levels into a single tool-agnostic set of defaults, and let each adapter directory only translate it into its own format.
{"defaults": { "timeoutMs": 15000, "retries": 2, "permission": "readonly" },"services": {"issueTracker": { "endpointEnv": "TRACKER_ENDPOINT", "tokenEnv": "TRACKER_TOKEN" },"logQuery": { "endpointEnv": "LOG_ENDPOINT", "tokenEnv": "LOG_TOKEN" }}}
Secrets are injected through environment variables or a credential management service and never committed to the repository. Redact log output so endpoints and token fragments do not end up in records.
Event hooks. A hook’s value is turning project red lines into machine-enforceable checks, but its implementation is tightly coupled to each assistant’s event model and output protocol. The safe pattern is shared logic with a per-side shell:
#!/usr/bin/env bash# adapters/agent-a/hooks/pre-write.sh — thin shell for this side; protocol translation onlyset -euo pipefailproject_root="$(cd "$(dirname "$0")/../../.." && pwd)"# 1) Call the tool-agnostic shared validation logicif ! bash "$project_root/shared/workflows/guard-write.sh"; thenecho '{"decision":"block","reason":"write target hits a protected path or confirmation is missing"}'exit 0fiecho '{"decision":"allow"}'
The shared validation logic shared/workflows/guard-write.sh should cover at least three red lines:
- No direct changes to protected directories (such as data migration scripts and production config templates);
- No deletion, forced overwrite, or bulk rewrite without explicit confirmation;
- No credentials or tokens written into any project file.
The other side needs only another thin shell that converts the shared script’s exit code into the output format and event names that assistant expects. There is one set of red lines; there can be many ways to express them.
8. Six Steps to Land the Migration
- Inventory the baseline. List every asset (entry files, memory files, capabilities, hooks, scripts, configuration) and tag each item as “asset” or “adaptation.”
- Build the skeleton. Create
shared/,skills/, andadapters/, move assets in by type, and leave the original directory untouched for now. - Write the generic entry. Finish
ENTRY.mdand both thin entries so the new assistant can first “find” things, then read them accurately. - Add the adapter layer. Write capability registries, tool connection config, and hook shells for the new side — references only, no copies.
- Run in parallel. Use both assistants for a while and watch for missing rules or inconsistent behavior.
- Switch and clean up. Once stable, point the original assistant’s entry at the new structure, delete the duplicate copies, and keep a single adapter directory.
9. Drift Prevention: Make “Forgot to Sync” Impossible
Structure and conventions have to be held by mechanisms:
- No copying. Adapters may reference paths only; any “duplicate file” counts as a defect.
- Checks up front. Hook the consistency check into a pre-commit hook or CI pipeline so failures block the change.
- Traceable changes. Decisions and pitfalls are appended to
decisions.mdandpitfalls.md; history is never overwritten. - Regular audits. Run a full check weekly, produce an asset inventory plus recent changes, and confirm both sides agree.
checks/verify-assets.sh example:
#!/usr/bin/env bash# Asset consistency check: structure, single source, entry size, sensitive dataset -uo pipefailroot="$(cd "$(dirname "$0")/.." && pwd)"errors=0err() { echo "[FAIL] $1"; errors=$((errors + 1)); }ok() { echo "[ OK ] $1"; }# 1) Required asset files existfor f in shared/README.md shared/context.md shared/decisions.md \shared/pitfalls.md ENTRY.md; do[ -f "$root/$f" ] && ok "found $f" || err "missing $f"done# 2) Each adapter directory is structurally completefor d in "$root"/adapters/*/; do[ -d "$d" ] || continuefor f in ENTRY.md skills.registry.json tools.json; do[ -f "$d$f" ] && ok "$(basename "$d")/$f" || err "$(basename "$d") missing $f"done# 3) The entry must stay "thin": pointers onlylines=$(wc -l < "$d/ENTRY.md" 2>/dev/null || echo 0)if [ "$lines" -le 40 ]; thenok "$(basename "$d") entry size is under control (${lines} lines)"elseerr "$(basename "$d") entry is too long (${lines} lines); move rule text into shared/"figrep -q "ENTRY.md" "$d/ENTRY.md" \&& ok "$(basename "$d") entry points to the generic entry" \|| err "$(basename "$d") entry does not point to the generic entry"done# 4) No asset copies inside the adapter layerif find "$root/adapters" -name 'context.md' -o -name 'decisions.md' \-o -name 'pitfalls.md' | grep -q .; thenerr "asset copies found in the adapter layer; single-source rule violated"elseok "no asset copies in the adapter layer"fi# 5) Sensitive data scan (illustrative: replace with the patterns your project uses)if grep -rniE '(secret|token|password)[[:space:]]*[:=][[:space:]]*["'"'"']?[A-Za-z0-9_-]{12,}' \"$root/shared" "$root/adapters" >/dev/null 2>&1; thenerr "suspected hardcoded credential; use environment variables or a credential management service"elseok "no hardcoded credentials found"fiecho "-----------------------------------------"if [ "$errors" -eq 0 ]; thenecho "All checks passed"; exit 0elseecho "$errors check(s) failed"; exit 1fi
If your team already hosts project artifacts in the cloud, versioned asset packages can go into object storage, check results can be sent to a log service, and monitoring alerts can be configured for consecutive failures. On Baidu AI Cloud this maps naturally onto a closed loop of “object storage for asset snapshots + log service for audit trail + monitoring alerts as a safety net”; on other cloud platforms the same can be assembled from the equivalent generic capabilities. Either way the core is unchanged: single-source assets, automated checks.
10. Verification Checklist After the Switch
- Open the project in the new assistant: can it state the project purpose, current stage, and next steps without asking you anything?
- Are all three red lines (no changes to protected paths, confirmation before dangerous operations, no credentials on disk) actually enforced?
- Are capabilities discovered and behaving consistently, and does editing a definition take effect on both sides?
- Do hook trigger timing and output format match that assistant’s protocol?
- Does the check script report zero failures?
- Are there no longer any “other-side-only” duplicate files in the asset directories?
11. Common Mistakes
- Copy the whole directory and rename it: fastest in the short term, most expensive in the long term, and divergence is nearly certain.
- Fill the entry with rule text: pushes against the instruction length cap and squeezes key constraints out of context.
- Rely on conversation history for memory: amnesia on every switch, and nothing is auditable.
- Put business rules in the adapter layer: written twice, which is just divergence in a new location.
- Ignore permission model differences: the same “just run it” can mean completely different risk levels across assistants, so red lines must become executable checks.
Conclusion
Dual-assistant compatibility is not “both assistants can open the project”; it is “both assistants share the same understanding of the project.” Three things get you there: separate assets from adaptation completely, make entries pointers rather than rule text, and hand consistency to a script instead of to memory. Once rules, memory, and workflows have exactly one source, migration stops being an ongoing “move plus keep in sync” burden and becomes a one-time structural change — and adding a third assistant later costs only one more thin adapter directory.
