Give AI Coding Agents a Memory - The dev-notes Folder I Use With Claude Code and Copilot
A dev-notes folder with an index, project map, plans, execution logs and ADRs so Claude Code, Copilot or any agent picks up context without re-explaining.
The Problem#
Every new chat with an AI coding agent starts from zero. I re-explain the project structure, re-state the rules, and re-describe the plan we agreed on yesterday. When the context window fills up mid-task, the agent forgets the plan it wrote an hour ago and starts improvising.
Worse, the decisions made along the way (why we picked library A over B, what we tried that didn’t work) live only in a chat history nobody reads again.
The Solution#
Keep a dev-notes/ folder in the repo that the agent reads at the start of every session. It holds a short index, a map of the project, the plans we’ve agreed on, a log of what actually ran, and the decisions worth keeping.
The folder is plain markdown, so it works the same with Claude Code, GitHub Copilot, or whatever tool comes next. The tool-specific part is just one line pointing at the index.
Record decisions, not just code#
The decisions part borrows from Architecture Decision Records:
An architecture decision record (ADR) is a document that captures an important architectural decision made along with its context and consequences.
An architecture decision (AD) is a software design choice that addresses a significant requirement.
An architecture decision log (ADL) is the collection of all ADRs created and maintained for a particular project (or organization).
An architecturally-significant requirement (ASR) is a requirement that has a measurable effect on a software system’s architecture.
All these are within the topic of architecture knowledge management (AKM).
— Quoted from joelparkerhenderson/architecture-decision-record ↗
I use ADRs to persist:
- feature designs
- migrations
- data model changes
- security decisions
- anything else I’d otherwise have to explain to the agent twice
Rules I settled on
- Don’t persist every plan by default. Persist by rules: scope of N+ files, cross-cutting impact, schema changes, or security implications.
- One plan per file. Prevents merge conflicts when two branches both touch the notes.
- Let the AI plan first, then write the note only after I approve it.
- Prune periodically. A weekly sweep keeps
INDEX.mdlean. Old plans move to an archive page so the front page stays short.
How to Do It#
1. Create the folder#
# Your project repo
dev-notes/
- INDEX.md # index of dev-notes; reference only what you want AI to read
- PROJECT_MAP.md # persistent, human-readable project map
- project.map.json # (optional) machine-readable project map
- plans/ # proposals (immutable after approval)
- 2025-09-07-migrate-keychain.plan.md
- exec/ # (optional) execution logs -- what actually ran
- 2025-09-07-migrate-keychain.exec.md
- adrs/ # decisions worth keeping
- ADR-keychain-migration.mdshThe workflow around it:
You describe task
│
▼
PLAN produced (no files touched) ──> you/human/agent review
│ ▲
├─ approve: mark PLAN "Approved"│
│ │
▼ │
APPLY (execute) ──> write EXECUTION LOG ┘
│
└─ (optional) write ADR for lasting decisionsplaintext2. Point your tool at the index#
Claude Code imports files into memory with @. Add one line to CLAUDE.md:
See @dev-notes/INDEX.md for current plans, project map and decisions.markdownThen lock down what the agent may write in .claude/settings.json. It can read the notes freely but only append execution logs, and it can never read secrets:
{
"permissions": {
"allow": ["Read(./dev-notes/**)", "Write(./dev-notes/exec/**)"],
"deny": ["Read(./secrets/**)", "Read(./.env*)"],
"additionalDirectories": ["./dev-notes"]
}
}jsonGitHub Copilot has no import syntax, but .github/copilot-instructions.md is always in context, so a plain instruction does the job:
Before starting any task, read `dev-notes/INDEX.md` and the files it links to.
For tasks touching 3+ files, write a plan to `dev-notes/plans/` first and wait for approval.markdown3. Fill in the files#
dev-notes/INDEX.md. Keep it to links; this is the only file the agent must read every time:
# dev-notes index
## Project
- @dev-notes/PROJECT_MAP.md
## Active plans
- @dev-notes/plans/2025-09-07-migrate-keychain.plan.md
## Decisions
- @dev-notes/adrs/ADR-keychain-migration.md
## Archive
- @dev-notes/archive/2025-q3.mdmarkdowndev-notes/PROJECT_MAP.md. Short, concrete, and updated when the layout changes:
# Project Map (last updated: 2025-09-07)
## Top-Level Layout
- app/ – RN app entry; providers, navigation
- api/ – REST clients; auth interceptor
- server/ – FastAPI; /v1/search, /v1/auth
- infra/ – IaC; GitHub Actions; Dockerfiles
- tests/ – unit + e2e; fixtures
## Entry Points
- mobile: app/index.tsx → App.tsx
- server: server/main.py (uvicorn) ; config in server/settings.py
## Key Flows
1) Login → Token store (Keychain/SecureStorage) → Auth header via api/interceptor.ts
2) Search → api/search.ts → server/routers/search.py
## Build & Test
- mobile: `yarn install` ; iOS: `cd ios && pod install` ; run: `yarn ios`
- server: `uv venv && uv run pytest -q`
- CI: see .github/workflows/ci.yml
## Schemas / Contracts
- OpenAPI: server/openapi.yaml
- Types: api/types/*.ts
## See Also
- @dev-notes/INDEX.md # plans & ADRsmarkdowndev-notes/project.map.json (optional). The same map in a shape that’s cheap for an agent to parse:
{
"entryPoints": {"mobile": "app/index.tsx", "server": "server/main.py"},
"flows": ["login", "search"],
"build": {"mobile": ["yarn install","pod install","yarn ios"], "server": ["uv run pytest -q"]},
"contracts": {"openapi": "server/openapi.yaml"}
}jsondev-notes/plans/*.plan.md. Written by the agent in plan mode, approved by me, then frozen:
---
id: PLAN-2025-09-07-keychain
status: Proposed # update to "Approved" after approval
links: { issue: "#1234" }
---
# Migrate rn-secure-storage → react-native-keychain
## Context
…
## Options
A) … B) …
## Decision (if any so far)
Preferred: …
## Implementation Plan
- Files:
- Commands:
- Tests:
- Risks & Rollback:markdowndev-notes/exec/*.exec.md. What actually ran, so the next session can pick up from reality rather than from the plan:
---
plan: PLAN-2025-09-07-keychain
status: Executed
pr: https://github.com/acme/app/pull/567
commits:
- fix(security): replace secure storage with keychain (PLAN-2025-09-07-keychain)
sha: abc123…
results:
tests: "unit 152/152 pass"
ios: "pod install OK"
---
## Steps Run
1) yarn add react-native-keychain
2) cd ios && pod install
…
## Diffs / Notes
- See PR for unified diff; highlights: …markdowndev-notes/adrs/*.md. The classic Michael Nygard template ↗:
# Title
## Status
What is the status, such as proposed, accepted, rejected, deprecated, superseded, etc.?
## Context
What is the issue that we're seeing that is motivating this decision or change?
## Decision
What is the change that we're proposing and/or doing?
## Consequences
What becomes easier or more difficult to do because of this change?markdownOr the tiny version I use for small projects:
# PLAN: <feature/issue> (YYYY-MM-DD)
## Context
## Options considered
## Decision (if any)
## Implementation plan (steps/commands/files)
## Risks & rollback
## Verification (tests, metrics)markdownExample#
My macOS app SideTime ↗ uses a trimmed version of this. The index is a dozen lines:
# Dev Notes Index
## Plans
- [2025-09-11 Sparkle Auto-Update Implementation](.dev-notes/plans/2025-09-11-sparkle-auto-update.plan.md)
- [2025-10-04 Sparkle Appcast Generation Process](.dev-notes/plans/2025-10-04-sparkle-appcast-generation.plan.md)
## Archive
- [Feature Roadmap](.dev-notes/archive/feature-roadmap.md)markdownWhen I came back to the Sparkle work weeks later, a fresh Claude Code session read the two plans and continued from where the last one stopped. No re-explaining.
Tips#
/memorycheck: run/memoryin Claude Code after editingCLAUDE.mdto confirm the@imports actually loaded./permissionsUI: run/permissionsonce to verify the allow/deny rules resolve the way you expect.- Keep the index tiny. Everything in it costs context on every session. If it grows past a screen, archive.
- Dates in filenames.
2025-09-07-migrate-keychain.plan.mdsorts itself and tells the agent how stale it is. - One source of truth. If you also keep a
copilot-project-context.md, have it link toPROJECT_MAP.mdrather than duplicating it, or the two drift apart.
Summary#
A plain-markdown dev-notes/ folder with an index, a project map, approved plans, execution logs and ADRs gives any AI coding agent persistent memory across sessions, for the cost of one line in CLAUDE.md or copilot-instructions.md.