Why I didn't package my AI organism
/ 5 min read
I have a personal AI coding system built on cell biology. Germline (code), epigenome (memory), metabolon (runtime). It runs on a Fly app, a Mac, and a remote box. The public repo is the organism’s DNA; my private repos hold its state.
Yesterday I started cleaning it up. I had two private repos that could have been one. I had a Latin misfit (officina, “workshop”) in an otherwise bio-themed stack. Easy rename job.
Then Claude and I got ambitious.
The elegant vision
What if vivesca wasn’t just my personal setup but a real framework? brew install vivesca. vivesca init scaffolds your own private phenotype. Updates via brew upgrade. Each user gets their own instance; the public repo is the genotype; everyone’s epigenome accumulates separately. Cell biology all the way down.
We had the architecture diagrams. We had the CLI surface. We had the biological metaphor map. Public = genotype, private = phenotype, each user an organism. Three rounds of “that’s great, let’s keep going” later, I stopped and asked the question you should always ask:
Is this actually a good idea?
The list of hard problems
Here’s what I wrote down when I made myself be honest:
-
Polyglot packaging. The code is Python, Rust, Go, Bash, Markdown. “One install” across languages means shipping a binary plus venvs plus binaries plus hooks. That’s not an install. That’s a distribution.
-
Hook paths are absolute. Every shell hook references
~/this/exact/path/synapse.py. Install location determines everything. Upgrades move paths. I’d be building path migration logic for users who don’t exist. -
Bootstrapping a private repo for a stranger.
vivesca initwould have to create a GitHub repo under someone else’s account via OAuth, initial commit, push. Or assume they did it manually. Neither is a five-second setup. -
Update merge conflicts. If a user edits a skill file and I ship a new version, who wins? I’d be building a package manager’s hardest feature for a package nobody has installed yet.
-
My compute assumptions are baked in. My code knows about
somaandganglionandmacby hostname. It reads 1Password. It assumes Tailscale. A new user has none of these. Generalizing them is a secrets abstraction subsystem, a compute manifest, and a provisioning flow. Each one is its own project. -
Starter state is an impossibility. Empty epigenome means the organism has nothing to bootstrap from. My epigenome means they inherit my biases, my contacts, my schedule. There is no “neutral” starting memory.
-
The biology metaphor is a wall for newcomers. Germline, epigenome, chromatin, metabolon, ribosome, secretome, synapse, axon, dendrite. Great for me. A 20-term glossary for anyone else before they can navigate.
-
No one has asked. Not one person has said “can I run my own vivesca?” I would be building for an imagined audience. Imagined audiences produce wrong abstractions.
-
The second user problem. You don’t design a framework until you have two real instances. With one (me), every design decision bakes in my specifics. With two, the actual shared patterns emerge. Framework-first is backwards.
What I shipped instead
Not the framework. A cleanup.
- Renamed
officinatoproteomein the plan doc (pending execution post-deadline) - Planned merging two private repos into one (
phenotype, containingproteome/andepigenome/) - Committed both specs to
loci/plans/with status frontmatter - Updated my state tracker: “parked until week 2 of next job, because migration risk during deadline week is not worth the elegance gain”
The cleanup ships. The framework doesn’t. If someone ever says “can I run vivesca?”, the spec is already written. Until then, I’m not building for ghosts.
The moment that mattered
When Claude proposed the elegant architecture, I asked: “is it a perfect and ideal architecture?”
The honest answer was no. The honest answer is almost always no for any architecture that’s been iterated on for ten minutes without hitting code. Hard problems compound invisibly when you’re in the design phase. You can’t see them until you try to implement, and the cost of trying-and-failing at scale is much higher than the cost of listing them up front.
The move that saved me: I asked the question and made the agent list the problems instead of defending the proposal. Nine real problems appeared immediately. None of them were trivia. All of them would have eaten months.
The principle
YAGNI applies to architecture, not just features.
You already know not to add features nobody’s asked for. The same logic applies to abstractions, frameworks, and generalizations. If you’re designing for imagined users, you’re building on fiction. When real users show up, they’ll need different things than you predicted, because you predicted them from your own specifics.
The rule: ship the smallest thing that solves your actual problem. Document the elegant version for later. Let the elegant version sit until someone asks for it. If no one asks, you saved months. If someone asks, the spec is ready and now you have a real second user to design with.
Framework-first is a trap that looks like ambition. The best frameworks are extracted from working systems, not designed before them.