Hexagonal architecture
Alistair Cockburn’s 2005 article calls the pattern “Ports and Adapters,” with “Hexagonal Architecture” as its alternative name. Users, programs, tests, or batch scripts can drive the application. Tests can run without its eventual devices and databases.¶
A port is an interface for an application job. A technology-specific adapter implements that interface for an outside system. The application need not know what is on the other side. The distinction is inside versus outside, not a prescribed number of sides.¶
Rat-stack’s stance
Joel Hooks:¶
I think hexagonal and ports and adapters, generally speaking, is an extremely good fit and matches what we are kind of doing anyway inside of our effect layer. So if we were putting a name on the architecture or a principle from which we derive our own version of the architecture, hexagonal would be it. We are not zealots. However, we do recognize really good ideas when we see them.¶
Rat-stack’s Effect layer follows the inside/outside boundary. We adapt that principle without requiring the whole architecture, its diagram, or particular folder names.¶
How rat-stack does it
On the driving side, interfaces call the application. One capability, every surface18 starts with a contract, binds a handler, and projects CLI, HTTP, MCP, RPC, and code mode21. The no-hand-rolled-surface rule keeps interface construction in the projection package.¶
On the driven side, where the application calls services, Effect Context.Service definitions provide ports for sending interest mail, subscriber intake (SubscriberIntake), and confirmation (SubscriberConfirm). Layers provide recording or HTTP mail, unconfigured or HTTP confirmation, and in-memory storage. Tests provide memory, recording, and fake services. Worker wiring builds the production HTTP adapters alongside InterestMode; it does not swap the whole adapter set on each mode.¶
The switch to the external signup implementation also changes application behavior. The handler branches on mode, and the confirm routes do too. The form template keeps its fields and POST target across modes, but rendering inserts a human-check widget when a site key is configured. Its complete markup is not guaranteed identical.¶
Typed preparation for agent-assisted intake uses the same service boundary: IntakeTicket, AbuseScore, and IntakeEvents, question and consent schemas, and test layers live in core. Interest signup12 records the agent-only application path and email confirmation11 boundary.¶
Boundaries fixed
Three leaks have been fixed:¶
- HTTP adapters lived beside ports in core. The mail, intake, and confirmation HTTP adapters now live in
@rat-stack/subscriber-delivery, composed bysrc/delivery.ts.¶ - Two ports were named for the provider rather than the job.
SubscriberIntakeandSubscriberConfirmname the jobs.¶ - No lint rule kept core free of adapters.
no-core-adaptersrejects HTTP-client and adapter/vendor imports from core, with failing-case tests.¶
Cartridges36 adds rat-stack’s own packaging and removal test, including infrastructure supplied through Layer.provide. A Layer as constructor12 explains the construction mechanism.¶
Sources
- Hexagonal architecture the original 2005 article. Alistair Cockburn. Original ports-and-adapters article; used for the inside/outside boundary. Accessed 2026-10-01.
- rat-stack/packages/core/src/interest-confirm-port.ts at main · joelhooks/rat-stack · GitHub. GitHub joelhooks/rat-stack. Confirmation port; used for the driven-side service boundary. Accessed 2026-10-01.
- rat-stack/packages/core/src/interest-mailer.ts at main · joelhooks/rat-stack · GitHub. GitHub joelhooks/rat-stack. Mail port; used for sending interest mail without choosing transport. Accessed 2026-10-01.
- rat-stack/packages/core/src/interest-intake.ts at main · joelhooks/rat-stack · GitHub. GitHub joelhooks/rat-stack. Intake port; used for subscriber intake independent of its adapter. Accessed 2026-10-01.
- rat-stack/packages/subscriber-delivery/src/delivery.ts at main · joelhooks/rat-stack · GitHub. GitHub joelhooks/rat-stack. Delivery composition; used for the HTTP adapters outside core. Accessed 2026-10-01.
- rat-stack/apps/site/src/worker.ts at main · joelhooks/rat-stack · GitHub. GitHub joelhooks/rat-stack. Worker composition; used for production adapter wiring. Accessed 2026-10-01.
Last changed 2026-10-10 in 978dccc. Source on GitHub. Change log.
Linked from
- A clean playground. rat-stack does real work with packages that stay easy to add and remove.
Interest signup keeps delivery in an adapter package outside core.
- Agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
Hexagonal architecture — Ports name the application’s jobs; adapters connect them to the outside world.
- Change log. What changed in the files served here, newest first.
Hexagonal architecture — edited: docs: point live docs, skills and Brain pages at apps/site
- Code snippets quote a pinned source. Shipped design brief: pinned Git objects, typed diagnostics, and one build-only snippet model for both views.
The package follows ports and adapters.¶
- Effect keeps the surfaces on one contract. Schema owns values, projections build interfaces, and Layers supply implementations.
Hexagonal architecture names the adapter boundary.
- Engine-neutral tokens keep adapters replaceable. The highlighter port exposes text, roles, and font styles rather than Shiki types.
This follows ports and adapters.¶
- Feature flags. Typed feature flags with owners, removal dates, and stable subject rollouts.
The Config adapter reads deployment configuration.
- Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
- HTTP success needs a status check and a decoder. Supply the client, check the response status, decode accepted data, and name failures at the adapter boundary.
Provider clients remain in adapters under hexagonal architecture.¶
- Interest signup. Agent-only applications start email confirmation through interfaces owned by core and delivery implemented in a separate package.
See hexagonal architecture.
- Learn mode presents concepts at useful depths. An agent presents source-derived concepts during real work and keeps learning events in a private local log.
Learn owns the FeedbackAuthor port.
- Learn the stack | rat-stack. Hands-on guides to Effect actions, XState lifecycles, and the seams between stack pieces.
Follow ports and adapters for provider boundaries and agent next actions for hypermedia guidance.
- learn-rat-stack. Trace a capability through Effect, XState, five projections, the CLI, and Alchemy. Try hosted search and read.
This follows hexagonal architecture: composition supplies the file-system dependency.¶
- One capability, every surface. A schema-typed contract and one handler feed every interface rat-stack keeps.
HATEOAS covers links that guide an agent’s next action; hexagonal architecture names the ports-and-adapters principle.¶
- Pin the source and report drift separately. A pinned excerpt stays fixed while a separate diagnostic compares it with HEAD.
The configured registry follows ports and adapters.¶
- Rat Stack lore | rat-stack. Short, source-grounded notes on the ideas and decisions behind rat-stack.
Hexagonal architecture — Ports name the application’s jobs; adapters connect them to the outside world.
- rat-stack. An Effect stack so pure (aspirational) Kit Langton will blush.
- Source change history (log.md). The generated change log as Markdown.
Hexagonal architecture — edited: docs: point live docs, skills and Brain pages at apps/site
- Structure an Effect codebase by domain. Start with folders for application work, services and Layers in the same file, and startup code that supplies implementations.
See hexagonal architecture.¶
Unlinked mentions (33)
- A clean playground → One-line infrastructure removal remains unproven for that adapter.¶
- add-a-store → An adapter implements those operations for a storage provider.¶
- Agent rules for rat-stack (AGENTS.md) → Core owns job-shaped ports; adapter packages implement them, and apps provide them at composition.
- Analytics → The events cartridge owns the CrashArchive port and its R2 adapter.
- Build and run rat-stack (README.md) → 0: Node-backed services; keep adapter and core pins matched.
- Capabilities → A downstream storage adapter owns its statement and row limits.¶
- Cartridges → ts picks Better Auth’s D1 or Hyperdrive adapter.¶
- Code snippets quote a pinned source → The adapter maps svx to Markdown and txt to text; it accepts javascript explicitly.¶
- Effect + Alchemy peer patterns → It is a separately published Alchemy package with provider subpaths, so rat-stack can use it without forking an adapter.
- Effect 4 study: September 2026 → Alchemy and its Better Auth adapter use beta.81.
- Effect basics → The Worker returns a fetch Effect to its Alchemy Worker adapter:¶
- Effect keeps the surfaces on one contract → Hexagonal architecture names the adapter boundary.
- Engine-neutral tokens keep adapters replaceable → The proposed Shiki adapter keeps Shiki’s token type inside the adapter.
- Feature flags → The memory adapter supplies rules and writable values for tests.¶
- Fence → An adapter implements an application-owned interface for a specific provider.¶
- Hosted agent interfaces → Its asset adapter adds a delay to make cold reads overlap.
- HTTP success needs a status check and a decoder → An adapter implements an application interface for a provider.¶
- Interest signup → packages/subscriber-delivery provides the adapter, the implementation that connects those interfaces to external delivery.
- keep-or-cut → ts, and the HTTP adapter test¶
- Layer composition makes dependencies explicit → The application chooses its workspace layout and adapter package boundaries.¶
- Learn mode presents concepts at useful depths → The command-line interface (CLI) and MCP tools use a local progress adapter, an implementation that connects learning operations to local files.
- learn-alchemy → sh as a redirect, and port 1337 for dev.¶
- One capability, every surface → Analytics shows a separate infrastructure cartridge; interest signup shows core ports with a delivery adapter outside core.
- One prompt serves people and agents → Core owns the PromptLibrary port, an interface for listing and reading prompts.¶
- Purpose and boundaries of rat-stack (VISION.md) → New code takes the rat-stack path: a shared contract, a job-shaped service port, a provider adapter outside core, and an outcome you can observe.
- rat-stack → Analytics is a running capture system; interest signup shows consent and confirmation across a delivery adapter.
- rat-stack-mode → md: choosing an adapter or testing its behavior.¶
- Run Effect at the integration boundary → The checked adapter exposes a small Promise API to a hypothetical foreign framework.
- Scopes release resources when work ends → The migration adapter opens a Postgres client inside Effect.tryPromise.
- ship → Adapter: the implementation that connects the release procedure to a deployment provider.¶
- Structure an Effect codebase by domain → An adapter implements an interface for a platform or provider.¶
- There is no ISR on Cloudflare → There is no SvelteKit isr switch for the Cloudflare adapter.
- uncomplect → Call the application’s port.