Before I built ValyrianCtx, every morning started the same way. I'd open Claude Code, type a paragraph explaining what I was working on yesterday, what I'd decided, what I'd tried that failed, and where I left off. The AI would respond with perfect enthusiasm — as if hearing it all for the first time. Because it was.
After building ValyrianCtx, I open my editor and start working. The AI already knows. It knows I chose Postgres over MongoDB because I need cross-table transactions. It knows I tried the recursive approach and it failed on deep nesting. It knows the next step is writing integration tests.
The difference: I saved roughly 12–15 minutes per session. Across a team of five, that's over 5 hours per week of context re-explanation — gone.
This post breaks down every architectural decision inside ValyrianCtx — an open-source tool that gives AI coding assistants persistent memory across sessions. By the end, you should know enough to use it, extend it, or steal its ideas for your own tools.
The Amnesia Problem
Every AI coding assistant — Claude Code, Cursor, Copilot, Antigravity, Trae, Warp — has the same blind spot.
They remember nothing.
Not across sessions. Not across branches. Not across IDEs. Every conversation starts at zero. You, the developer, become the memory layer. You're the one who remembers what was decided, what was tried, and what failed. You're the one who spends the first 5–15 minutes of every session acting as a human context dump.
That's the gap. Git gives you code history. But code history without intent history is like reading a novel with every other chapter ripped out. You can see the words but you can't follow the story.
I think this is the single biggest productivity drain in AI-assisted development today.
Smart people assume the AI companies will solve this with built-in memory features. Here is why that will not be enough: memory features are platform-locked. Claude Code in the morning, Cursor in the afternoon — Claude's memory does not help Cursor. Switch branches, and the context from main does not apply to feature/payments. Your teammate picks up your branch? They start from zero regardless.
The solution isn't better AI memory. The solution is a context layer that sits between the developer and all their AI tools — one that's Git-aware, branch-scoped, IDE-agnostic, and team-shareable.
That's what ValyrianCtx is.
The Context Ceiling
Every current AI coding IDE has a hard context limit — and when you hit it, you are dead in the water.
You're in the middle of a productive session. You've built up rich context: file contents, conversation history, tool outputs. Everything is flowing. Then the IDE tells you the context window is full. No more requests. Session over.
Your options? Start a new session (losing all that context) or manually trim the conversation (losing important history). Either way, you lose.
This is why persistent context that lives outside the AI session matters. When you hit the ceiling and start fresh, ValyrianCtx means you do not start from zero. Your decisions, approaches, current state, and next steps survive the session reset.
You lose the conversation. You keep the intent.
What ValyrianCtx Does
ValyrianCtx is a CLI tool and MCP server that saves and restores structured coding context across AI sessions. Install it globally, initialize it in your repo, and it handles the rest.
npm install -g valyrianctx
cd your-project
valyrianctx init
That init command does six things:
- Creates a
.valyrianctx/directory for storing context - Generates rule files for every AI editor it detects (Claude Code, Cursor, Antigravity, OpenCode, Trae, Warp)
- Writes MCP server configuration where supported
- Installs git hooks for automatic context capture
- Updates
.gitignoreto keep per-developer context private - Sets up the Living Context system (more on this — it's the key innovation)
From that point forward, your AI assistant automatically knows what you were doing, what you decided, and what comes next.
Two Strategies, One Prompt
The context storage is deliberately simple.
.valyrianctx/
config.json # Version, repo name, timestamp
sessions/
1708012800000.json # Chronological session snapshots
branches/
main.json # Branch-scoped context arrays
feature__payments.json # Branch names with / become __
Every context entry has a fixed shape:
interface ContextEntry {
id: string; // UUID
timestamp: string; // ISO 8601
branch: string; // Git branch
repo: string; // Repository name
author: string; // From git config
task: string; // What you're working on
goal?: string; // Why (ticket reference)
approaches: string[]; // What you tried
decisions: string[]; // What you chose and why
currentState: string; // Where things stand now
nextSteps: string[]; // What comes next
blockers?: string[]; // What's blocking you
filesChanged: string[];
filesStaged: string[];
recentCommits: string[];
assignee?: string; // For team handoffs
handoffNote?: string;
}
Context isn't free-form text. It's structured intent: what you tried, what you decided, and why. That structure is what makes it useful across sessions, branches, and teammates.
Two storage strategies run simultaneously:
- Sessions (
sessions/): Append-only chronicle. Every save creates a new timestamped file. This is your audit trail. - Branches (
branches/): Each branch gets a JSON array of entries. New saves append. Theresumecommand reads the latest entries from the current branch.
Everything compiles down to a single markdown prompt. That prompt is the universal interface — it works in any AI tool, any IDE, any workflow. Copy-paste it, pipe it via --stdout, or let the system inject it automatically.
Living Context
The problem with building a context tool for AI assistants: they are unreliable at following instructions.
You can write in a rule file: "Before starting work, run valyrianctx resume." Cursor will sometimes do it. Claude Code will usually do it. Antigravity might ignore it. Across six different AI editors, "please run this command first" has maybe a 60% success rate.
So I flipped the approach.
This is Living Context. When you save context, ValyrianCtx doesn't just store it in .valyrianctx/. It also injects it into the rule files that each IDE already loads:
- Cursor reads
.cursor/rules/valyrianctx.mdc - Trae reads
.trae/rules/valyrianctx.md - Warp reads
.warp/valyrianctx.md - Gemini/Antigravity reads
.gemini/valyrianctx.md
The system uses two distinct marker sets to keep things clean:
<!-- valyrianctx:start -->
[Instructions: "You MUST resume context first..."]
<!-- valyrianctx:end -->
<!-- valyrianctx:context:start -->
[Actual session context: task, decisions, state...]
<!-- valyrianctx:context:end -->
Instructions are committed to git (team-shared). Context is gitignored (per-developer). The dual-marker system means your teammates get the rules but not your local session state.
There's a design note buried in the source code that captures the core insight: "AI agents treat passive phrasing as optional reference. They treat imperative phrasing as directives." Every generated rule file uses "you MUST" language, not "you should consider."
Three Layers of Auto-Resume
Living Context is layer one. But I'm paranoid about reliability, so I built two more.
Layer 1 — Living Context: Rule file injection. Context is physically present in files the AI reads on startup. Zero commands needed.
Layer 2 — MCP Auto-Resume: First-tool-call interception. The MCP server prepends context to the response of the first tool call in a session. Transparent to the AI.
Layer 3 — Git Hook Injection: post-checkout hook. When you switch branches, the hook automatically injects that branch's context into rule files.
The MCP layer deserves special attention. The server maintains a four-variable state machine:
let sessionResumed = false;
let toolCallCount = 0;
let lastToolCallTime: number | null = null;
let explicitSaveMade = false;
On the very first tool call of a session — regardless of which tool is called — the server checks: has context been resumed yet? If not, it prepends the full context prompt to the tool's response. The AI receives its answer plus the context, transparently. If the first call happens to be valyrianctx_resume, it skips the prepend to avoid duplication.
The Greensight Parser
When you run valyrianctx save --auto, the system needs to figure out what you were doing. You might have been in Claude Code, or Cursor, or Antigravity, or any of four other editors. Each stores session data differently, in different locations, in different formats.
Greensight is a chain-of-responsibility parser that tries six extractors in priority order and returns the first successful result:
-
Claude Code — Reads
~/.claude/projects/<encoded-path>/where the path encoding replaces/with-. Parses JSONL session files using a sliding window (last 500 lines). Separates first user messages (the task) from last assistant messages (the state). Also readsmemory/MEMORY.mdfor persistent project knowledge. -
Antigravity/Gemini — The most sophisticated extractor. Reads
~/.gemini/antigravity/brain/<id>/and parses three separate files:task.md(checkbox items),implementation_plan.md(with GitHub-style alerts as decisions), andwalkthrough.md(for current state). Has a multi-pass task extraction strategy. -
Cursor — Tries three sources in order:
.cursor/rules/*.mdcfiles in the repo,~/.cursor/User/globalStorage/cursor.composer/for conversation JSON, and workspace storage files. -
OpenCode — Searches
~/.opencode/,~/.config/opencode/, and<repo>/.opencode/for sessions in JSON and JSONL formats. -
Trae — Similar multi-location search with support for rule files using frontmatter format.
-
Warp — Handles the widest variety of formats: JSON, JSONL, and even
.logfiles with regex-based parsing.
Each extractor is self-contained. If one fails, the next tries. Adding support for a new IDE means writing one new extractor function and adding it to the chain. The system currently handles over 15 different file format variations across the six IDEs.
The shared helper functions are where the real NLP happens:
extractDecisions(messages); // "decided", "chose", "opted", "selected"
extractApproaches(messages); // "tried", "attempted", "tested", "experimented"
extractState(messages); // "currently", "now", "at this point", "status:"
extractNextSteps(messages); // "next steps", "todo", "remaining", "still need to"
The parser doesn't understand your code. It understands your workflow. It reads six different AI editors' session formats and extracts the same structured intent from all of them.
The Smart Save Guard
You have a detailed conversation with Claude Code. You explain your architecture, constraints, and decisions. You save context manually with rich, structured data.
Then you commit your code.
The post-commit hook fires. It runs valyrianctx save --auto. The auto-extractor reads your editor's session data, produces a thin summary, and overwrites your carefully structured context.
The Smart Save Guard prevents this. When save --auto runs, it checks: was a rich structured save (one with approaches and decisions populated) made within the last 5 minutes? If yes, skip the auto-save.
const lastEntry = entries[entries.length - 1];
if (lastEntry) {
const timeSinceLastSave =
Date.now() - new Date(lastEntry.timestamp).getTime();
const isRichSave =
lastEntry.approaches.length > 0 || lastEntry.decisions.length > 0;
if (isRichSave && timeSinceLastSave < 5 * 60 * 1000) {
return; // Skip — high-quality save is recent
}
}
This creates a priority hierarchy: human-quality saves are never degraded by machine-quality auto-saves.
The Prompt Merge
When the system generates a context prompt, it does not just use the latest entry.
It takes task, state, and next steps from the most recent entry. But it merges approaches and decisions from the last three entries, deduplicated by lowercase comparison.
Why three? A low-quality auto-save might have a good task and currentState but empty decisions. If only the latest entry mattered, two sessions of carefully recorded decisions would vanish. Merging three entries means rich context survives even across thin auto-saves.
const recentEntries = entries.slice(-3);
const allApproaches = dedup(recentEntries.flatMap((e) => e.approaches));
const allDecisions = dedup(recentEntries.flatMap((e) => e.decisions));
The best context system isn't the one that saves the most. It's the one that loses the least.
The Idle Safety Net
Two independent idle timers protect against the most common context loss scenario: the developer who walks away without saving.
MCP Server (5-minute timeout): A timer checks every 60 seconds. If 5 minutes pass with no tool calls and no explicit save, it creates a low-quality [auto-idle] context entry and injects it into rule files. The timer is unref()'d so it does not keep the Node process alive when stdin closes.
VS Code Extension (10-minute timeout): Tracks file saves via onDidSaveTextDocument. If 10 minutes pass without activity, it runs valyrianctx save --auto. It also auto-saves when a terminal closes and when the extension deactivates.
Graceful shutdown: The MCP server intercepts SIGTERM and SIGINT. If there was activity but no explicit save, it performs a final auto-save before exiting.
Team Workflows
ValyrianCtx isn't just a solo tool. Three features make it work for teams.
Handoffs (valyrianctx handoff alice "Auth flow is 80% done"): Creates a context entry with assignee and handoffNote fields. When Alice resumes on the same branch, she sees the handoff note at the top of her context prompt — what you decided, where you left off, what remains.
Sharing (valyrianctx share): Removes .valyrianctx/ from .gitignore and commits it. The team can see context history. valyrianctx share --stop reverses it.
Branch-scoped context: Context is scoped to the current git branch. The post-checkout hook fires on branch switch and injects the correct context into rule files. Switch from main to feature/payments and the AI gets the payments context automatically.
The Command Surface
Core Commands:
init— Initialize repo with rule files, hooks, and storagesave [message]— Save context (interactive, auto-extract, or structured)resume— Generate context prompt (clipboard, stdout, or inject)log— View context history for branch or all branchesdiff— Show changes since last context save
Team Commands:
handoff— Transfer context to a teammateshare— Commit.valyrianctx/for team visibilitywatch— Chokidar-based file watcher with auto-save on intervalhook install/remove— Manage git hooks (post-commit, post-checkout)
AI-Powered Commands:
summarize— AI generates structured context from git statesuggest— AI suggests 3–5 actionable next stepscompress— AI compresses older entries to keep context lean
The AI-powered commands work with any OpenAI-compatible API. compress is the most useful: it keeps your latest entry intact, compresses all older entries into a single AI-generated summary, and replaces the branch file with just two entries. Context stays lean even after weeks of development.
The Tech Stack
Eight runtime dependencies. No framework. No database. No cloud service. The entire system is files-on-disk + git. That's a deliberate choice: zero infrastructure means zero barrier to adoption.
TypeScript is compiled to ES2020/CommonJS with strict mode. The build is a single tsc invocation. No bundler, no webpack, no esbuild. The output is readable JavaScript that you can debug by reading dist/.
Limitations
No cloud sync. Context lives on disk and in git. If you want cross-machine sync, you use valyrianctx share and git.
No semantic understanding. Greensight extracts patterns from text. It doesn't understand your code. If your AI session was entirely about architecture diagrams on a whiteboard, the parser won't capture it.
No real-time collaboration. Handoffs are asynchronous. There's no live "pair context" feature.
AI commands require an API key. summarize, suggest, and compress need an OpenAI-compatible API. The core save/resume/inject workflow works entirely offline.
Parser coverage varies. Claude Code and Antigravity have the richest extraction (200+ lines each). Newer editors like OpenCode and Trae have simpler extractors that may miss nuance.
I'd rather ship a tool that does 5 things reliably than 50 things that break when you need them.
The Design Philosophy
Three principles guided every decision:
-
Don't ask the AI to cooperate. Every feature that depends on the AI voluntarily running a command is fragile. Living Context, MCP auto-resume, and git hook injection all work without the AI doing anything special. The AI just reads its own instruction files — and the context is already there.
-
The prompt is the universal API. Instead of building integrations for each IDE's internal API (which change constantly), ValyrianCtx generates a markdown prompt. Markdown works everywhere. Copy-paste works everywhere. The most portable integration is no integration at all.
-
Git is the truth. Branch-scoped context, git hooks for automatic capture, git-based sharing,
.gitignorefor privacy boundaries. Git is already the developer's source of truth for code. ValyrianCtx makes it the source of truth for intent, too.
Git tracks code history. ValyrianCtx tracks intent history. Together, they tell the complete story of how software is built.
Getting Started
# Install globally
npm install -g valyrianctx
# Initialize in your project
cd your-project
valyrianctx init
# That's it. Your AI assistant will auto-resume context.
# But if you want to save manually:
valyrianctx save "Implemented auth flow with PKCE" \
--approaches "tried implicit grant first;; switched to PKCE for security" \
--decisions "chose RS256 for JWT signing;; 24h token expiry" \
--state "Auth flow works, refresh tokens pending" \
--next-steps "implement refresh token rotation;; add rate limiting"
# Resume in any AI tool:
valyrianctx resume --stdout
# Or just start a new session — Living Context handles it.
If you're on a team, add ValyrianCtx as a dev dependency instead:
npm install -D valyrianctx
Then everyone on the team gets context auto-resume through the committed rule files, without needing a global install.
What I'm Building Next
I'm exploring three directions:
- A web dashboard for visualizing context history across branches and team members
- Semantic compression that uses embeddings to merge similar context entries intelligently
- More IDE extractors — JetBrains AI Assistant, GitHub Copilot Chat, and Zed are on the list
If you build developer tools, use AI coding assistants daily, or just want to stop re-explaining your project every morning — try it. Open an issue. Tell me what's broken. Tell me what's missing.
Vasudhaiva Kutumbakam — the world is one family.
What's the most time you've ever spent re-explaining a project to an AI assistant? I'm curious what that number looks like for other people.