Switching AI Coding Tools Without Losing Context: A Shared Local Memory Layer
This article explains how to keep project context portable across AI coding assistants by storing it in a repository-local, tool-neutral memory layer. It covers the real source of context-switching pain, five categories of durable project knowledge, why copy-and-paste context transfer fails, a single-source-of-truth adapter architecture, a practical directory structure, layered on-demand loading, lifecycle governance, consistency checks, security boundaries, a phased rollout plan, and the limits of the approach.
1. The real problem: context is not portable
Running two AI coding assistants in parallel is already a rational engineering choice. Single-vendor service availability, rate-limiting policies, and model-version release cadence all carry uncertainty. Putting the entire development workflow behind one entry point concentrates risk. The value of a backup is not that it is “smarter,” but that it is “another option that still works.”
However, once you start working across two tools, the pain point appears immediately, and it has little to do with model capability: the same project background has to be re-explained repeatedly between tools. Why was a particular state-management approach chosen? Which API response structure carries historical baggage? Where did the last change stop? That information usually does not exist in the code. It exists only in conversation history, and conversation history is the least portable asset.
Defining the problem accurately matters. It is not “the account was blocked and the records were lost.” It is this: project context is bound to the session storage of a tool rather than to the project itself. As long as context lives inside one vendor’s conversation store, the cost of switching tools, switching machines, or handing work to another team member will be paid again and again.
2. Breaking down “context”: five categories of durable project facts
The first improvement is to reject the vague word “context.” The content that can actually be distilled and reused can be split into five clear categories. The first four can exist independently of any specific tool:
- Project structure facts: module layout, directory conventions, entry points, and data-flow direction.
- Engineering command facts: exact commands for installation, build, test, linting, formatting, and migrations.
- Decision records: why A was chosen over B, what was given up, and what residual costs remain. This is the most valuable category and the easiest to lose.
- Constraints and prohibitions: coding standards, dependency types that must not be introduced, boundary conditions that must be covered, and security or compliance requirements.
- Interaction preferences: answer language, comment style, change granularity, and whether the tool may modify files directly.
The fifth category is indeed tied to specific tools, but the first four are completely decoupled from them. If the decoupled parts are moved into the repository, most of the switching cost disappears. The remaining session state, such as which function is currently being edited, is short-lived and harmless if lost.
3. Why copy-and-paste keeps failing
The copy-and-paste approach is not merely “slightly inefficient.” It is structurally unsustainable:
- It is a snapshot, not a link. What gets pasted is a text copy from one moment in time. Later updates on either side do not flow back. The same fact exists in N different places, and consistency cost grows roughly with the square of the number of tools.
- It is not auditable or traceable. No one can tell whether descriptions of the same project background remain consistent across three conversations, and the rationale behind a code change is not visible during code review.
- It wastes context budget. Context window size is a finite resource. Manually pasting several thousand words of background crowds out space for code and retrieval results, and it dilutes the model’s attention to key constraints. It is commonly observed in practice that the effective utilization of middle-section information drops when context becomes too long. Full injection does not mean effective understanding.
- It does not travel with people. When a new colleague joins, or when you switch to another machine, these assets reset to zero.
The conclusion is clear: context must become a first-class citizen of the repository, versionable, reviewable, and verifiable, rather than a private cache owned by one product.
4. Core idea: single source of truth plus adapter projections
The skeleton of the solution fits in one sentence: memory is stored inside the repository in a tool-neutral format as the single source of truth; each tool uses its own adapter to generate the rule file it needs from that source.
This structure is isomorphic to a compiler toolchain: source code is the single source of truth, platform-specific artifacts are generated by the build process, and generated artifacts are not manually edited.
- Source: Markdown files with YAML front matter under
.ai/memory/. - Adapter: a short script that renders the source into the project-level rule files expected by each tool. Different tools load files by different names and follow different activation rules. Consult each tool’s official documentation rather than relying on memory or hard-coded assumptions.
- Artifacts: generated rule files are either excluded by
.gitignoreor checked in CI to verify that they remain in sync with the source.
The benefit is that adding a new tool changes the cost from “re-explaining the entire background” to “writing a roughly twenty-line rendering template.”
5. Directory structure and file format
A minimal recommended structure:
repo/├── .ai/│ ├── memory/│ │ ├── project.md # structure, stack, and how to run│ │ ├── commands.md # engineering command list│ │ ├── constraints.md # standards, prohibitions, and security requirements│ │ ├── glossary.md # domain terms and abbreviations│ │ └── decisions/│ │ ├── 0001-orm-choice.md│ │ └── 0002-error-model.md│ ├── tasks/│ │ └── 2026-08-19-refund-flow.md│ └── adapters/│ ├── render.mjs│ └── templates/└── docs/adr/ # align with the team’s existing ADR directory
Each memory file should carry metadata. This metadata is the foundation for later governance:
---id: decision-0001type: decisionscope: backendupdated_at: 2026-08-12verified_at: 2026-08-18 # last manual confirmation that it still holdsstatus: active # active | stale | supersededowners: [team-payments]---# Data access layer choice## DecisionUse a lightweight query builder plus hand-written SQL. Do not introduce a full-featured ORM.## Background and alternatives- Alternative 1: Full-featured ORM. Higher development efficiency.- Alternative 2: Pure hand-written SQL. Maximum control but more boilerplate.## Why it was rejectedReporting queries require window functions and complex joins. Full-featured ORMs do not express them well enough, so the team would eventually fall back to raw SQL and end up maintaining two mental models.## Residual costPagination and soft deletes must be implemented manually in the repository layer, and mappings must be written by hand when adding entities.
Decision records must include “why it was rejected” and “residual cost.” A memory that contains only the conclusion has low value, because the tool cannot tell whether a new proposal is repeating an old path that was already rejected.
6. Layering and on-demand loading: controlling the context budget
Do not try to inject all memory at once. Layer memory by scope and let tools read it on demand:
- L0 Global preferences: personal or team-wide style preferences that apply across projects.
- L1 Organizational standards: coding standards, approved dependency lists, and security baselines.
- L2 Project facts: structure, commands, constraints, and glossary information described above.
- L3 Task snapshots: single-task state under
.ai/tasks/, with a short lifecycle, archived when the task closes.
For loading strategy, rule files should contain only indexes and summaries, while details are exposed through explicit file paths so the tool can read them when needed:
## Memory index (read on demand; do not load everything at once)- Engineering commands → `.ai/memory/commands.md`- Hard constraints → `.ai/memory/constraints.md`- Architecture decisions → `.ai/memory/decisions/` (sort by ID ascending and read the summary section first)## Summary of hard constraints- Do not add new runtime dependencies unless a justification is recorded in constraints.md.- All external interfaces must have contract tests.
At the same time, do not write facts into memory when they can be read directly from the environment. The directory tree, dependency versions, Git history, and test output are authoritative and do not expire. Let the tool run commands to inspect them; that is far more reliable than pasting a copy that will become stale:
# Prefer letting the tool retrieve this directly instead of relying on a memory copygit log --oneline -20git diff --statcat package.json | jq '.scripts'
7. Lifecycle governance: memory decays
Most solutions stop at “create a file.” Three months later, the file begins to lie: the recorded startup command has been renamed, and the documented architecture decision has been overturned. Shared memory without a governance mechanism is more dangerous than no memory, because it actively misleads.
Four steps are necessary:
- Write: make a fixed close-out action part of every task. Update
project.md, add a decision record if needed, and remove temporary notes for completed work. This action should be written into the task definition, not left to individual discipline. - Validate: automatically compare memory with code in CI. See the example in the next section.
- Retire: automatically mark entries as
stalewhenverified_atexceeds a threshold. Downgrade their display in rule files and prompt for confirmation. Overturned decisions should be markedsupersededand linked to their successor instead of being deleted. The history of decisions is itself an asset. - Handle conflicts: when two memory entries contradict each other, prefer the one with the newer
verified_at, and mark the conflicting entries as “pending manual confirmation.” Do not let the tool silently merge contradictory information. That can create hard-to-detect false premises.
8. Consistency checks: making memory verifiable
Governance must become an executable check. The following script verifies whether the commands registered in memory actually exist, preventing documentation from drifting away from the engineering setup:
// .ai/adapters/check-memory.mjsimport { readFileSync } from 'node:fs';import { execSync } from 'node:child_process';const doc = readFileSync('.ai/memory/commands.md', 'utf8');// Expected format: table rows | Purpose | Command |const rows = [...doc.matchAll(/^\|\s*([^|]+?)\s*\|\s*`([^`]+)`\s*\|$/gm)];if (rows.length === 0) {console.error('No commands parsed from commands.md. Check the table format.');process.exit(1);}let failed = 0;for (const [, purpose, cmd] of rows) {try {// Prefer a dry-run-style probe when available; otherwise only check executability.execSync(`${cmd} --help`, { stdio: 'ignore', timeout: 10_000 });} catch {console.error(`Memory invalid: ${purpose} -> ${cmd}`);failed++;}}process.exit(failed === 0 ? 0 : 1);
The rendering script should also remain minimal so the adapter layer does not become a maintenance burden:
// .ai/adapters/render.mjsimport { readFileSync, writeFileSync } from 'node:fs';const sources = ['project.md', 'commands.md', 'constraints.md', 'glossary.md'];const body = sources.map((f) => readFileSync(`.ai/memory/${f}`, 'utf8').replace(/^---[\s\S]*?---\n/, '')).join('\n\n---\n\n');// Write to the rule-file paths required by each target tool; follow official documentation.const targets = ['target rule file path for tool A', 'target rule file path for tool B'];for (const out of targets) writeFileSync(out, body, 'utf8');
It is important to emphasize that the check validates factual content, not wording. The only criterion is whether the commands, paths, and interfaces recorded in memory still exist.
9. Security and compliance boundaries
Once the memory repository enters version control, project background knowledge becomes part of the code assets, so boundaries are required:
- Never put secrets, tokens, connection strings, or internal network addresses into the memory repository. Leave only placeholders and instructions for how to obtain them.
- Do not write descriptions that contain personal information or production data samples. Use synthetic data when examples are needed.
- Desensitize personal names and organization details in decision records according to team standards.
- When a team-level memory repository is centrally hosted, object storage can keep multiple versions, logging services can retain audit trails for changes, and CI pipelines can trigger synchronization and validation, with monitoring alerts notifying responsible owners of anomalies. These capabilities fall into general cloud infrastructure categories. When selecting them, base decisions on the actual interfaces and pricing offered, and do not assume that someone else’s configuration applies to your environment.
10. Rollout path and expected benefits
Do not roll everything out at once. Proceed in this order, with each step providing standalone value:
- Week 1: Create only
commands.mdandproject.md. This alone removes most of the repeated manual explanation. - Week 2: Add adapter rendering and verify that both tools receive consistent rules.
- Week 3: Add decision records, but only for controversial choices made in the last three months.
- Week 4: Integrate CI validation and start the
stalemarking process.
The benefit is not only saving time. Three more important changes occur: switching tools becomes “reloading” instead of “retraining”; code review can show the rationale behind changes; and new team members ask better questions when taking over work, because they read conclusions with reasons instead of scattered historical chat logs.
11. Boundaries and non-applicable scenarios
This approach does not solve every problem. Stating boundaries clearly is more valuable than exaggerating its effects:
- It does not close capability gaps between tools. If one tool is stronger for a specific language or framework, that is a capability issue, and the memory layer cannot fix it.
- It cannot replace code itself. Any fact that can be expressed by code should be expressed by code. Memory should carry only decisions and constraints that exist outside the code.
- Very long context still needs chunking. The memory layer improves relevance, not context-window capacity.
- Governance cost is real. A memory repository without maintainers will degrade into a source of noise within a few months. At that point, deleting it is better than keeping it.
The core judgment is simple: context should be version-controlled like source code, not consumed like chat history. Once that is achieved, which AI assistant you use becomes a replaceable runtime choice.
