Stack
What I build with, and the reason for each choice.
This is what I build with and why, taken from lockfiles, configs, and git history rather than from memory. An item is marked as in use only when it is in an active repo this month.
Languages and runtimes
- TypeScriptusingEvery active repo, strict, run directly by Bun. One observation from 2026: agents do better in Rust because they actually run the compiler, whereas in TypeScript they skip the type check.
- BunusingRuntime, package manager, test runner, and SQLite driver. It runs TypeScript without a compile step, and it is the hard constraint: nothing that needs a JVM gets in.
- RustusedThese were the smart-contract years.
- PythonusedThat was the year of orchestration frameworks. My rule since then is that Python trains and TypeScript ships.
- Lisp, ClojureusedA year around the idea that prompts and agent decisions are plain data. The runtime constraint ended it; the code-is-data framing stayed.
Frameworks and libraries
- Next.js, ReactusingI left it once for a mobile backend in 2025 and came back for every site since, including this one.
- TurborepousingIt is only in repos with real build graphs; the rest are plain workspaces.
- Vercel AI SDKusingThe one framework layer I keep, because provider abstraction is the part a framework can solve. It sits behind one wrapper so every model call runs on a subscription.
- ZodusingIt is in every repo, and I still wish for grammar-based validation.
- DrizzleusingChosen over Prisma because I already knew SQL and did not want a layer that hid it.
- Tailwind 4, Biome, Shiki, MDXusingThis site. Lint is advisory in CI on purpose; a check that is red by default teaches everyone to ignore red.
- RemotionusingHard to make a nice video with at first. The explainer-video studio runs on it, and on the Linux box it renders faster than realtime.
- commanderusingEvery tool in my personal system is a subcommand. The binary is the interface.
- EveusingClose to the shape I want: an agent is a directory of files and the whole system is version-controlled.
Data
- SQLiteusingHabits, relationships, the search index, every business body. Files are for what a human writes and diffs; a database is for many rows of one shape that a machine writes.
- sqlite-vecusingVectors in the same file as the text. About a hundred times faster than the local-first tool I tried first.
- A local file by default. One environment variable makes it a replica shared across hosts with no server I run.
- Markdown in a folder, under gitusingThe daily log is markdown and SQLite only indexes it. Event-sourced designs were rejected three times.
- ZepusedIt holds the memory organ's graph, still registered and unused since May.
- PostgresusedOne venture ran on it in mid-2026 before moving to SQLite.
Infra and machines
- The Linux boxusingA daily money reading died once because the laptop had no network at 7:30am, and a missing datapoint looks like a quiet day. Since then nothing scheduled runs on a laptop; the Mac is authoritative and the box is a replica for compute.
- CoolifyusingThe deploy layer on the box, next to a self-hosted job runner and a local container registry.
- DockerusingAgent sandboxes with a coding agent and Bun baked in.
- It keeps run history with unlimited retention, and the daily money digest lives here.
- A push to main is picked up by a runner on the box over an outbound connection. No webhooks, no open ports.
- Cloudflare PagesusingThirty small sites up in August 2026 with a hundred planned, each a probe to see whether anyone clicks.
- VercelusingThis site and one cohort of the business sites.
- Stripe, ResendusingThe repo never mirrors their state, because a mirror is a cache and caches drift.
- Upstash RedisusingA rotating credential can have exactly one writer, so the shared token store lives here.
- Subscriptions, not API keysusingModel calls route through one provider on the chat subscription. Headless agent calls are billed as API and treated as real spend.
Workflow
- git, GitHubusingGit is the convergence mechanism: uncommitted means proposed, a commit means accepted. Agents cannot delete repositories, because the token lacks the scope, on purpose.
- Worktrees, one writer per checkoutusingSeveral branch-mutating agents in one working directory corrupt each other, because a branch switch is global to the directory.
- Stacked PRsusingEach PR is one reviewable idea. I review from my phone, so a small diff is the difference between a review and a rubber stamp.
- LinearusingA good issue is a home for convergence rather than a task. What it lacks is a long-running view of ends and monitors, something that is not a chat.
- Claude Code, Cursor, Codex, pi, OpenClawusingThe loop as of August 2026: something becomes a Linear issue, I approve it, a cloud agent picks it up, I review and merge.
- MCPusingScripts come first; the protocol wraps them for when a second harness needs the same thing.
- SlackusingOne bot, pull-based, no server. Each business agent is bound to its own channel.
Dropped, with the reason
- AzuredroppedI now use it only for image generation and reranking. Other providers handle the remaining model calls.
- Cloudflare Durable ObjectsdroppedThe design started from schemas and runtime machinery before it had touched enough reality. Replaced by a folder under git, local-first.
- ConvexdroppedFast to move with, and it limited how much I could over-schematize. It survives as the analogy for what I want to be for agents.
- Supabase, then MongoDBdroppedSchemaless felt right when I did not know what I was building. Both gone by 2026; the journals are markdown files.
- LangChaindroppedIts core abstraction was the thing I kept working around, which told me it was solving a different problem than mine.
- n8ndroppedI found I could standardize the input to rich text plus attachments and let scripts decide.
- Railway, HonodroppedIt lasted two months, and the home server took that role.
- A Telegram bot for capturedroppedA log command and a voice recorder on walks replaced it.