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:failed become a fixed set (route:exchange:failed) with routeId in details. Wildcard patterns on ctx.on() / ctx.once() are replaced by exact names, the "*" catch-all, and the forRoute() filter helper (the event() source adapter keeps its pattern support); ecosystem packages declare events by merging into EventDetailsMap. plugin:registered is removed (it duplicated plugin:starting). See the migration guide.
  • Subscription source contract -- source adapters receive a single Subscription object ({ context, signal, meta, ready(), complete(), emit() }) instead of five positional parameters. .from() additionally accepts async generator functions and (async) iterables, and @routecraft/testing adds a testSubscription() helper. See the migration guide.
  • StepOutcome step contract -- custom Step implementations 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 shared Step instance. Custom aggregators return { body, headers? } instead of a fabricated Exchange. See the migration guide.
  • Namespaced error-code registry -- ecosystem packages own codes under a claimed namespace via registerErrorCodes() plus ErrorCodeRegistry declaration merging; RC is reserved for core. Adds RC1003 (error-code registration failed). See the migration guide.
  • Type-enforced builder positioning -- craft() returns a pre-from builder, so pipeline operations before .from() are compile errors; builder generics move to a state bag (RouteBuilder<{ body: T }>, AnyRouteBuilder for lists). See the migration guide.
  • Splitters return child bodies -- .split() callbacks return values (or splitChild(body, headers) for per-child header overrides) instead of hand-built Exchange instances; the framework owns child construction. See the migration guide.
  • Consumer SPI -- Consumer.register receives the Message envelope and consumer classes construct from one ConsumerDeps bag; Message, ProcessingQueue, ConsumerType, and ConsumerDeps are exported. See the migration guide.
  • Per-adapter header key objects -- HeadersKeys keeps framework keys only; adapter keys move to TimerHeaders / CronHeaders / FileHeaders / CsvHeaders / JsonlHeaders / MailHeaders / CarddavHeaders; HEADER_MAIL_* / HEADER_CARDDAV_* and HeaderKeysRegistry are removed (wire keys unchanged). .header() rejects every engine-owned routecraft.* key up front. See the migration guide.
  • client.sendDirect and public capability discovery -- CraftClient.send is renamed sendDirect (response generic defaults to unknown); context.capabilities() replaces reads of the internal direct registry, and ADAPTER_DIRECT_REGISTRY / getDirectChannel / sanitizeEndpoint are no longer exported. See the migration guide.
  • Naming sweeps -- CardDAV* exports become Carddav* (acronym casing per the Http precedent), the carddav option types adopt the two-sided Server/Client naming (CarddavServerOptions for the read role, CarddavClientOptions for writes and deletes), and jsonl's three file option types fold into one JsonlFileOptions. See the migration guide.
  • choice() variadic surface; BranchBuilder renamed, ChoiceSubBuilder removed -- the fluent callback .choice(c => c.when(p, fn).otherwise(fn)) becomes variadic .choice(when(p, fn), ..., otherwise(fn)) with standalone when / otherwise helpers imported from @routecraft/routecraft, the path surface now shared with the new multicast. BranchBuilder is renamed PathBuilder; ChoiceSubBuilder is gone. See the migration guide.

Core

  • Recovery directives -- .error() handlers may return recovery.drop(reason?) (discard the failing exchange) or recovery.rethrow() (decline recovery) instead of a recovery body or a manual throw.
  • Open error and principal models -- rcError accepts a per-occurrence retryable override; RCMeta.category and Principal.kind accept ecosystem-defined strings alongside the known values.
  • Plugin identity and lifecycle -- plugins may declare name (used as pluginId on events and logs) and reserve dependsOn; registerTeardown callbacks unwind LIFO; getRoutes() returns a copy.
  • route:source:failed lifecycle event -- fires when a source subscription rejects (the source gave up producing), with { routeId, route, adapter?, error }. Unlike route:stopping it 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 / RC5027 become AI1001 / AI1002 / AI1003 under the new AI namespace; update any code or alerting that matches on error.rc.

  • Agent blocks replace skills -- AgentOptions.skills and agentPlugin({ skills }) are removed in favour of a blocks record that unifies skills, memory, identity, and instructions, with progressive disclosure now the default. See the migration guide.

  • skills({ source }) and fromFile(path) builders -- skills now returns a blocks record to spread into blocks: { ... }; fromFile reads a UTF-8 file at resolution time.

  • Nested block groups -- a blocks value can be a single block or a nested blocks group, so skills({ source }) can stay grouped under one key (blocks: { skills: await skills(...) }) instead of being spread flat. Groups flatten to group__leaf names. See the migration guide.

  • Tag selectors on tools() removed -- the { tagged } / { tagged, from } variants and the tags override on directTool are gone. Use the new tools((catalog) => [...]) builder form for dynamic selection.

  • Block-loader calls partitioned out of toolCalls -- progressive loads surface on AgentResult.blocksLoaded and emit agent:block:* events instead of agent:tool:*.

  • skills: frontmatter on agents() rejected -- supply blocks through 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 -- CraftContext delegates events to an internal EventBus; adapter config keys (cron, direct, mail, telemetry, http) move to per-module config appliers; the route engine splits into pipeline/ modules (executor, validation, synthetic steps). Two behavioural notes: context store seeding for adapter config now happens in initPlugins() (called automatically by start()), and plugin teardown (including registerTeardown callbacks) drains in reverse order.
  • Uniform factory tagging -- every public adapter factory is tagged for mockAdapter(), enforced by a conformance test; previously direct, simple, timer, cron, log, noop, and others (plus two transformer-mode branches of html() / json()) were silently unmockable.

