The Stack Behind the Assistant
People occasionally ask what it's actually like running Claude Code across a home lab rather than a single laptop with a single project open in a single tab. The honest answer is that it looks less like "using a chatbot" and more like operating a small, opinionated piece of infrastructure that happens to have a language model wired into the middle of it. It has a filesystem layout, a launcher with three generations of history, a memory subsystem with its own eviction policy, and, as of a few weeks ago, its own knowledge graph. None of this was planned in advance. All of it accreted the way real infrastructure always does: because the previous layer had an annoying gap in it.
What follows is a tour of the current state of that stack, in the order the gaps appeared.
Rule One: The Projects Live on the NAS
The most boring decision in this entire setup is also the one that quietly makes everything else possible: every project directory lives under a single NFS export from grathrpi02, the lab's NAS, mounted at /mnt/raid0 on every machine that needs it. ~/projects isn't a folder on winifred, or on baloo, or on hathi. It's a symlink (or a bind mount, depending on the box) into the same 450TB of btrfs RAID0 sitting on a Raspberry Pi in a rack, wired into the same DNS cluster that resolves everything else in the lab.
The consequence is one I didn't fully appreciate until I'd been relying on it for months: I can open a Claude Code session on the workstation, walk away mid-task, sit down at the laptop an hour later, and the project tree, the git history, the half-finished CLAUDE.md, and the session's own memory files are all sitting exactly where I left them. Nothing to sync, nothing to push first, nothing to remember to rsync before switching machines. It is the single most load-bearing piece of infrastructure in the whole arrangement, and it's also the one nobody writes blog posts about, because "I mounted an NFS share" doesn't sound like an achievement. It isn't. It's plumbing. But plumbing is what allows everything downstream of it to assume "the project is just there," and an enormous amount of the tooling described below only works because that assumption is safe to make.
It's also, not incidentally, the reason the project chooser had a problem worth solving.
Three Generations of "Which Project Was I In, Again?"
Once your projects live in one enormous shared tree, spread across a lab's worth of client work, personal experiments, and infrastructure repos, the question "which one was I working on, and what happened last time" stops being trivial. Claude Code will happily --continue a session if you're sitting in the right directory, but "sitting in the right directory" assumes you remember which of forty-odd directories that is, and what state you left it in. That problem has now been solved three times, each time slightly better than the last.
claude+ was the first attempt: an fzf-driven picker that scans ~/.claude/projects/ for session data and ~/projects/ for anything without any, sorts the lot by recency, and shows session counts and summaries next to each entry. Pick one, it resumes with --continue. Pick "+ NEW PROJECT," it scaffolds a directory, runs git init, and drops in an empty CLAUDE.md. It did the job for a while, and it's the reason a sibling tool called gemini+ exists, doing the identical thing for Gemini Code sessions, because once you've written the picker once, porting it to a second CLI is an afternoon's work, not a redesign.
The gap in claude+ was structural, not cosmetic: it's a flat list. Forty projects in a flat fzf menu is navigable. A hundred and forty, spanning client engagements, personal tooling, and infrastructure repos that themselves contain sub-projects, is not. That gave rise to chloe, which kept the bash-and-fzf core but added the git and memory awareness the name implies, most usefully treating ~/.claude itself as an available context directory, so a session working on lab tooling could see its own configuration without a manual cd.
The current generation is casey, a full rewrite in Python rather than a bash script driving Python fragments, and it exists to solve the hierarchy problem chloe never got around to. Casey walks the projects tree to arbitrary depth, automatically detecting which folders are "groups" (pure navigation, containing other projects) versus "projects" (leaf folders you can actually launch), and lets you group related work the way it's actually organised on disk, rather than the way a flat picker forces you to pretend it is. It also supports persistent links, so a project can declare a dependency on another project living elsewhere in the tree, and casey will automatically add that linked project as an extra context directory on every launch, without copying or moving anything. Sensibly, casey runs entirely in parallel with chloe rather than replacing it outright: no shared mutable state, so I can flip between the two while deciding whether the hierarchy is worth the added complexity, and chloe keeps working, completely unbothered, in the meantime. This is, incidentally, a pattern worth stealing for any tool you're not yet ready to trust: build the replacement alongside the incumbent, not on top of it.
Mnemosyne: Making the Assistant Remember Correctly, Not Just Remember More
None of the above solves a much harder problem, which is that Claude Code's default memory setup is, to put it charitably, naive. Everything goes into one flat directory, nothing is scoped by project, nothing decays, and fragments from an entirely unrelated engagement have an unpleasant habit of surfacing in a session where they have no business being. I did not enjoy debugging a client's infrastructure while Claude quietly, confidently referenced context from a different client's infrastructure that happened to share a memory file. That is not a hallucination. That is a filing problem, and filing problems have architectural solutions.
The solution is a project I've been calling Mnemosyne, and it is, deliberately, not an application. It's a set of hooks, skills, and scripts wired directly into ~/.claude/, implementing a five-tier memory architecture rather than one flat pile:
Tier 0 is permanent global memory, injected into every session, evicted only by hand. Tier 1 is cross-project feedback, capped at fifty entries and decaying after ninety days without reinforcement. Tier 2 is project-scoped decisions, loaded only when the working directory matches, evicted after thirty days of silence. Tier 3 is recent session summaries, the most volatile tier, holding only the last three sessions and evicted first whenever the whole system runs over its token budget, which is capped hard at roughly three thousand tokens of injected context regardless of how much you've accumulated. Tier 4 is the verbatim archive, the full JSONL transcript of everything, never injected automatically, queryable on demand.
That last tier is where it gets genuinely useful rather than merely tidy. A nightly "dream cycle," modelled loosely on the idea that sleep consolidates memory rather than simply storing it, runs GATHER, SCORE, PROMOTE, EVICT, INDEX, and NARRATE phases against the accumulated transcripts: it decides what's worth keeping, promotes what's proven itself, writes off what hasn't been touched in weeks, and produces a short narrated summary of what actually happened, rather than leaving me to reconstruct it from raw logs. The corrections mechanism is bitemporal rather than destructive: when a memory turns out to be wrong, its record isn't deleted, its valid_until field is stamped superseded-<date>, so there's an audit trail of what the system used to believe and when it stopped believing it. That single design choice has saved me more debugging time than almost anything else in this stack, because "why did it do that" is answerable by reading a file rather than guessing.
The practical effect, measured the only way that matters, is fewer repeated corrections and less context spent re-explaining things I've already explained. Token usage down, retained knowledge up, which is precisely the trade a memory system is supposed to make and precisely the one the stock setup wasn't making.
Giving the Archive a Shape: LanceDB and the Knowledge Graph
A verbatim archive you can only query by exact keyword match is barely an archive; it's a filing cabinet with the drawers labelled in a language you've half-forgotten. So the fourth phase of Mnemosyne's build added semantic search over that whole Tier 4 history, using LanceDB, an embedded vector database with no server process to babysit, living quietly at ~/.claude/lancedb/. An incremental indexer runs during the nightly dream cycle, embedding messages with a small local model (all-MiniLM-L6-v2, 384 dimensions, cached on disk, no API key and no network call required), and a /memory-search slash command lets me ask, in plain language, "what did we decide about the reverse proxy config back in March," and get back the actual conversation rather than a keyword match on the word "proxy."
The part I find most interesting, though, isn't the search, it's what happens once you have several months of embedded conversation sitting in one place: you can look at its shape. A topology analysis phase clusters the entire embedded history and looks specifically for what it calls saddle points, pairs of clusters that sit close together in the embedding space without actually overlapping, which is a reasonably good proxy for "two areas of your own thinking that are related but have never been connected." The output gets pushed to a small visualisation server so the clustering is genuinely browsable, not just a JSON blob, with a level-of-detail explorer that lets you zoom from the whole shape of the archive down into individual messages inside a cluster. Reading your own several-months of technical decisions rendered as a graph, with the gaps between clusters flagged as the interesting bit rather than the clusters themselves, is a peculiar experience. It's the closest thing I've found to an outside view of how a project's thinking has actually evolved, as opposed to how I remember it having evolved, which are reliably not the same thing.
None of these pieces were designed together. The NAS mount solved "where do my files live." The chooser lineage solved "which of these files was I in." Mnemosyne solved "does the assistant remember the right things about the files." LanceDB and the topology work solved "can I actually see the shape of everything it remembers." Each one exists because the previous layer worked well enough to expose the next problem. That's not a criticism of the process; it's the only honest way infrastructure like this ever gets built.
The Next Gap: A Shorthand Both Sides Can Read
Which brings me to the bit that doesn't exist yet, and that I think is the interesting frontier rather than the solved problem. Every layer described above is, ultimately, still constrained by natural language as the medium of exchange between me and the model, and between the model and its own memory. English is a spectacularly inefficient encoding for the kind of information Mnemosyne is trying to preserve: a design decision, its rationale, and the conditions under which it stops applying, expressed in English, costs a paragraph. The same information, expressed as a small formal structure, costs a fraction of that, and loses nothing that mattered.
The speculative next step, then, is a shorthand: not a programming language, and not quite a constructed language either, but something closer to what Esperanto was attempting for humans, or what pidgin languages become when two groups need to trade meaning quickly without either side learning the other's grammar in full. A compact notation, legible to a human with a small amount of training, and losslessly parseable by an LLM, for exactly the categories of thing Mnemosyne already tracks: a decision, its rationale, its scope, its expiry condition, its supersession chain. If a memory file's frontmatter can already express scope: project:X and valid_until: superseded-2026-04-17, there's no obvious reason the reasoning connecting those fields has to be written out in full prose every time, other than that prose is the medium we both happen to already speak.
The payoff, if it works, isn't just token efficiency, though token efficiency compounds nicely across a five-tier memory system with a hard budget. It's knowledge density: the same context window holding meaningfully more decisions, more caveats, more of the shape revealed by the topology graph, because the notation encoding them doesn't spend three sentences on grammatical connective tissue a formal shorthand simply doesn't need. Whether that ends up looking like a constrained YAML dialect, a genuinely new symbolic grammar, or something closer to a controlled natural language like Attempto, I don't yet know. It's the next thing on the list, in the same spirit as everything above it: not because it sounded impressive on a roadmap slide, but because the current layer just exposed where it hurts.
Previous Post
AskDiana Shows Its WorkingNext Post
Astra and the Group That Broke the Rules