Migration script now resets SERIAL sequences (audit_log, context_files, etc.) to max(existing_id) after copying rows. Without this, the sequence is still at its post-schema-creation value and every INSERT hits a duplicate key error.
9.7 KiB
I Built a Context Server to Fight My ADHD-Induced Context Sprawl
How replacing 7 scattered config files with a single source of truth saved my sanity (and my tokens).
If you work with AI tools the way I do — Claude Desktop for research, Claude Code for implementation, Codex CLI for reviews, Cursor for quick edits, and Hermes Agent for orchestration — you have a problem you might not have named yet.
I call it context sprawl. And if you have ADHD, it's worse than you think.
The Problem
Every AI harness has its own context file convention:
| Harness | File |
|---|---|
| Hermes | AGENTS.md |
| Claude Code | CLAUDE.md |
| Cursor | .cursorrules |
| Copilot | .github/copilot-instructions.md |
| Codex CLI | CODEX.md |
| Windsurf | .windsurfrules |
| Continue.dev | .continuerc |
When you work on the same project across multiple harnesses, you end up with N copies of the same project context. They drift. One says the build system is Go; another still says Python. One knows about the new OAuth flow; another doesn't. The LLM reads stale instructions and makes confident, wrong decisions.
For someone with ADHD, this is a specific kind of hell:
- You forget which file you last updated
- You avoid updating because it means updating 4-6 files
- You lose track of which harness has the "right" version
- You context-switch between tools and can't remember what the project actually needs
- The friction of maintaining context across tools becomes so high that you stop maintaining context at all
And then every LLM session starts from scratch — re-asking questions you already answered, re-discovering decisions you already made, re-making mistakes you already fixed.
The Tipping Point
I was working on a project called RemoteRig — a multi-camera remote monitoring system built in Go with ESP32-C6 camera nodes. I had context in:
AGENTS.md(Hermes)CLAUDE.md(Claude Code).cursorrules(Cursor)CODEX.md(Codex CLI)- A Notion page (for humans, but also where I drafted things)
- My own memory of what I'd told each tool (which is the worst place to store anything when you have ADHD)
I'd update AGENTS.md with a new architecture decision, forget to update CLAUDE.md, and then Claude Code would suggest something I'd already ruled out. I'd spend the first 20 minutes of every session re-explaining the project. Sometimes I'd update the wrong file and wonder why Codex was still using the old Go module structure.
The context was sprawled across the filesystem like a hoarder's garage, and I was the only one who knew where anything was — except I didn't, because ADHD.
The Solution: CTXD (Context Dossier)
I built CTXD — a single source of truth for project context that every AI harness can read from and write to.
Architecture
Context Dossier (Docker container, port 9091)
├── PostgreSQL 16 backend
├── Multi-file context per project:
│ ├── CONTEXT.MD ← canonical overview, synced as AGENTS.md to repos
│ ├── DECISIONS.MD ← architecture decisions, rationale
│ ├── RUNBOOKS.MD ← deploy, troubleshoot, operate procedures
│ ├── PROMPTS.MD ← project-specific prompts for different harnesses
│ └── GLOSSARY.MD ← project-specific terms, acronyms
├── OAuth 2.0 authorization server
│ ├── Dynamic Client Registration (Claude auto-registers)
│ ├── Authorization Code + PKCE
│ └── Scopes: ctxd.read, ctxd.write
├── Streamable HTTP MCP endpoints:
│ ├── /readonly/mcp (read-only, OAuth ctxd.read)
│ ├── /write/mcp (read-write, OAuth ctxd.write)
│ └── /mcp (internal, shared API key)
├── Web UI (per-user login, admin panel)
├── Version-checked writes (optimistic concurrency)
├── Append-only audit log
├── Point-in-time snapshots (auto-rotated)
└── Full-text search (PostgreSQL tsvector + GIN)
How it works
-
One canonical file per project —
CONTEXT.MDis the source of truth. CTXD syncs it toAGENTS.mdin the project root and creates symlinks (CLAUDE.md,.cursorrules,CODEX.md→AGENTS.md). Every harness reads the same file. -
LLMs connect via MCP — Claude Desktop connects to
https://ctxd.yourdomain.com/readonly/mcpand auto-discovers OAuth. No manual config, no API keys in URLs. It can read project context, search across all projects, and list individual files. -
LLMs can write context — With a
ctxd.write-scoped OAuth token, an LLM can update files with version checking. If two agents try to edit simultaneously, the second one gets aversion_conflictand knows to re-read, merge, and retry. -
The compiled view — When an LLM calls
get_project_context("remote-rig"), it gets all files concatenated into a single document with a metadata header. One call, complete context, no guessing. -
A locked client guide — There's a
get_client_guide()MCP tool that returns a lockedLLM-CLIENT.MDfile. Every LLM session starts by reading this guide, which explains how to connect, what tools are available, and what the discipline rules are. The file is immutable — no LLM can modify its own instruction manual.
What it solves for ADHD
- One place to update — Change
CONTEXT.MDonce. Every harness gets it via sync or MCP. No more updating 6 files. - No remembering required — The LLM reads context at the start of every session. You don't have to remember what you told it last time.
- Audit trail — Every read, write, and search is logged. When you can't remember what changed (and you can't, because ADHD), the audit log tells you.
- Version checking — Optimistic concurrency means no silent overwrites. If you and an LLM edit at the same time, the conflict is caught, not lost.
- Search — Full-text search across all projects. "What did I decide about the camera node?" → search → answer.
- Snapshots — Automatic point-in-time backups before every edit. Roll back if something goes wrong.
The Build
I built CTXD over a series of focused sessions with Hermes Agent — itself powered by the same MCP infrastructure. Some of the tools that made this possible:
- Hermes Agent for orchestration and the MCP framework
- PostgreSQL 16 as the primary database (migrated from SQLite)
- MCP SDK 1.28 with Streamable HTTP transport (replaced the older SSE pattern)
- OAuth 2.0 with DCR, PKCE, and per-scope access control
- Docker Compose for deployment — env-driven, no config files needed
- Traefik for public TLS termination and routing
The development was iterative and honest. I hit real bugs: the set -e in the entrypoint script killed the container because a PostgreSQL schema check returned exit code 1. The __main__.py checked for a SQLite file that doesn't exist when using PostgreSQL, causing an infinite re-initialization loop. The FTS5 search query used ? placeholders instead of %s for psycopg. Each one was a "oh, of course" moment — the kind you only get by actually building and deploying.
What I Learned
Context sprawl is an accessibility problem. For neurotypical developers, maintaining 6 config files is annoying. For someone with ADHD, it's a barrier that leads to giving up on context entirely — and then every AI interaction starts from zero.
The single source of truth pattern isn't just about consistency. It's about reducing the cognitive load of context management to one action: update CONTEXT.MD. That's one decision, one file, one habit — something even an ADHD brain can maintain.
OAuth + MCP is the right protocol stack for this. LLMs don't need API keys in environment variables. They need to discover a resource, authenticate via OAuth, and use standardized tools. The fact that Claude Desktop can connect to CTXD with zero manual configuration — just a URL — is the difference between "I should set this up" and "I'll just re-explain the project again."
PostgreSQL matters more than you think. I started with SQLite, which was fine for one user. But the moment you want concurrent agents writing context, proper backups, and full-text search that actually works — PostgreSQL is the right tool. The migration was a real engineering task (dual-backend support, schema rewrite, FTS5 → tsvector), and it was worth every hour.
Where It's Going
CTXD is now running in production at ctxd.cubecraftcreations.com, serving context to Claude Desktop, Hermes, and any OAuth-capable MCP client. It backs:
- RemoteRig (Go, ESP32-C6)
- ExtrudeX (3D printing control system)
- Tracehound (network diagnostic tool)
- Control Center (homelab dashboard)
The code is open and documented. There's a static demo at ctxd-demo that shows the UI without needing a database. There's a full README, an LLM.txt for automated deployment, and a SKILL.md that LLMs can read to understand how to use the server.
The Takeaway
If you work across multiple AI tools and find yourself re-explaining your project every session — you have context sprawl. If you have ADHD, context sprawl isn't just inefficient; it's a wall between you and productive AI-assisted work.
Building CTXD was my answer. It turned 6 files into 1, turned "remember what I told Claude" into "Claude reads the context server," and turned "I'll update the context later" into "I update one file and every tool gets it."
One source of truth. One habit. Zero context sprawl.
CTXD is open source. The production repo is at CubeCraft-Creations/CTXD, with a static demo at CTXD-Demo. Built by Joshua at CubeCraft Creations.