Adapters

  • HTTP source Breaking -- http() is now a two-sided adapter. http({ path, method? }) exposes a route over HTTP via defineConfig({ http: { port, host, auth } }); Bun runtimes bind through Bun.serve and Node 22+ uses a zero-dependency node:http shim. Global auth accepts jwt() / jwks() bearer or apiKey({...}); per-route constraints reuse .authorize({...}). Per-route auth handling has three modes via http({ 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.json endpoints register automatically. Each is configured via the uniform http: { builtins: { health, ready, openapi } } block with { enabled, requireAuth } per endpoint (Spring-Actuator-inspired). Defaults gate the routes count on /ready from anonymous callers (requireAuth: true) and keep /openapi.json public (requireAuth: false, matching the Stripe / GitHub / Twilio convention). Request bodies are parsed by Content-Type (JSON / text / urlencoded / multipart), capped by maxBodySize. Adds error codes RC5018 (request rejected) and RC5019 (server bind failed). Breaking: the destination option type HttpOptions<T> is renamed HttpClientOptions<T> (the source uses HttpServerOptions); 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(), and html() gain mode: '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 HTTP GET; dynamic function paths are supported) and mode: 'delete' (idempotent file removal that passes the body through unchanged). Adds the JsonReadAdapter, CsvReadAdapter, JsonlReadAdapter, HtmlReadAdapter, and FileReadAdapter types.
  • CSV and JSONL decode transformers -- calling csv() or jsonl() with no path now returns a transformer that parses a CSV / JSONL string already in the body (for example an http() response), matching the existing json() and html() decode transformers. Adds CsvTransformerOptions, CsvFileOptions, and JsonlTransformerOptions; csv()'s path is now optional. A dynamic (function) path used as a destination now works for html() too, where it previously threw at construction.

Mail

  • Mail source envelope moves to headers Breaking -- .from(mail(...)) now follows the payload-on-body, envelope-on-headers convention shared with the HTTP source. The exchange body is a MailBody ({ text?, html?, attachments? }) and the envelope (from, to, cc, bcc, subject, date, messageId, replyTo, flags, sender, rawHeaders) lands on routecraft.mail.* headers, declaration-merged into RoutecraftHeaders and exported on the MailHeaders key object. .input({ body }) now validates against the message content alone. The fetch destination (.enrich(mail(...))) still returns MailMessage[] unchanged. New exported type MailBody. 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 stays direct / verified instead of unverified. 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? } | false option on MailServerOptions (defaults match the old hardcoded 30 / 1s / 60s; maxAttempts: Infinity never gives up; false fails fast). Because the initial connect retries, the source signals readiness before the first connection succeeds, so route:started no longer guarantees the mailbox was reachable. New exported type MailReconnectOptions. When any source gives up for good, the new core route:source:failed event 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 Exchange is frozen with explicit copy-on-write; state is unified on { body, headers }.
  • .authorize() route-entry guard -- a route-only authorization validator that replaces requirePrincipal and raises RC5020 when a credential expires mid-run.
  • Field-shaping helpers keep and mask -- two .transform() helpers: keep is grant-based, fail-closed allowlisting; mask obfuscates values regardless of caller.
  • Choice operation -- a conditional routing primitive with transform() and enrich() 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.agents is a record (no defineAgent), and system / user accept 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 userinfo enrichment -- 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 by userinfo enrichment; the token-level mappers remain.
  • New error codes RC5020-RC5022 -- token expired during processing, principal enrichment failed, and userinfo sub invariant violated.

Adapters

  • Adapter mocking -- mockAdapter swaps any tagged adapter in tests; the file, csv, json, jsonl, and html factories 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 MailMessage body, and a verify-sender option.
  • Optional peer loader everywhere -- every optional-peer import now routes through loadOptionalPeer and emits RC5017 with an install hint.

Telemetry Breaking

  • Bun-only SQLite sink -- the built-in telemetry sink uses bun:sqlite; better-sqlite3 is 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 craft CLI -- the published binary now requires Bun >= 1.1.0.
  • Bun monorepo -- installs, scripts, and lockfile migrate from pnpm to Bun.
  • create-routecraft refactor -- scaffolder extracted into a library with expanded test coverage.
  • bun:test everywhere -- 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 -- log and debug documented; map and schema clarified.
  • 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 -- cron and direct adapters 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/testing for 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/testing package -- 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/ai package -- 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

  • direct adapter validation -- improved validation and error messages for inter-capability communication.
  • aggregate operation -- default aggregator now flattens arrays and combines scalars automatically.
  • batch operation -- new ESLint rule (batch-before-from) enforces correct batch positioning at the route level.
  • pseudo adapter -- 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.local support -- environment variables in .env.local are 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 run and craft watch commands.
  • create-routecraft -- project scaffolding tool.
  • ESLint plugin -- require-named-route rule out of the box.
  • Test utilities -- @routecraft/testing package with testContext and spy adapter.
Previous
Installation