One schema, three surfaces

Joel writes in a reply:

my approach wrt to the agentic backend is to cover cli/api/mcp27 with a single openapi15 schema that is used to generate all three

His example is this repository. A capability is a named action with a contract and handler. A contract defines the shared input, output, failures, and metadata. Effect Schema supplies types and runtime checks for these values.

The code makes the direction more precise:

Each interface for calling the action, or surface, shares the same behavior. defineContract owns input, output, failure, description, and annotations. implement binds one handler.

A projection builds an interface from a capability.

One contract feeds the projections

Contract (Effect schemas + one handler)
├─ toHttpApi ── HTTP + OpenAPI
├─ toCommand ── CLI
└─ toToolkit ── MCP tools

Where the CLI composes them

apps/cli/src/surfaces.ts composes the projections. command.ts maps registered capabilities to commands. It also prints the generated OpenAPI document.

Source: apps/cli/src/surfaces.ts at a646f7ffd00273d85fbe1d905d9cdb194fdc0f60, lines 21–25.

apps/cli/src/surfaces.ts · a646f7ff
export const http = toHttpApi("RatStack", capabilities);

export const tools = toToolkit(capabilities);

export const codeMode = toCodeMode(capabilities);

Each call receives the same capability list.

One HttpApi definition supplies the HTTP implementation and its OpenAPI document. The broader shared definition is the capability contract. This split avoids three independently maintained schemas.

See MCP27, OpenAPI15, and code mode21 for each interface.

See how we do it with Effect9 for the whole path.

Sources

  1. Joel Hooks on schema-driven CLI/API/MCP. Primary source. Joel Hooks on schema-driven CLI/API/MCP Accessed 2026-10-02.
  2. packages/capability/src/contract.ts. GitHub. packages/capability/src/contract.ts Accessed 2026-10-02.
  3. packages/capability/src/to-http-api.ts. GitHub. packages/capability/src/to-http-api.ts Accessed 2026-10-02.
  4. packages/capability/src/to-command.ts. GitHub. packages/capability/src/to-command.ts Accessed 2026-10-02.
  5. packages/capability/src/to-toolkit.ts. GitHub. packages/capability/src/to-toolkit.ts Accessed 2026-10-02.
  6. apps/cli/src/surfaces.ts. GitHub. apps/cli/src/surfaces.ts Accessed 2026-10-02.
  7. apps/cli/src/command.ts. GitHub. apps/cli/src/command.ts Accessed 2026-10-02.

Last changed 2026-10-07 in f1a00f2. Source on GitHub. Change log.

Linked from

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

    Do not spam or retry through another surface when the result is uncertain.

  2. Agent rules for rat-stack (AGENTS.md). What you may change, which commands to run, and which changes need approval.
  3. Auth. Email and password sign-in through Better Auth, with the signed-in person provided to each RPC call.

    The public sign-in surface is gated by AUTH_ENABLED, which defaults to false.

  4. Build and run rat-stack (README.md). What is in the repo, how the example works, and how to run it.

    Bind a server-side handler, then project the capability onto every agent surface.

  5. 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.

    The largest difference is the API surface.

  6. Change log. What changed in the files served here, newest first.

    One schema, three surfaces — edited: feat(learn): teach cards 63 to 82 with plain lines, diagrams and snippets

  7. Effect + Alchemy peer patterns. Source-grounded patterns from repos on nearby Effect and Alchemy pins.

    Encode the capability-only surface rule in a test or type-aware lint rule.

  8. Effect keeps the surfaces on one contract. Schema owns values, projections build interfaces, and Layers supply implementations.

    One schema, three surfaces: project the contract instead of maintaining three schemas.¶

  9. Feature flags. Typed feature flags with owners, removal dates, and stable subject rollouts.

    A live operator write surface and listFlagChanges remain future work.¶

  10. Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
  11. Infrastructure as effects. Sam Goodwin relates application operations to infrastructure requirements in one typed program.

    Each surface derives its input and failure definitions from the same schemas.¶

  12. learn. Present Effect, Alchemy, XState, and application-design concepts during real work when the operator enables learn mode. Use for adaptive explanations and local learning progress.

    Read the public deck through either surface:¶

  13. MCP is another surface. MCP lists and calls schema-typed tools; rat-stack projects the same handlers instead of adding MCP-only behavior.

    In rat-stack, MCP projects the shared handler.¶

  14. One capability, every surface. A schema-typed contract and one handler feed every interface rat-stack keeps.

    Here, a surface is an interface for calling the action.

  15. OpenAPI describes the refusal too. The generated HTTP contract declares inputs, outputs, and the bodyless 400 returned when decoding fails.

    See generating surfaces for the document’s source.¶

  16. Oxlint rule limits. How the current lint rules draw their syntax boundaries.
  17. Purpose and boundaries of rat-stack (VISION.md). What this starter is for and what a useful copy should keep.

    sh is the teaching surface.

  18. Rat King binds agents into one encrypted network. Rat King plans an encrypted AT Protocol agent network built on rat-stack.

    Every surface projects the same contract.

  19. Rat Stack lore | rat-stack. Short, source-grounded notes on the ideas and decisions behind rat-stack.

    One schema, three surfaces — A capability contract feeds CLI, HTTP, and MCP; OpenAPI is generated output, not their input.

  20. 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.
    Link context

    The interesting question is whether one Effect Schema definition can project into a CLI, a REST API with OpenAPI, an MCP server, and a code-mode surface, and what Executor and Kody teach about the last two.

  21. Schemas define the boundary. Define accepted data with Schema, decode unknown input before dispatch, and encode results through the declared contract.

    See also: one schema, three surfaces, OpenAPI refusals, services, and testing.¶

  22. Source change history (log.md). The generated change log as Markdown.

    One schema, three surfaces — edited: feat(learn): teach cards 63 to 82 with plain lines, diagrams and snippets

  23. use-a-prompt. Discover and read published rat-stack prompts before starting a task with one.

    Call listPrompts through an available capability surface.¶

Unlinked mentions (46)