How the manage_adr Tool Persists Architecture Decision Records in codebase-memory-mcp
The manage_adr tool writes Architecture Decision Records to a SQLite database using an atomic upsert operation on the project_summaries table, with automatic one-time migration support for legacy flat-file ADRs.
The manage_adr tool serves as the sole write interface for Architecture Decision Records (ADRs) within the DeusData/codebase-memory-mcp repository’s Model Context Protocol (MCP) server. Unlike in-memory storage that evaporates on restart, this implementation guarantees durability by persisting ADRs to a SQLite backend, ensuring your architectural decisions remain accessible across process lifecycles.
Resolving a Writable Store Handle
When handle_manage_adr in src/mcp/mcp.c receives a request, it first obtains a storage handle through resolve_store_internal (lines 10158‑L10246). Because the MCP server typically operates with read-only store handles for safety, the tool checks if the underlying project is file-backed. If so, it opens a separate read-write handle (owned_rw) to ensure the SQLite database operates in WAL mode and prevents write conflicts with the read-only handle used elsewhere in the system.
This dual-handle approach ensures that ADR mutations do not interfere with concurrent read operations while maintaining ACID compliance for the write transaction.
Legacy File Migration
For projects upgrading from earlier versions of the tool, handle_manage_adr implements a one-time migration path. The code invokes adr_read_legacy_file (lines 10115‑L10148) to check for the existence of a historic flat file at .codebase-memory/adr.md. If present, the function reads the legacy markdown content into a heap-allocated buffer.
The migration block (lines 10248‑L10263) then persists this content into the SQLite store via cbm_store_adr_store, after which the legacy file is ignored. This ensures no ADR data is lost when transitioning from file-based to database-backed storage.
SQLite Upsert Operations
The actual persistence logic resides in cbm_store_adr_store within src/store/store.c (lines 7288‑L7299). This function executes an atomic SQL statement that inserts new records or updates existing ones while preserving creation timestamps:
INSERT INTO project_summaries (project, summary, source_hash, created_at, updated_at)
VALUES (?1, ?2, '', ?3, ?4)
ON CONFLICT(project) DO UPDATE SET summary=excluded.summary,
updated_at=excluded.updated_at;
Table Schema and Timestamps
The project_summaries table maintains one row per project, storing the complete ADR markdown in the summary column. The helper function iso_now supplies ISO‑8601 formatted timestamps for both created_at and updated_at fields (lines 7289‑7290), enabling full audit trails of when decisions were originally recorded versus last modified.
The write operation returns CBM_STORE_OK only if sqlite3_step yields SQLITE_DONE, ensuring the transaction commits successfully before the function returns control to the MCP handler.
Retrieval and Section Extraction
For read operations, cbm_store_adr_get (lines 7311‑L7318 in src/store/store.c) fetches the stored ADR and populates a cbm_adr_t struct. If no record exists for the requested project, the function returns CBM_STORE_NOT_FOUND.
When invoked with mode="sections", the tool bypasses the database and parses the raw content locally using adr_list_sections_from_content to extract markdown headings. This allows clients to retrieve just the structure of the ADR without transmitting the full document content.
Practical Usage Examples
Store a new ADR or update an existing one via the HTTP API:
curl -X POST http://localhost:8080/api/adr \
-d '{"project":"myproj","mode":"update","content":"## PURPOSE\nNew ADR\n"}'
Retrieve the persisted ADR later:
curl http://localhost:8080/api/adr?project=myproj
# → {"content":"## PURPOSE\nNew ADR\n","status":"updated"}
Using the native MCP JSON‑RPC interface:
{
"jsonrpc":"2.0",
"method":"manage_adr",
"params":{
"project":"myproj",
"mode":"update",
"content":"## PURPOSE\nNew ADR\n"
},
"id":1
}
Summary
- The
manage_adrtool orchestrates ADR persistence throughhandle_manage_adrinsrc/mcp/mcp.c, coordinating between the MCP server and storage layer. - Writes execute via
cbm_store_adr_storeusing SQLiteINSERT ... ON CONFLICTupserts to theproject_summariestable, ensuring atomic updates. - Legacy
.codebase-memory/adr.mdfiles migrate automatically on first access throughadr_read_legacy_file, preventing data loss during upgrades. - ISO‑8601 timestamps track both
created_atandupdated_atfields for complete audit history. - The tool supports both full content retrieval and lightweight section parsing via
adr_list_sections_from_content.
Frequently Asked Questions
What database table stores ADRs in codebase-memory-mcp?
ADRs persist in the project_summaries table within the project’s SQLite database. The summary column contains the full markdown content of the Architecture Decision Record, while created_at and updated_at columns maintain temporal metadata for each project’s ADR.
How does manage_adr handle concurrent write operations?
The tool prevents write conflicts by opening a dedicated read-write handle (owned_rw) when mutations are required, separate from the read-only store handle used elsewhere. This approach leverages SQLite’s WAL (Write-Ahead Logging) mode to allow concurrent reads while ensuring the ADR write commits atomically via sqlite3_step.
Can I retrieve specific sections of an ADR without parsing the full content?
Yes. When calling manage_adr with mode="sections", the tool invokes adr_list_sections_from_content to parse markdown headings locally and return only the section structure. This mode avoids transmitting the entire document when you only need the table of contents or heading hierarchy.
What happens to existing ADRs when upgrading from older versions?
The tool automatically detects legacy flat files at .codebase-memory/adr.md using adr_read_legacy_file. On first access, it migrates the legacy content into the SQLite store via cbm_store_adr_store, preserving the existing ADR while transitioning to the new database-backed architecture. After migration, the system reads exclusively from the database.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →