What we build on, and what we keep out
Everything we build on is named below, with the version we run and what each piece is responsible for. Beside it sits a shorter list.
That one holds the things this stack keeps out on purpose. Each entry carries its reason and the assertion in the code that keeps it out. Where our own written rules are ahead of our own practice, those counts are here too, with the date they were taken. All of it is checkable inside the repository you would end up owning. If you are weighing us up for a specific build, the fastest route is to tell us what it is.
One tool installs the libraries and one lockfile records what it installed. So a dependency tree cannot differ between two contributors, or between a laptop and a build machine. That is npm workspaces, at npm@11.6.2. The build coordinator, Turborepo, sits at turbo 2.9.12, pinned to that exact version with no range around it. The language on the hosting side is TypeScript, at typescript 6.0.3, also exact. Charts are drawn with ECharts. The headless tests run on Vitest with the Cloudflare Workers pool, and the browser tests run on Playwright with axe checking accessibility.
How the platform is put together
5
The database
Cloudflare D1 with Drizzle, at drizzle-orm ^0.45.2 and drizzle-kit ^0.31.10. SQLite at the edge, with queries written in TypeScript.
Hands upward
A schema and its migrations, versioned in the same repository as the code they belong to.
4
Hosting
Cloudflare Workers Static Assets, at @astrojs/cloudflare ^13.5.5 and wrangler ^4.95.0. The static front end and the edge logic stay joined.
Hands upward
A single deployment, running close to whoever asked for the page.
3
Styling
Tailwind v4 on a token theme, at tailwindcss ^4.3.3. Named tokens only, so no hex colours, no raw pixel lengths and no one-off values.
Hands upward
One set of colours and spacing steps that every surface draws from.
2
Interactive widgets
Solid and Kobalte islands, at solid-js ^1.9.13 and @kobalte/core ^0.13.11. Only the parts that have to respond ship any JavaScript at all.
Hands upward
Menus, accordions and forms that work with a keyboard and with a screen reader.
1
The website builder
Astro, at astro ^6.3.8. It turns content and components into pages ahead of time, so most of the site is finished HTML before anyone asks for it.
Hands upward
Pages that arrive without a framework runtime attached to them.
Automation that runs on our own machines is Python, and no package.json in this repository carries it, by design. The boundary is physical.
What a stack choice commits you to
If you are the one who signs for this build, you carry it afterwards. The people who wrote it move on to other work. The runtime underneath keeps its own schedule and stops being supported on a date somebody else already set. If the only people who can read what was built are the people who built it, every later change routes back through them.
That exposure lands on whoever approved the choice, not on the firm that delivered it. Checking us on that before anything is signed is reasonable. None of it needs to be taken on trust.
The runtime we build to has a published support window, with dates anyone can look up. This stack keeps certain things out on purpose, and something concrete holds each refusal in place. Once we are gone, the work can be picked up by people we never hired. The accounts were yours the whole time.
One boundary belongs here rather than at the end. We work primarily in TypeScript and JavaScript, across the browser, Node and the edge. That rules out real work, and it may rule out yours.
Each Node.js line runs about 36 months from first release to end of life. Roughly 30 of those months sit under long-term support. The working group publishes the dates years ahead. The end of any line can be looked up before anything is committed to it. Node 20 stopped receiving support on 2026-04-30. Node 22 is scheduled through 2027-04-30, and that is the floor this stack is built to.
Forward-readiness is a posture, not a guarantee.
Show data table
| Stage | end-of-support year |
|---|---|
| Node 18 | 2,025 |
| Node 20 | 2,026 |
| Node 22 | 2,027 |
| Node 24 | 2,028 |
| Node 26 | 2,029 |
This stack needs Node 22 or later. Node 22 is scheduled to be supported until 2027-04-30.
What this stack keeps out
Four model providers are called in the work we do. Two are direct: the OpenAI API and the Anthropic API. Two are cloud platforms: Google Cloud with Vertex AI and Gemini Enterprise, and AWS with Amazon Bedrock. What each one may do with code and data is set out on our AI-augmented development page. Those terms live there. None of the four is reachable from the hosting side, which is the first of five things this stack keeps out on purpose.
- A model vendor's software development kit inside a hosted Worker. None of the 16 package.json files in this repository declares one, and that covers the OpenAI, Anthropic, Google and Amazon Bedrock client libraries alike. The enforcement is narrower than the count. The integration suite carries a forbidden-import list naming the Anthropic client libraries and its API host, at apps/anima-site/test/integration/error-pages.integration.test.ts, lines 206 to 211, so a new file importing one of those fails. The other three rest on the dependency files alone. The ratified rule behind it is that no agent code runs in a Worker. Both the dependency files and that list sit in this repository, and one command runs the tests. Nothing here blocks a commit, a push or a merge, so it is a check anyone holding the code can run rather than a gate that stops work on its own.
- pnpm, yarn and bun. One package manager and one lockfile: package-lock.json is in the repository, and pnpm-lock.yaml, yarn.lock and bun.lockb are not. Moving to any of them, or to Nx, means retiring the decision page that rules them out and writing its successor first.
- A build cache shared across machines. Switching one on would mean writing down the telemetry tradeoff first, in its own decision page, before anything changed.
- Cloudflare Pages. Everything deploys on Workers, so the static front end and the edge logic ship together under one configuration.
- Hex colours, raw lengths and one-off styling values. Every colour and every spacing step comes from a named token, so a change to the palette reaches every surface at once.
The data terms for each of the four providers:
AI-augmented developmentWhen the work is finished, the code lives in your repositories and the deployments in your cloud accounts. If you already have your own Git hosting, cloud accounts and storage, we work inside them. If you do not, we provision them, set them up, and hand the keys over.
Owning it matters more when somebody other than us can pick it up. That is a large part of why this stack is assembled from widely used pieces rather than from anything invented here. The figures below come from the Stack Overflow Annual Developer Survey 2025. They are the share of developers who answered its web-frameworks question. Only one of the seven is part of this stack: Node.js, which everything here is built to run on. The others are shown so that figure has something to sit against.
Show data table
| Item | Value |
|---|---|
| Node.js | 48.7 per cent |
| React | 44.7 per cent |
| Next.js | 20.8 per cent |
| Express | 19.9 per cent |
| Vue.js | 17.6 per cent |
| Svelte | 7.2 per cent |
| Deno | 4 per cent |
Node.js, the runtime everything here is built to run on, is the most commonly used of the seven.
Three counts from this repository, taken on 2026-09-04.
They describe a live tree and they drift, so the date travels with them.
Of 22 declared technologies, 13 have a reason we can quote from a ratified decision page. The other nine are ordinary libraries, chosen because they do the job. Saying that is more accurate than pretending every line of a lockfile was a strategic call.
Pinning is real here and it is not uniform. Eight of the nine root development dependencies are set to an exact version. A vite 7.3.3 override binds what the dependency tree resolves underneath. Our own pinning rule also asks for mise.toml, .nvmrc and .node-version at the repository root. None of the three is there. We wrote the rule and we have not finished applying it.
The ratified decision pages behind the toolchain, 2026-09-04
9 root development dependencies, 2026-09-04
3 files named by the rule, 2026-09-04
*Disclaimer: The same rule asks for Wrangler pinned to an exact version, and apps/anima-site declares wrangler ^4.95.0, which is a range.
Forward-readiness is a posture, not a guarantee, and we will not claim more than that. Two commitments hold when a choice ages.
When a choice ages
The platform under your system goes out of support.
You are still shipping on it, and the pressure turns into a full rewrite of code that works.
What we commit to
We modernize without forcing rewrites where audits show incremental hardening will do. The audit comes first, and a rewrite is what happens when hardening genuinely will not carry it.
A decision about your system gets made by tooling.
Nobody reads it before it lands in your repository.
What we commit to
Human judgment on every decision. A person reads what goes into your system and answers for it afterwards.
Whether this fits your work
Where we fit
Work that runs on the web, across the browser, Node and the edge.
A build you will own outright and host in your own accounts.
A team that wants the reason behind each choice written down somewhere they can read it.
Where we are the wrong call
You need a native iOS or Android application rather than something that runs on the web.
You want people working inside your existing team rather than a build you own end to end.
Questions, answered
Which AI model providers do you use, and what happens to our code?
What version of Node does this stack run on?
Do we own the code, and can we host it ourselves?
Is everything pinned to an exact version?
Will you build on something other than this?
Do you use pnpm, yarn or bun?
Everything above is a starting position, and a specific build moves parts of it. Tell us what you are making, what it has to run on, and who has to maintain it once it is live. We will say which parts of this apply to your case and which parts we would change. That answer comes before anything is agreed. If the disqualifying conditions above describe your work instead, saying that early saves us both a call.
Bring the thing you are building
We choose the stack that fits the project, not the one that maximizes our familiarity.