# How Architecture Decision Records (ADRs) Are Managed in codebase-memory-mcp: A Complete Technical Guide

> Discover how Architecture Decision Records ADRs are managed in codebase-memory-mcp. Learn about markdown blob storage CRUD operations via C API CLI and HTTP endpoints plus automatic migration.

- Repository: [Martin Vogel/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)
- Tags: how-to-guide
- Published: 2026-07-11

---

**The codebase-memory-mcp project treats Architecture Decision Records as first-class artifacts stored as markdown blobs in SQLite, offering CRUD operations through a C API, CLI tool, and HTTP endpoints with support for section-level updates and automatic migration from legacy file storage.**

The codebase-memory-mcp tool provides a robust system for managing Architecture Decision Records (ADRs) alongside code graph metadata. Unlike standalone documentation files, ADRs are persisted in the same storage layer as the rest of the project intelligence, making them searchable, versioned, and portable. This integration ensures that architectural decisions remain tightly coupled with the codebase they describe.

## Storage Backend and Data Model

ADR content is stored in the SQLite `project_summaries` table, sharing the same database that backs other code-graph metadata. Each ADR is persisted as a plain-text markdown blob with a strict size limit of **8,000 bytes** enforced by the `CBM_ADR_MAX_LENGTH` constant defined in [`src/store/store.h`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/store/store.h).

This design choice keeps ADRs portable while preventing storage bloat. The 8000-byte limit accommodates comprehensive decision records while maintaining query performance across the `project_summaries` table.

## Core C API for ADR Management

The primary interface for ADR operations resides in [`src/store/store.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/store/store.c) (lines 6217-6608), exposing four key functions declared in [`src/store/store.h`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/store/store.h) (lines 601-630):

- **`cbm_store_adr_store`** – Creates a new ADR or overwrites an existing one for a specified project.
- **`cbm_store_adr_get`** – Retrieves the current ADR content into a `cbm_adr_t` structure.
- **`cbm_store_adr_delete`** – Permanently removes the ADR record from the database.
- **`cbm_store_adr_update_sections`** – Updates specific markdown sections (e.g., *Status*, *Context*) without modifying unrelated content.

Validation helpers `cbm_adr_validate_content` and `cbm_adr_validate_section_keys` ensure that stored ADRs conform to expected markdown formatting before persistence.

## Parsing and Section-Level Updates

To enable surgical edits, the codebase implements parsing utilities that decompose markdown into key-value pairs. The **`cbm_adr_parse_sections`** function extracts headers and their content, while **`cbm_adr_render`** reconstructs the markdown blob after modifications.

This architecture allows developers to update individual sections—such as changing only the *Status* from "Proposed" to "Accepted"—without rewriting the entire document. The `cbm_store_adr_update_sections` function accepts arrays of keys and values, applies the changes to the parsed structure, and re-renders the final markdown for storage.

## Legacy Migration Strategy

Earlier versions of codebase-memory-mcp stored ADRs in a standalone file at `<repo_root>/.codebase-memory/adr.md`. The migration logic in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c) (lines 6684-6782) handles backward compatibility seamlessly.

When accessing ADR data, the system first queries the SQLite database. If no record exists, it checks for the legacy file, imports the content into the database, and deletes the old file. This one-time migration ensures zero data loss when upgrading to newer versions of the tool.

## HTTP API and Web Interface

The web UI exposes RESTful endpoints implemented in [`src/ui/http_server.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/ui/http_server.c) (lines 765-826):

- **`GET /api/adr?project=X`** – Returns the raw markdown content for the specified project.
- **`POST /api/adr`** – Accepts a JSON payload containing `project` and `content` fields to create or update an ADR.

These endpoints provide language-agnostic access to decision records, enabling integration with external documentation systems or CI/CD pipelines.

## CLI Integration with manage_adr

The `manage_adr` command-line tool, registered in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c), provides direct shell access to ADR operations:

```bash

# Create or update an ADR

cbm manage_adr mode=update project=myservice content="$(cat path/to/adr.md)"

# Display current ADR

cbm manage_adr mode=read project=myservice

# Remove the ADR

cbm manage_adr mode=delete project=myservice

```

The CLI surfaces detailed error messages—such as "no ADR found" or "merged ADR exceeds … chars"—providing immediate feedback when operations violate constraints like the 8000-byte limit.

## Data Integrity and Consistency Guarantees

During full re-indexing operations, the pipeline safeguards against accidental ADR loss. Comments in [`src/pipeline/pipeline.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/pipeline/pipeline.c) (lines 118-119) indicate that the system captures existing ADRs before wiping the database and restores them afterward.

This protection mechanism, implemented in response to issue #516, ensures that major migrations or schema updates do not destroy architectural decision history. All ADR functions set meaningful error messages that propagate to both the CLI and HTTP interfaces, maintaining clear communication about failure states.

## Code Examples

### Storing a New ADR in C

```c
cbm_store_t *store = cbm_store_open("mydb.sqlite");
const char *project = "myservice";
const char *adr_md = "# Decision 001\n\n**Status:** Accepted\n\n...";

int rc = cbm_store_adr_store(store, project, adr_md);
if (rc != 0) {
    fprintf(stderr, "Failed to store ADR: %s\n", cbm_store_last_error(store));
}
cbm_store_close(store);

```

### Reading an ADR in C

```c
cbm_adr_t adr = {0};
if (cbm_store_adr_get(store, "myservice", &adr) == 0) {
    printf("ADR content for %s:\n%s\n", adr.project, adr.content);
    cbm_store_adr_free(&adr);
}

```

### Updating Only the Status Section

```c
const char *keys[]   = {"Status"};
const char *values[] = {"Deprecated"};
cbm_adr_t updated;

if (cbm_store_adr_update_sections(store, "myservice",
                                  keys, values, 1, &updated) == 0) {
    printf("Updated ADR:\n%s\n", updated.content);
    cbm_store_adr_free(&updated);
}

```

### Accessing ADRs via HTTP

```bash

# Retrieve ADR

curl https://cbm.local/api/adr?project=myservice

# Update ADR

curl -X POST https://cbm.local/api/adr \
    -H "Content-Type: application/json" \
    -d '{"project":"myservice","content":"# New ADR\n\n..."}'

```

## Summary

- **Architecture Decision Records** in codebase-memory-mcp are stored as markdown blobs in the SQLite `project_summaries` table with an 8000-byte limit enforced by `CBM_ADR_MAX_LENGTH`.
- **Core operations** leverage the C API in [`src/store/store.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/store/store.c), including `cbm_store_adr_store`, `cbm_store_adr_get`, and section-level updates via `cbm_store_adr_update_sections`.
- **Legacy compatibility** is maintained through automatic migration from [`.codebase-memory/adr.md`](https://github.com/DeusData/codebase-memory-mcp/blob/main/.codebase-memory/adr.md) files to the database, handled in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c).
- **Multi-interface access** includes the `manage_adr` CLI tool and HTTP endpoints (`/api/adr`) defined in [`src/ui/http_server.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/ui/http_server.c).
- **Data integrity** is preserved across full re-indexes through safeguards in [`src/pipeline/pipeline.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/pipeline/pipeline.c) that backup and restore ADRs during database migrations.

## Frequently Asked Questions

### What is the maximum size for an Architecture Decision Record in codebase-memory-mcp?

The system enforces a hard limit of **8,000 bytes** (defined as `CBM_ADR_MAX_LENGTH` in [`src/store/store.h`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/store/store.h)) for each ADR stored in the `project_summaries` table. This constraint ensures that markdown content remains concise and query performance stays optimal. Attempts to store larger records will fail with a "merged ADR exceeds … chars" error message.

### How does the system handle ADRs created in older versions of the tool?

Legacy ADRs stored in `<repo_root>/.codebase-memory/adr.md` are automatically migrated on first access. The logic in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c) checks the database for existing content; if empty, it reads the legacy file, imports the markdown into SQLite, and deletes the old file. This seamless migration ensures backward compatibility without manual intervention.

### Can I update specific sections of an ADR without rewriting the entire document?

Yes. The API provides `cbm_store_adr_update_sections` in [`src/store/store.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/store/store.c), which uses `cbm_adr_parse_sections` to decompose the markdown into key-value pairs, updates only the specified sections (such as *Status* or *Context*), and re-renders the content using `cbm_adr_render`. This allows surgical edits while preserving the rest of the document structure.

### Are ADRs preserved during database re-indexing operations?

Yes. According to comments in [`src/pipeline/pipeline.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/pipeline/pipeline.c) (lines 118-119), the pipeline explicitly captures existing ADRs before performing full database wipes and restores them afterward. This safeguard, implemented to address issue #516, prevents accidental loss of architectural decision history during major schema migrations or re-indexing tasks.