# Effect keeps the surfaces on one contract

> For agents: start with the [agent guide](https://ratstack.sh/llms.txt). Every page is Markdown by default; add `Accept: text/html` for HTML.

Free workshop: [how to burn a trillion tokens and get good results](/tokenmaxx#interested).

Our shared definition is [`packages/capability/src/contract.ts`](https://github.com/joelhooks/rat-stack/blob/main/packages/capability/src/contract.ts). Effect Schema owns inputs, outputs, and failures. [`implement.ts`](https://github.com/joelhooks/rat-stack/blob/main/packages/capability/src/implement.ts) binds the handler and its approval requirement.

The HTTP projection creates an Effect HttpApi. Other projections create CLI commands and an AI toolkit from the same contracts.

[`apps/cli/src/surfaces.ts`](https://github.com/joelhooks/rat-stack/blob/main/apps/cli/src/surfaces.ts) and [`apps/mischief/src/app.ts`](https://github.com/joelhooks/rat-stack/blob/main/apps/mischief/src/app.ts) supply implementations with Layers.

## Follow one surface at a time

- [MCP is another surface](/lore/mcp-is-another-surface): discover and call the toolkit over the protocol.
- [OpenAPI describes the refusal too](/lore/openapi-describes-the-refusal-too): derive the HTTP document and declare the bodyless decode failure.
- [One schema, three surfaces](/lore/one-schema-three-surfaces): project the contract instead of maintaining three schemas.
- [Schemas define the boundary](/lore/schemas-define-the-boundary): decode unknown values and keep domain refusals typed.
- [One program can replace several tool calls](/lore/one-program-can-replace-several-tool-calls): combine content capabilities without widening their authority.

## Layer supplies the job

[`packages/core/src/join-intake.ts`](https://github.com/joelhooks/rat-stack/blob/main/packages/core/src/join-intake.ts) builds a `Layer.effect(JoinInterest, ...)`. It captures the ticket, scoring, events, contact store, delivery, and token services. It then returns the submission method.

Source: [`packages/core/src/join-intake.ts` at `445b1a20b51a5492f8e586daeb9306e8011b7673`, lines 44–50](https://github.com/joelhooks/rat-stack/blob/445b1a20b51a5492f8e586daeb9306e8011b7673/packages/core/src/join-intake.ts#L44-L50).

```ts
const tickets = yield* IntakeTicket;
const scorer = yield* AbuseScore;
const events = yield* IntakeEvents;
const contacts = yield* JoinContactStore;
const intake = yield* SubscriberIntake;
const tokens = yield* InterestTokens;
const crypto = yield* Crypto.Crypto;
```

**What to notice:** The Layer captures dependencies before returning the submission method.

Effect's [`Layer.provide`](https://github.com/Effect-TS/effect/blob/effect%404.0.0/packages/effect/src/Layer.ts) supplies a Layer's dependencies. [`HttpApiBuilder.layer`](https://github.com/Effect-TS/effect/blob/effect%404.0.0/packages/effect/src/http-api/HttpApiBuilder.ts) registers HTTP routes and can expose OpenAPI. Neither requires a second domain handler.

[One capability, every surface](/lore/one-capability-every-surface) states the house rule. [Hexagonal architecture](/lore/hexagonal-architecture) names the adapter boundary. [The fence](/lore/the-fence) enforces it.

The [peers](/resources/same-version-repos.svx) page records other Effect and Alchemy projects. It does not claim that they use this design.

## Sources

1. [packages/capability/src/contract.ts](https://github.com/joelhooks/rat-stack/blob/main/packages/capability/src/contract.ts)
   GitHub. packages/capability/src/contract.ts Accessed 2026-10-02.

2. [packages/capability/src/implement.ts](https://github.com/joelhooks/rat-stack/blob/main/packages/capability/src/implement.ts)
   GitHub. packages/capability/src/implement.ts Accessed 2026-10-02.

3. [packages/capability/src/to-http-api.ts](https://github.com/joelhooks/rat-stack/blob/main/packages/capability/src/to-http-api.ts)
   GitHub. packages/capability/src/to-http-api.ts Accessed 2026-10-02.

4. [apps/cli/src/surfaces.ts](https://github.com/joelhooks/rat-stack/blob/main/apps/cli/src/surfaces.ts)
   GitHub. apps/cli/src/surfaces.ts Accessed 2026-10-02.

5. [apps/mischief/src/app.ts](https://github.com/joelhooks/rat-stack/blob/main/apps/mischief/src/app.ts)
   GitHub. apps/mischief/src/app.ts Accessed 2026-10-02.

6. [packages/core/src/join-intake.ts](https://github.com/joelhooks/rat-stack/blob/main/packages/core/src/join-intake.ts)
   GitHub. packages/core/src/join-intake.ts Accessed 2026-10-02.

7. [Effect 4 Layer](https://github.com/Effect-TS/effect/blob/effect%404.0.0/packages/effect/src/Layer.ts)
   GitHub. Effect 4 Layer Accessed 2026-10-02.

8. [Effect 4 HttpApiBuilder](https://github.com/Effect-TS/effect/blob/effect%404.0.0/packages/effect/src/http-api/HttpApiBuilder.ts)
   GitHub. Effect 4 HttpApiBuilder Accessed 2026-10-02.

## Lore on this page

- [OpenAPI describes the refusal too](/lore/openapi-describes-the-refusal-too)
- [A clean playground](/lore/a-clean-playground)

## Linked from

- Agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms.txt)

- Change log → What changed in the files served here, newest first. → [Read page](https://ratstack.sh/log)

- Full agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms-full.txt)

- log.md → The generated change log as Markdown. → [Read page](https://ratstack.sh/log.md)

- MCP is another surface → MCP lists and calls schema-typed tools; rat-stack projects the same handlers instead of adding MCP-only behavior. → [Read page](https://ratstack.sh/lore/mcp-is-another-surface)

- One program can replace several tool calls → Code mode combines typed content calls inside one bounded execute request. → [Read page](https://ratstack.sh/lore/one-program-can-replace-several-tool-calls)

- One schema, three surfaces → A capability contract feeds CLI, HTTP, and MCP; OpenAPI is generated output, not their input. → [Read page](https://ratstack.sh/lore/one-schema-three-surfaces)

- OpenAPI describes the refusal too → The generated HTTP contract declares inputs, outputs, and the bodyless 400 returned when decoding fails. → [Read page](https://ratstack.sh/lore/openapi-describes-the-refusal-too)

- Rat Stack lore | rat-stack → Short, source-grounded notes on the ideas and decisions behind rat-stack. → [Read page](https://ratstack.sh/lore)

- Schemas define the boundary → Schema-driven development defines accepted values and failures before projecting or decoding them. → [Read page](https://ratstack.sh/lore/schemas-define-the-boundary)
