Getting Started
Changelog
All notable changes to Routecraft.
Routecraft is in active development -- APIs may change between minor versions.
v0.6.0 In development
This section tracks changes landing on main since the v0.5.0 release; release notes will be finalised when v0.6.0 is tagged. 0.6.0 is the architecture release before v1: the contracts that freeze at v1 changed shape once, now, so they do not have to change after, and the engine rework brings a significant performance improvement to route and event processing. See the 0.5.x to 0.6.0 migration guide for all upgrade steps.
Core Breaking
- Fixed event names; identity in the payload -- hierarchical names like
route:<id>:exchange:failedbecome a fixed set (route:exchange:failed) withrouteIdindetails. Wildcard patterns onctx.on()/ctx.once()are replaced by exact names, the"*"catch-all, and theforRoute()filter helper (theevent()source adapter keeps its pattern support); ecosystem packages declare events by merging intoEventDetailsMap.plugin:registeredis removed (it duplicatedplugin:starting). See the migration guide. Subscriptionsource contract -- source adapters receive a singleSubscriptionobject ({ context, signal, meta, ready(), complete(), emit() }) instead of five positional parameters..from()additionally accepts async generator functions and (async) iterables, and@routecraft/testingadds atestSubscription()helper. See the migration guide.StepOutcomestep contract -- customStepimplementations return what happened (continue/complete/drop/branch/fanOut) and the executor owns all scheduling; the wrapper buffer/relay protocol is gone. Per-execution metadata rides the outcome instead of mutating the sharedStepinstance. Custom aggregators return{ body, headers? }instead of a fabricatedExchange. See the migration guide.- Namespaced error-code registry -- ecosystem packages own codes under a claimed namespace via
registerErrorCodes()plusErrorCodeRegistrydeclaration merging;RCis reserved for core. AddsRC1003(error-code registration failed). See the migration guide. - Type-enforced builder positioning --
craft()returns a pre-frombuilder, so pipeline operations before.from()are compile errors; builder generics move to a state bag (RouteBuilder<{ body: T }>,AnyRouteBuilderfor lists). See the migration guide. - Splitters return child bodies --
.split()callbacks return values (orsplitChild(body, headers)for per-child header overrides) instead of hand-builtExchangeinstances; the framework owns child construction. See the migration guide. - Consumer SPI --
Consumer.registerreceives theMessageenvelope and consumer classes construct from oneConsumerDepsbag;Message,ProcessingQueue,ConsumerType, andConsumerDepsare exported. See the migration guide. - Per-adapter header key objects --
HeadersKeyskeeps framework keys only; adapter keys move toTimerHeaders/CronHeaders/FileHeaders/CsvHeaders/JsonlHeaders/MailHeaders/CarddavHeaders;HEADER_MAIL_*/HEADER_CARDDAV_*andHeaderKeysRegistryare removed (wire keys unchanged)..header()rejects every engine-ownedroutecraft.*key up front. See the migration guide. client.sendDirectand public capability discovery --CraftClient.sendis renamedsendDirect(response generic defaults tounknown);context.capabilities()replaces reads of the internal direct registry, andADAPTER_DIRECT_REGISTRY/getDirectChannel/sanitizeEndpointare no longer exported. See the migration guide.- Naming sweeps --
CardDAV*exports becomeCarddav*(acronym casing per theHttpprecedent), the carddav option types adopt the two-sided Server/Client naming (CarddavServerOptionsfor the read role,CarddavClientOptionsfor writes and deletes), and jsonl's three file option types fold into oneJsonlFileOptions. See the migration guide. choice()variadic surface;BranchBuilderrenamed,ChoiceSubBuilderremoved -- the fluent callback.choice(c => c.when(p, fn).otherwise(fn))becomes variadic.choice(when(p, fn), ..., otherwise(fn))with standalonewhen/otherwisehelpers imported from@routecraft/routecraft, the path surface now shared with the newmulticast.BranchBuilderis renamedPathBuilder;ChoiceSubBuilderis gone. See the migration guide.
Core
- Recovery directives --
.error()handlers may returnrecovery.drop(reason?)(discard the failing exchange) orrecovery.rethrow()(decline recovery) instead of a recovery body or a manual throw. - Open error and principal models --
rcErroraccepts a per-occurrenceretryableoverride;RCMeta.categoryandPrincipal.kindaccept ecosystem-defined strings alongside the known values. - Plugin identity and lifecycle -- plugins may declare
name(used aspluginIdon events and logs) and reservedependsOn;registerTeardowncallbacks unwind LIFO;getRoutes()returns a copy. route:source:failedlifecycle event -- fires when a source subscription rejects (the source gave up producing), with{ routeId, route, adapter?, error }. Unlikeroute:stoppingit never fires for an orderly shutdown, so it is the signal to alarm on for a dead channel.
AI & MCP Breaking
AI error codes renamed --
RC5025/RC5026/RC5027becomeAI1001/AI1002/AI1003under the newAInamespace; update any code or alerting that matches onerror.rc.Agent blocks replace skills --
AgentOptions.skillsandagentPlugin({ skills })are removed in favour of ablocksrecord that unifies skills, memory, identity, and instructions, with progressive disclosure now the default. See the migration guide.skills({ source })andfromFile(path)builders --skillsnow returns ablocksrecord to spread intoblocks: { ... };fromFilereads a UTF-8 file at resolution time.Nested block groups -- a
blocksvalue can be a single block or a nestedblocksgroup, soskills({ source })can stay grouped under one key (blocks: { skills: await skills(...) }) instead of being spread flat. Groups flatten togroup__leafnames. See the migration guide.Tag selectors on
tools()removed -- the{ tagged }/{ tagged, from }variants and thetagsoverride ondirectToolare gone. Use the newtools((catalog) => [...])builder form for dynamic selection.Block-loader calls partitioned out of
toolCalls-- progressive loads surface onAgentResult.blocksLoadedand emitagent:block:*events instead ofagent:tool:*.skills:frontmatter onagents()rejected -- supplyblocksthrough the per-agent overrides map instead.New error codes
AI1001-AI1003-- block resolution failure, name collision / reserved_block_prefix, and block misconfiguration.
Internals
- Engine restructuring --
CraftContextdelegates events to an internalEventBus; adapter config keys (cron,direct,mail,telemetry,http) move to per-module config appliers; the route engine splits intopipeline/modules (executor, validation, synthetic steps). Two behavioural notes: context store seeding for adapter config now happens ininitPlugins()(called automatically bystart()), and plugin teardown (includingregisterTeardowncallbacks) drains in reverse order. - Uniform factory tagging -- every public adapter factory is tagged for
mockAdapter(), enforced by a conformance test; previouslydirect,simple,timer,cron,log,noop, and others (plus two transformer-mode branches ofhtml()/json()) were silently unmockable.
Adapters
- HTTP source Breaking --
http()is now a two-sided adapter.http({ path, method? })exposes a route over HTTP viadefineConfig({ http: { port, host, auth } }); Bun runtimes bind throughBun.serveand Node 22+ uses a zero-dependencynode:httpshim. Global auth acceptsjwt()/jwks()bearer orapiKey({...}); per-route constraints reuse.authorize({...}). Per-route auth handling has three modes viahttp({ auth: "required" | "optional" | "skip" }): secure-by-default"required","optional"(admit anonymously, attach principal when a valid credential is present, reject invalid credentials), and"skip"(bypass the middleware entirely for truly identity-free routes like RSS or probes). Built-in/health,/ready, and/openapi.jsonendpoints register automatically. Each is configured via the uniformhttp: { builtins: { health, ready, openapi } }block with{ enabled, requireAuth }per endpoint (Spring-Actuator-inspired). Defaults gate theroutescount on/readyfrom anonymous callers (requireAuth: true) and keep/openapi.jsonpublic (requireAuth: false, matching the Stripe / GitHub / Twilio convention). Request bodies are parsed byContent-Type(JSON / text / urlencoded / multipart), capped bymaxBodySize. Adds error codesRC5018(request rejected) andRC5019(server bind failed). Breaking: the destination option typeHttpOptions<T>is renamedHttpClientOptions<T>(the source usesHttpServerOptions); a type-only change with no runtime impact. See the 0.5.x to 0.6.0 migration guide. - Codec read and delete modes --
file(),json(),csv(),jsonl(), andhtml()gainmode: 'read'as a destination (reads and parses, or extracts, the file mid-route and returns the value, so.enrich()/.to()can pull it in like an HTTPGET; dynamic function paths are supported) andmode: 'delete'(idempotent file removal that passes the body through unchanged). Adds theJsonReadAdapter,CsvReadAdapter,JsonlReadAdapter,HtmlReadAdapter, andFileReadAdaptertypes. - CSV and JSONL decode transformers -- calling
csv()orjsonl()with nopathnow returns a transformer that parses a CSV / JSONL string already in the body (for example anhttp()response), matching the existingjson()andhtml()decode transformers. AddsCsvTransformerOptions,CsvFileOptions, andJsonlTransformerOptions;csv()'spathis now optional. A dynamic (function) path used as a destination now works forhtml()too, where it previously threw at construction.
- Mail source envelope moves to headers Breaking --
.from(mail(...))now follows the payload-on-body, envelope-on-headersconvention shared with the HTTP source. The exchangebodyis aMailBody({ text?, html?, attachments? }) and the envelope (from,to,cc,bcc,subject,date,messageId,replyTo,flags,sender,rawHeaders) lands onroutecraft.mail.*headers, declaration-merged intoRoutecraftHeadersand exported on theMailHeaderskey object..input({ body })now validates against the message content alone. The fetch destination (.enrich(mail(...))) still returnsMailMessage[]unchanged. New exported typeMailBody. See the 0.5.x to 0.6.0 migration guide. - Direct mail no longer misclassified as auto-forwarded -- a single first-hop ARC seal (
i=1,cv=none) added by the delivering MX is no longer read as forwarding, so DMARC-aligned direct mail staysdirect/verifiedinstead ofunverified. Mailing-list and validated-forward classification are unchanged. - Connection recovery covers every failure path, and is configurable -- IDLE-mode fetch failures and the initial connect at route start now go through the same reconnect-with-backoff loop as IDLE drops and poll fetch failures (previously they killed the route), and the folder is drained right after a reconnect so mail that arrived during an outage is delivered immediately. New
reconnect: { maxAttempts?, baseDelayMs?, maxDelayMs? } | falseoption onMailServerOptions(defaults match the old hardcoded 30 / 1s / 60s;maxAttempts: Infinitynever gives up;falsefails fast). Because the initial connect retries, the source signals readiness before the first connection succeeds, soroute:startedno longer guarantees the mailbox was reachable. New exported typeMailReconnectOptions. When any source gives up for good, the new coreroute:source:failedevent fires with{ routeId, route, adapter?, error }so a dead channel can be alarmed on (#425).
Docs site
- Blog at /blog -- Markdoc-backed posts with a featured + latest layout.
- Cheat sheet at /cheat-sheet -- searchable single-page DSL reference, print-to-PDF friendly.
- 0.5.x to 0.6.0 migration guide -- upgrade steps for the breaking AI changes above.
v0.5.0 Pre-release
May 2026
Several breaking changes across the core, AI, mail, telemetry, logger, and CLI surfaces. See the 0.4.x to 0.5.0 migration guide for the full public-API diff and step-by-step upgrade notes.
Core
- Dual-mode wrapper pattern --
.error()becomes a route-level wrapper rather than a top-level method, and source-level parse errors flow through the same handler. - Immutable Exchange -- the
Exchangeis frozen with explicit copy-on-write; state is unified on{ body, headers }. .authorize()route-entry guard -- a route-only authorization validator that replacesrequirePrincipaland raisesRC5020when a credential expires mid-run.- Field-shaping helpers
keepandmask-- two.transform()helpers:keepis grant-based, fail-closed allowlisting;maskobfuscates values regardless of caller. - Choice operation -- a conditional routing primitive with
transform()andenrich()on branch builders. - Discovery metadata on the route builder -- route id, description, and validation move from source options to the builder.
AI & MCP Breaking
- Agent runtime -- tool-calling loop, streaming via
onEvent/onDelta, agent destination, and per-binding tool description overrides. tools()DSL -- declarative tool registration, selection, and resolution.- Agent configuration overhaul --
agentPlugin.agentsis a record (nodefineAgent), andsystem/useraccept a string or function. See the migration guide. - MCP OAuth 2.1 server -- OAuth 2.1 provider with principal hierarchy, plus a general MCP HTTP auth surface and tool annotations.
- MCP protected-resource metadata -- resource identity moves to
mcpPlugin({ title, resource }); both validator and OAuth-proxy modes auto-mount RFC 9728 metadata. Field-by-field moves are in the migration guide. - Plugin-level
userinfoenrichment --mcpPlugin({ userinfo })hydrates the principal after verification, enabling the WorkOS AuthKit pattern. Lives on the plugin, orthogonal to the auth mode. ClaimMappers.{email,name,roles}removed -- superseded byuserinfoenrichment; the token-level mappers remain.- New error codes
RC5020-RC5022-- token expired during processing, principal enrichment failed, and userinfosubinvariant violated.
Adapters
- Adapter mocking --
mockAdapterswaps any tagged adapter in tests; thefile,csv,json,jsonl, andhtmlfactories are tagged out of the box. direct<TIn, TOut>()distinct types -- a route can accept one body shape and emit another.- Mail (IMAP) reliability -- reconnect on transient fetch failures, a reshaped
MailMessagebody, and a verify-sender option. - Optional peer loader everywhere -- every optional-peer import now routes through
loadOptionalPeerand emitsRC5017with an install hint.
Telemetry Breaking
- Bun-only SQLite sink -- the built-in telemetry sink uses
bun:sqlite;better-sqlite3is removed. Node deployments that relied on it must bring their own sink.
Logger
- stdout default -- the logger writes to stdout instead of stderr.
CLI & Tooling
- Bun-only
craftCLI -- the published binary now requires Bun >= 1.1.0. - Bun monorepo -- installs, scripts, and lockfile migrate from pnpm to Bun.
create-routecraftrefactor -- scaffolder extracted into a library with expanded test coverage.bun:testeverywhere -- the internal suite migrates off vitest, retained only for the cross-runtime tests.
Docs
- Migration guide -- new 0.4.x to 0.5.0 migration guide.
- Canary docs at
/next/-- canary builds deploy alongside the stable build at the root. - Operator reference --
loganddebugdocumented;mapandschemaclarified. - Claude Code skills -- Agent Skills for authoring adapters and capabilities bundled at the repo root.
v0.4.0 Pre-release
March 2026
Adapters
- Cron source -- new adapter for scheduling capabilities with cron expressions.
- JSONL adapter and chunked mode -- read and write line-delimited JSON with chunked streaming for large files.
- Modular adapter structure -- adapters refactored into a consistent file layout with a unified DSL registration system.
- Merged options --
cronanddirectadapters now support merged options across config and route.
AI & MCP
- stdio MCP client -- spawn and manage stdio-based MCP servers with a unified tool registry.
- Bearer token authentication -- secure MCP HTTP transport with bearer tokens.
Framework
- Terminal UI -- new TUI for inspecting running contexts and routes.
- Reduced public API surface -- internal-only exports are no longer published, tightening the long-term API contract.
TypeScript
- Declaration-merging registries -- compile-time adapter safety via type registries that adapter packages can extend.
Testing
- Spy adapter assertions -- richer assertion helpers in
@routecraft/testingfor spying on capability output.
Docs
- Light mode -- hero section and syntax highlighting now respect light mode.
- Copy-to-clipboard -- code blocks gain a copy button.
- Community resources -- new section linking external content and contributors.
- Dark-mode contrast -- prose strong text is more readable on dark backgrounds.
v0.3.0 Pre-release
March 2026
Adapters
- Agent, embedding, and LLM adapters -- new adapters for integrating AI agent workflows, embedding models, and large language models directly into capabilities.
- HTTP adapter -- first-class HTTP source and destination support.
- Browser and HTML adapters -- interact with web pages and parse HTML content.
- JSON adapter -- dedicated adapter for JSON data sources.
- Grouping adapter -- group messages by key before forwarding.
- File adapter -- read and write text, JSON, and CSV files with a unified adapter.
AI & MCP
@routecraft/testingpackage -- expanded testing utilities with MCP integration support.- Consistent adapter pattern -- all adapters now follow a unified pattern for configuration, lifecycle, and error handling.
Events
- Hierarchical event model -- new operation-level events with parent-child relationships, enabling fine-grained observability across capability execution.
TypeScript
- TypeScript support -- author capabilities in TypeScript with full type inference and compile-time validation.
Docs
- Capability-centric terminology -- all documentation renamed from "routes" to "capabilities" for consistency.
- Advanced guides -- new documentation covering advanced patterns, capability composition, and adapter authoring.
v0.2.0 Pre-release
February 2026
AI & MCP
- New
@routecraft/aipackage -- MCP integration with full schema validation via Zod. Expose any capability as an MCP tool for Claude Desktop, Cursor, and other MCP clients. - MCP server support -- run your capabilities as an MCP server with a single CLI command.
- MCP client support -- call external MCP servers from within a capability using the
mcpPlugin.
Adapters & Operations
directadapter validation -- improved validation and error messages for inter-capability communication.aggregateoperation -- default aggregator now flattens arrays and combines scalars automatically.batchoperation -- new ESLint rule (batch-before-from) enforces correct batch positioning at the route level.pseudoadapter -- new adapter for stubbing sources and destinations in tests and local development.
Framework
- Cross-instance identity -- supports multiple package copies and
npx-based installs resolving to the same context identity. - Logging configuration -- enhanced logging setup with more control over levels and output format.
v0.1.1 Pre-release
November 2025
Quality-of-life improvements.
Adapters
- Custom log messages -- adapters and operations now support custom log message overrides.
- Fetch adapter -- automatically parses JSON responses, no manual parsing needed.
Framework
.env.localsupport -- environment variables in.env.localare loaded automatically alongside.env.
Tooling
create-routecraft-- project scaffolding now supports example selection and template file configuration.- CodeSandbox -- added online playground link in the installation docs for zero-install experimentation.
v0.1.0 Pre-release
October 2025
Initial release.
Framework
- Fluent DSL --
craft().from().to()builder syntax for authoring capabilities. - Core operations --
transform,filter,enrich,aggregate,split,validate,tap,process,header, and more. - Backpressure -- simple and batch consumers with built-in backpressure support.
- CraftContext -- route lifecycle management with hot reload in development.
- Error handling -- structured RC error codes with Pino logging.
Adapters
- Built-in adapters --
simple,timer,direct,log,noop,fetch.
Tooling
- CLI --
craft runandcraft watchcommands. create-routecraft-- project scaffolding tool.- ESLint plugin --
require-named-routerule out of the box. - Test utilities --
@routecraft/testingpackage withtestContextandspyadapter.