My stack
Nine stacks, and the shipped thing each one is answerable for. The problem picks the language; the language then commits you to something, and that part is worth saying out loud.
I wrote a backend with an empty dependency block, and it was the runtime that made that reasonable rather than reckless.
apps/api in Tether: authentication, device custody, lending, catalogue, search and a live event stream. package.json lists "dependencies": {} — every line of it is Bun’s own surface.
Bun.serve for HTTP and a router I wrote over it, bun:sqlite for a synchronous in-process database, Bun.password for argon2id hashing off the event loop, and crypto.getRandomValues for ids. bun build --compile turns the lot into a single executable with the database beside it.
A synchronous query blocks everybody, so /metrics reports event-loop lag — the one number that tells you it happened. Custody transfers settle on a timer as well as on read, because a veto window that only closes when someone looks is not a window.
Zero dependencies is not a boast about discipline. It is a bet that the runtime’s own primitives are better maintained than the packages I would have reached for — and the price of the bet is that I own the router, the migrations and the metrics.
Three of the things I maintain are Go, and all three are Go for the same reason: they are libraries other people compile into their own programs.
About 49,891 lines on Go 1.25, split into parser, tree, retrieval, ingest, storage, cache and queue packages, with Connect RPC generated through buf and a handful of benchmark commands beside the server.
A PDF has no headings — only glyphs with a size and a position. pdfgrab walks the content stream and surfaces positioned characters, lines, rects and curves, so tables can be found by geometry and every extracted string keeps the coordinates it came from to render back over a rasterised page.
Provider-agnostic LLM calls over Anthropic, OpenAI and Gemini with routing, fallback, cost tracking and composable middleware — so nothing above it is wired to one vendor. Built on langchaingo.
Go where the output is a binary or a module somebody else imports. The compile-time strictness is the point: a retrieval engine that panics in someone else’s service is my problem, not theirs.
Mercala is the one built the way a team would need it built, because that is the constraint it was written under.
mercala-core, mercala-agent, mercala-contracts and mercala-image-gen under one Maven parent on Java 21. Contracts is its own module so the agent and the core cannot drift apart quietly.
Spring Web and validation, Spring Kafka between modules, Resilience4j for circuit breaking and retry, Actuator for health, springdoc for the OpenAPI surface, and logstash-logback-encoder so the logs come out structured. The agent side runs on Spring AI.
Hybrid search with no Elasticsearch — full-text and vector ranking reconciled inside Postgres. One datastore to run, back up and reason about, rather than a second cluster to keep in sync with the first.
Honest state: the payment path is modelled and not wired. It is on the Mercala page in those words, and it stays there until it is true.
App Router, server-first, and one deliberate heresy on this particular site.
This site, Coursified’s web app and Voxtar’s. Server components by default; a client component is a decision with a reason, not the starting point.
Every internal link is a plain <a>. The pages are ported from a static design set where each page owns its own script and its own stylesheet — so a client-side transition would leak one page’s CSS into the next and skip the script the new page needs. The lint rule that forbids this is disabled with that reason written beside it.
Two separate React #418 mismatches came out of this port: page scripts mutating the DOM before hydration (fixed by moving them to afterInteractive), and whitespace text nodes inside table elements, which the HTML parser relocates and React then does not find where it left them.
Ported by a script rather than by hand, so a design revision re-ports instead of being re-typed — and verified by pixel-diffing every page against the original at three widths.
Two mobile apps, and neither of them owns a colour.
Both are Expo apps inside a Bun workspace beside the API they talk to, on React 19 and React Native 0.86 pinned at the root so one version of React exists across the whole tree.
@tether/design is a workspace package the mobile app imports; Coursified has packages/tokens doing the same job for web and mobile at once. A colour or a type step is declared once and read everywhere — which is the only reason the phone and the web build still look like the same product.
Getting a design to survive the trip into React Native is a matter of checking, not of eyeballing: fonts that silently fall back, shadows that do not exist on Android, and a safe-area inset that changes the whole layout.
The relay exists because a Worker cannot hold a stream open, and a Durable Object can.
A Worker has a 30-second CPU limit per request. Server-Sent Events held in a Worker would simply die, so the stream lives in a per-channel Durable Object instead — which holds writers indefinitely and hibernates when idle.
Hibernation is what makes “leave the bridge open all day” cost nothing. The relay is a dumb pipe: store the event, hold the stream, correlate request with response. It has no key to your machine and cannot run code on it.
Every event is captured in Postgres with full request and response detail, which is what turns a tunnel into an observability layer — replay, edit-and-replay, latency percentiles and signature checks.
Read the whole thing on the BridgeHook page, including what it borrows from smee.io and says so.
Python where the work is numbers, models or a script that has to be readable a year later.
The analysis service inside Voxtar: the part that takes recorded speech and produces acoustic measures against a person’s own baseline, rather than against a population average.
A Telegram bot that posts a quiz poll every morning, marks it automatically and publishes a leaderboard at close of play. Negative marking is −0.5, which is the figure the exam actually uses.
context8 reached 1.0.0 in 18 days across 52 commits. swarmtorch brings 120 metaheuristic optimisation algorithms to PyTorch with GPU-batched fitness evaluation — both are on the libraries page with their real version numbers.
Models sit behind a gateway, and MCP servers are something I write rather than only consume.
- Never one providerLLMGate exists so that Anthropic, OpenAI and Gemini are a routing decision with a cost number attached, not three rewrites. Fallback is configuration.
- I write the servers too
vectorless-mcpgives any MCP client structure-preserving retrieval; Coursified carries its ownpackages/mcp. Consuming somebody else’s tool is the easy half. - The SDKs are a means, not the architectureClaude Agent SDK and the Vercel AI SDK where they fit, plain HTTP where they do not. The interesting part is always the retrieval and the contracts, not the call.
- Retrieval before embeddingsVectorless exists because chunking throws away the structure that made the document answerable. Where a vector index genuinely earns its place — pgvector, Qdrant — it gets one.
Picking a stack is cheap. Living with what it commits you to is the job — and that is the part worth reading a repository to check.
Two copies of a CodeMirror package are two different types, and a caret range cannot promise you only get one.
- What brokeCoursified’s production build failed on 16 September 2026. Vercel’s bun could not parse the lockfile, resolved dependencies fresh, and landed
@codemirror/state6.7.4 beside 6.7.5. - Why two copies are fatalCodeMirror’s classes carry private fields, so to TypeScript two copies are two nominal types. Every
EditorViewpassed between them fails to typecheck — identical code, identical versions to the eye, and nothing compiles. - The fixBoth packages pinned exactly in
overrides, inpackage.jsonrather than the lockfile, so it holds even when the lockfile is ignored. A caret range promises behaviour; here what mattered was identity. - The note stays in the repoThe reasoning is written into
package.jsonbeside the pin. A pin without its reason is the next person’s bug.
The stacks are only interesting because of what they shipped.
Every one above names a repository. The products page is where they turn into things you can open, and the activity page is generated from the registries rather than written by hand.