AI coding assistants are at their best when the task is narrow, typed, and verifiable, and at
their worst when they have to guess at an architecture, invent interfaces, or reverse-engineer how
the pieces fit. Missive.js happens to be built out of exactly the primitives that keep an assistant
on the rails: a contract describes what a message looks like, an intent is fully typed, and your
business logic lives behind small, explicit dependency seams.
In other words: you (or the assistant) declare the shape, and the compiler holds everyone — including
the AI — to it.
A CommandHandlerDefinition / QueryHandlerDefinition / EventHandlerDefinition is a precise,
typed description of one message. Once it exists, the types of register, createCommand,
dispatch and the handler itself are all derived from it. An implementation that drifts from
the spec simply fails to compile.
Typed seams, not guesswork
Handlers receive their dependencies through a plain Deps type and the message through a typed
Envelope. The assistant writes pure logic against a fixed interface — it never has to invent
how to reach the database or where to wire things.
Adapters are tiny interfaces
Need Redis caching or a distributed lock? That is a 2–3 method interface (CacherAdapter,
LockAdapter). “Implement this adapter” is an unambiguous, individually testable task — the
ideal unit of work to delegate.
Cross-cutting concerns stay out of the way
Validation, caching, logging, retries and the rest are middleware. Business logic stays clean,
so the assistant only ever touches the handler body and its contract.
A Missive.js feature is a vertical slice: a single file holding the schema, the derived types,
the contract, the handler, and a factory that injects dependencies. That slice is the perfect
hand-off boundary for an assistant.
Write the contract first. Define the input schema and let the result type be inferred from the
handler, so the two can never disagree.
Hand the assistant the envelope type and the Deps interface, and ask for the handler. Because
the input and result are fixed by the contract, a wrong implementation will not type-check.
Wire it in the composition root. Register the factory with the real dependencies and attach
runtime validation through the validator middleware (validation is a middleware, not an argument
to register).
const { result } = await commandBus.dispatch(intent);
For infrastructure, ask for an adapter. “Write a Redis CacherAdapter” is a small, contract-bound
task: implement get(key) and set(key, value, ttl), then pass it to useCacherMiddleware. Build
against the in-memory default first, swap the adapter later — no other code changes.
This repository ships a Claude Code / Agent skill — using-missive-js — that teaches an
assistant the mental model, the golden-path recipe above, the full middleware catalog, and the
correctness rules that prevent plausible-but-wrong code (for example: register takes no schema
argument; the cacher’s TTL is in seconds while the lock’s is in milliseconds). Point your assistant
at it and the patterns on this page become its default behavior.
This drops the skill into .claude/skills/, and your agent picks it up automatically on its next
session. The source lives under skills/using-missive-js
in the repository, with deep-dive references for contracts, middlewares, adapters, and project
structure.