Rat Stack

Most of this site is for you to hand to your agent and use in your own setup. A lot is generated, and some of it reads weird. I’m rewriting it as I go, so it’s better to read for me and for you. Comments, feedback, and discussion are welcome: @joelhooks on X.

Build an app and its cloud as one typed program: TypeScript checks how the parts fit together. Effect is a TypeScript library for dependencies, errors, and concurrent work. Alchemy declares cloud resources in TypeScript and infers their connections from the code. Our goal is the best Effect + Alchemy application we can build.

An Effect stack so pure (aspirational) Kit Langton will blush.

The fence is our compiler checks, lint rules, and commit hooks. They reject prohibited code and shortcuts.

Copy rat-stack into your project and keep its source under your control. Keep the packages you need and follow the removal checklists for the rest.

Connect an agent

Paste this into your coding agent:

Read https://pr-108.ratstack.sh/llms.txt and use rat-stack as the reference
for how we build: Effect for the hard parts, Alchemy for the
infrastructure, and a fence that makes the easy path the right
one. Search its rules and skills before you write code, follow
its patterns, and tell me when my code breaks them.

Or connect the MCP (Model Context Protocol) server to let your agent call the site’s tools:

# Claude Code
claude mcp add --transport http rat-stack https://pr-108.ratstack.sh/mcp

# Codex
codex mcp add rat-stack --url https://pr-108.ratstack.sh/mcp

Cursor reads ~/.cursor/mcp.json:

{ "mcpServers": { "rat-stack": { "url": "https://pr-108.ratstack.sh/mcp" } } }

Load a skill into one session when the task needs it. Skills stay out of global and project skill folders. The skills index lists every skill and its SKILL.md URL.

Supports MCP protocol versions 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26, and 2024-11-05. Clients on protocol 2026-07-28 use no sessions. Older clients get their own session in a Cloudflare Durable Object, which stores state between requests.

Four ideas

See the vision for the reasoning and sources.

Packages and their jobs

rat-stack ships these packages and apps. Remove the ones you don’t need with the removal checklists. Trace their imports and run the checks after each cut.

| Package or app | Job | Removal | | --- | --- | --- | | capability | Shared data definitions and command-line, web, and agent interfaces | Keep the interfaces you use | | core | Shared operations and service interfaces | Keep what your app uses | | database | Run logs with D1 or Hyperdrive Postgres | Remove dependent services too | | auth | Identity and access through Better Auth16 | Remove dependent services too | | devtools | Record, replay, and compare operation calls | Optional development tools | | events | Capture request analytics18 | Optional | | lore | Query the public content graph | Remove dependent content operations too | | subscriber-delivery | Handle signup and email confirmation11 | Remove dependent signup operations too | | intake-live | Validate signup applications and protect stored answers | Remove dependent signup operations too | | code-snippets | Build highlighted code examples from source files | Remove dependent content features too | | check-harness | Run checks and report their results | Remove dependent deployment checks too | | deploy | Plan, apply, check, and roll back deployments | Remove dependent deployment commands too | | web | Browser UI built with Foldkit | Optional | | cli | Command-line interface | Optional | | mischief | Hosted site, agent interfaces, and code sandbox | Optional | | infra | Alchemy cloud resource declarations | Keep resources your app uses |

A cartridge is a package for one job, including its implementation and cloud resources. Add it with one package and one line that provides the implementation. Removing it must leave unrelated packages working.

The hosted agent interfaces6 run in Mischief; extracting them into a separate cartridge36 is still work to do.

Hexagonal architecture keeps service interfaces in core and provider-specific implementations outside it. A port names a job; an adapter connects it to a provider. HATEOAS uses response links to guide the next action. Analytics is a running capture system; interest signup shows consent and confirmation across a delivery adapter.

One capability, several interfaces

A contract defines an operation’s name, input, output, and errors. A capability binds that contract to a server-side handler. A projection exposes the capability through one interface, such as the CLI (command-line interface) or HTTP.

XState models work as states and the transitions between them. Effect Schema defines and validates the data each operation accepts and returns.

RPC (remote procedure call) lets the browser call server operations. OpenAPI describes the HTTP API in a format that software can read. Code mode21 is a way to run a program that calls tools inside a sandbox, a restricted execution environment.

              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚  one contract + capability          β”‚
              β”‚  Effect Schema: input Β· output Β· errβ”‚
              β”‚  one Effect handler                 β”‚
              β”‚  XState when the work has states    β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚  defineContract β†’ implement
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β–Ό            β–Ό            β–Ό            β–Ό            β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ command  β”‚ β”‚   HTTP   β”‚ β”‚   MCP    β”‚ β”‚   RPC    β”‚ β”‚ sandbox  β”‚
  β”‚   line   β”‚ β”‚ + OpenAPIβ”‚ β”‚  tools   β”‚ β”‚ browser  β”‚ β”‚ code modeβ”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  checked by  TypeScript 7 Β· Oxlint Β· Vitest Β· lefthook
  shipped by  pnpm Β· Turborepo Β· Alchemy β†’ Cloudflare Worker
One capability projected to the command line, HTTP with OpenAPI, MCP tools, browser RPC, and sandbox code mode

All five projections share one contract and handler. Agents use MCP27, HTTP, or code mode.

The pattern in code

This is the whole search capability. Every interface calls it.

export const search = implement(searchContract, ({ limit, query }) =>
  ContentStore.use((store) => store.search(query, limit)).pipe(
    Effect.map((matches) => ({ matches, total: matches.length }))
  )
);

The schemas define the input, output, and errors. Each projection calls the same handler through the same contract.

Learn the stack

Install these short guides for your agent with the command above, or read them here.

Start here

See how the pieces fit

Learn by building

Choose what you keep

Keep the fence sharp

Ship with evidence

XState 6 and Alchemy are pre-release. APIs move; pins.md lists the exact versions this repo builds against.

Source files