One capability, every surface
Goal: add one action and get a command, an HTTP route, an MCP31 tool, and a code-mode function from it. Browser RPC uses the same contracts; search and read show that side.¶
A capability is one named action with a contract28 and a server-side handler28.
A contract defines the shared input, output, failures, and metadata. Effect35 Schema30 provides types and runtime checks for these values. defineContract owns the name, Effect schemas, annotations, and approval setting. implement binds that contract to its handler.¶
Here, a surface26 is an interface26 for calling the action. A projection is code that converts registered capabilities into an interface. The interfaces are command line, HTTP, MCP tools, browser RPC, and code mode23. Each interface derives its input and failure definitions from the same schemas.¶
Worked example: inspectFile
1. The contract
export const inspectFileContract = defineContract("inspectFile", {
annotations: { idempotent: true, readOnly: true },
description: "Count bytes, characters, words, and lines in a file",
failure: FileStatsError,
input: Schema.Struct({
path: Schema.String.annotate({ description: "File to inspect" }),
}),
output: FileStatsSchema,
});The contract holds no handler. A browser can import it without server code.¶
2. The handler
export const inspectFile = implement(inspectFileContract, ({ path }) =>
runInspectMachine(path)
);
export const capabilities = [
inspectFile,The handler runs the inspection machine27.¶
3. The projections
export const http = toHttpApi("RatStack", capabilities);
export const tools = toToolkit(cliCapabilities);
export const codeMode = toCodeMode(cliCapabilities);const capabilityCommands = commandCapabilities.map((capability) => {
const command =
capability === inspectFile
? toCommand(capability, {
positional: ["path"],
render: formatFileStats,
}).pipe(Command.withAlias("stats"))No projection repeats the schema. Each one reads the contract it was given.¶
Why one contract
A second hand-written route would need its own schema, and the two could drift. Here each surface derives its input and failure from one place.¶
The split replaced defineCapability, which bundled contract data and its handler in one definition. The RPC client needed the contract without importing server implementation. toRpcGroup now projects contracts alone; toRpc connects those same contracts to implemented capabilities. The browser docs client imports only the shared contracts and RPC group. Commit 9a7bea5 records the split.¶
Michael Arnaldi7 demonstrates Schema decoding30 request input and encoding a frontend-safe result while preserving its output type. Effect Meetup SF, 27:17. In another conversation, the speakers discuss generated schemas and migrations as work agents can maintain, and a rule that rejects ad hoc JSON parsing. Cause & Effect 10, 63:49 67:53.¶
Next
To add a capability, define its contract and implement it beside the data or infrastructure it owns. Register it in capabilities28, then check each interface you keep. packages/capability/test/ exercises projections; apps/site/src/capabilities/index.ts shows the hosted registry.¶
Use the add-a-capability skill for the steps.¶
Read A browser send follows one path to the capability6 to see search called over RPC.¶
Analytics18 shows a separate infrastructure cartridge38; interest signup14 shows core ports with a delivery adapter30 outside core. Neither turns static pages or protocol discovery into domain capabilities.¶
See lifecycles are machines27 for stateful handlers and cartridges38 for the infrastructure boundary. HATEOAS9 covers links that guide an agent’s next action; hexagonal architecture30 names the ports-and-adapters principle.¶
Sources
- rat-stack/AGENTS.md at main · joelhooks/rat-stack · GitHub. GitHub joelhooks/rat-stack. Projection law; used for one contract across every interface. Accessed 2026-10-01.
- Shared contracts at a3f5a14. GitHub joelhooks/rat-stack. inspectFileContract declares the name, schemas, failure, and annotations. Accessed 2026-11-08.
- inspectFile capability at a3f5a14. GitHub joelhooks/rat-stack. implement binds inspectFileContract to runInspectMachine and registers it in capabilities. Accessed 2026-11-08.
- CLI projections at a3f5a14. GitHub joelhooks/rat-stack. toHttpApi, toToolkit, and toCodeMode project the same capability lists. Accessed 2026-11-08.
- CLI commands at a3f5a14. GitHub joelhooks/rat-stack. toCommand projects inspectFile with a positional path and the stats alias. Accessed 2026-11-08.
- rat-stack/packages/capability/src/implement.ts at main · joelhooks/rat-stack · GitHub. GitHub joelhooks/rat-stack. Handler binding; used for separating contracts from implementations. Accessed 2026-10-01.
- rat-stack/packages/capability/src/to-rpc-group.ts at main · joelhooks/rat-stack · GitHub. GitHub joelhooks/rat-stack. Client RPC projection; used for contracts without server handlers. Accessed 2026-10-01.
Last changed 2026-11-08 in fa39fa0. Source on GitHub. Change log.
Linked from
- A browser send follows one path to the capability. In the Foldkit docs browser, a search is a Message, then an update, then a named Command that calls the search capability over RPC on a cache miss and returns a result Message.
Its search box calls the search capability.¶
- Agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
One capability, every surface — A schema-typed contract and one handler feed every interface rat-stack keeps.
- An MCP your users want. Rhys Sullivan's practical guide gives rat-stack a checklist for useful MCP tools.
See one capability, every surface and the cartridges page for the contracts and auth boundary.¶
- CAFE names the Cloudflare, Alchemy, Foldkit and Effect stack. CAFE is a named stack: Cloudflare runs the app, Alchemy declares it, Foldkit draws the UI, and Effect does the typed work.
See one capability, every surface and infrastructure as effects.¶
- Capabilities. Named application actions exposed through generated interfaces share one definition and one server-side implementation.
See one capability, every surface for why.¶
- Cartridges. A cartridge owns one job and brings the infrastructure its service needs.
See one capability, every surface for the shared contract and a clean playground for the house rule behind these boundaries.¶
- Change log. What changed in the files served here, newest first.
One capability, every surface — new page: Initial commit from joelhooks/rat-stack template
- Effect keeps the surfaces on one contract. Schema owns values, projections build interfaces, and Layers supply implementations.
One capability, every surface states the house rule.
- Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
- HATEOAS. Links in a representation tell its reader what to do next; rat-stack applies that idea to agent-facing pages and responses.
One capability, every surface describes the existing projections.
- Hexagonal architecture. Ports name the application's jobs; adapters connect them to the outside world.
One capability, every surface starts with a contract, binds a handler, and projects CLI, HTTP, MCP, RPC, and code mode.
- Infrastructure as effects. Sam Goodwin relates application operations to infrastructure requirements in one typed program.
A contract defines shared input, output, failures, and metadata.
- learn-rat-stack. Trace a capability through Effect, XState, five projections, the CLI, and Alchemy. Try hosted search and read.
A projection builds a callable interface from capabilities.¶
- Lifecycles are machines. XState owns finite lifecycle states while declared Effect actors own side effects.
See one capability, every surface for how a capability can own a machine and the fence for the rule that protects it.¶
- Rat Stack lore | rat-stack. Short, source-grounded notes on the ideas and decisions behind rat-stack.
One capability, every surface — A schema-typed contract and one handler feed every interface rat-stack keeps.
- rat-stack. An Effect stack so pure (aspirational) Kit Langton will blush.
- Run Effect at the integration boundary. Build the runtime where a calling framework enters, reuse its services, and dispose it when that integration ends.
In rat-stack, capabilities remain the shared interface for application actions.
- Schema projections: 2026-09-18 history. Historical Effect rc.115 proposal and implementation receipts from 2026-09-18; use the one-capability-every-surface lore page for the current pattern.
Read One capability, every surface for today’s defineContract → implement pattern, including browser RPC, and current pins.
- Source change history (log.md). The generated change log as Markdown.
One capability, every surface — new page: Initial commit from joelhooks/rat-stack template
- The war stories. Seven public repo incidents: a deploy undoes itself, failure says 200, sessions forget their guests, and the rat tests the demolition instructions.
A generated-program test checks failure reporting across HTTP, MCP, RPC, and the CLI; restoring the false 200 makes it fail.¶
- Turbo remote cache. A separate Worker stores streamed Turbo artifacts in R2, with one credential per team and lifecycle expiry.
The capability projection requires struct inputs, excludes HEAD, and does not describe raw upload streams with per-artifact response headers.
Unlinked mentions (24)
- add-a-capability → A projection builds a callable interface from capabilities.¶
- add-a-feature-flag → A projection is a copy derived from a committed value.¶
- Agent rules for rat-stack (AGENTS.md) → The DO commits values, receipts, and projection markers together; alarms project to KV.
- Analytics → Local tests prove projection and archive writes; they do not prove Cloudflare delivery.¶
- Build and run rat-stack (README.md) → Code mode is another projection.
- Capabilities → A projection builds a callable interface from a capability.
- Durability → The default operator adapter commits position, receipt and projection marker in one Durable Object transaction.¶
- Effect + Alchemy peer patterns → Keep capability schemas in packages/core, the toRpc projection in packages/capability, and UI atoms in the web app.
- Effect keeps the surfaces on one contract → A projection builds an interface from a capability, a named action with a contract and handler.
- Feature flags → A projection is a copy derived from a committed value.¶
- Flags climb on evidence → A projection is a copy derived from a committed value.¶
- Hexagonal architecture → The no-hand-rolled-surface rule keeps interface construction in the projection package.¶
- keep-or-cut → A projection builds a callable interface from capabilities.¶
- learn-rat-stack → A projection takes a registry and reuses its domain handlers.¶
- Lint and type escape ledger (debt.md) → ts: a projection over a heterogeneous list erases error and requirement types at the boundary and recovers them for callers.
- One prompt serves people and agents → A projection builds a callable interface from capabilities.¶
- One schema, three surfaces → A projection builds an interface from a capability.¶
- OpenAPI describes the refusal too → ts builds the /api projection.
- rat-stack → Each projection calls the same handler through the same contract.
- Schema projections: 2026-09-18 history → Code mode is a fourth projection: serialize the catalog (Executor IR shape: JSON Schema per type, path per capability), emit .d.ts from the JSON Schema, expose search and execute as two ordinary Tools whose execute handler runs model code in a sandbox that can only call capabilities by path.
- Schemas define the boundary → In rat-stack, one capability contract supplies schemas to every interface projection.¶
- security-audit → The no-hand-rolled-surface rule in the boundary plugin restricts projection construction to the capability package.¶
- Tests prove behavior through supplied services → A capability is a named action; a projection converts it into an interface.¶
- uncomplect → Projection: An interface built from capabilities: a command, API, or agent tool.¶