keiro is a Haskell framework for event sourcing and workflow orchestration on PostgreSQL. It composes a set of sibling libraries — an append-only event store (kiroku), a pure state-machine core (keiki), and supervised subscription workers (shibuya) — into a runtime that an application builds on and runs against its own Postgres database. There is no separate workflow server, no second replicated log, and no parallel storage path for "workflow state" versus "domain events": everything is journaled into one kiroku event log.
Warning
keiro is under active development. It is already used in production, but the public API is not yet stable and may change in breaking ways between releases.
経路 (keiro) means route or path — the way something travels from an origin to a destination. The name is literal: an event stream is the route an aggregate's history has taken, a subscription follows the route through the global log, a projection routes events into read models, and a process manager routes source events into commands for another stream.
This repository is a Cabal multi-package workspace. Each package lives in its
own subdirectory and is listed in cabal.project.
keiro unifies two engines over a single Postgres event log:
- an event-sourcing core built on keiki's symbolic-register state-machine
transducer (
SymTransducer). Aggregates decide commands into events; process managers and routers turn one category's events into another category's commands, with timers, retry counters, and correlation ids as typed register slots; projections fold events into read models — all with optimistic- concurrency appends and total, replay-safe folds. - a durable-execution engine (the
Workfloweffect). Write a long-running process as an ordinaryeffectfulcomputation; each namedstepjournals its result into a kiroku stream (wf:<name>-<id>), so replay reuses recorded results. An action that completed before its result was journaled can run again after a crash; external effects still need idempotency. Suspension primitives —sleep,awakeable(external signal), and child workflows — journal as ordinary step records, and a resume worker recovers in-flight runs. Replay is keyed by step name, not source position. Preserve names and result codecs for retained steps; usepatchfor changes to replayed control flow.
The two engines share one substrate — kiroku streams in your Postgres — so
domain events, process-manager state, and workflow journals sit on one timeline,
inspected with one query. See docs/why-keiro.md for the
motivation and an honest account of what keiro deliberately gives up.
- typed stream names, event codecs, schema versions, event-type validation, and
upcasters (
Keiro.Stream,Keiro.Codec,Keiro.EventStream); - a
ValidatedEventStreamboundary that rejects unrecoverable, ambiguous, or state-losing transducers before they can run commands; - the canonical command cycle — load, streaming replay, decide, append-batch
with optimistic concurrency — including a transactional step
(
runCommandWithSql) that appends events, updates inline projections, and writes outbox/timer rows in one Postgres transaction (Keiro.Command); - snapshot-assisted hydration with compatibility checks and full-replay fallback
while history is retained (
Keiro.Snapshot); - validated projection catalogs spanning query models, application-owned
targets, typed inline/async owners, and deterministic sources; plus
category-scoped strong reads and atomically fenced, fixed-head coordinated
rebuilds with resumable progress (
Keiro.ReadModel,Keiro.Projection,Keiro.Projection.Catalog); - guarded catalog commands that roll back the append and projection writes when an application-owned relational precondition refuses;
- event-sourced process managers, routers, and durable timers
(
Keiro.ProcessManager,Keiro.Router,Keiro.Timer); - a durable-execution runtime — named-step journaling, crash-safe replay and
resume, and
sleep/awakeable/ child-workflow suspension (Keiro.Workflowand submodules); - a transactional outbox / idempotent inbox with Kafka adapters
(
Keiro.Outbox,Keiro.Inbox); - durable rejected-dispatch records and idempotent subscription dead-letter
replay (
Keiro.DeadLetter); - a versioned typed
.keirotoolchain that selects an explicit released language contract before parsing, checks cross-node policy, scaffolds generated modules and create-once holes, emits harnesses, and gates persistence-aware evolution (keiro-dsl); - native dependency-ordered database migration components and the
keiro-migrateCLI (keiro-migrations,pg-migrate); - bounded aggregate, workflow, manager, timer, shard, and projection inspection
through
keiro-ops, plus optional HTTP and WebSocket feeds inkeiro-ops-http; - OpenTelemetry telemetry across every delivery and handler (
Keiro.Telemetry).
keiro is a framework, not a server. It builds on the author's sibling libraries:
- kiroku — PostgreSQL append-only event store with gap-free contiguous global positions;
- keiki — the pure
SymTransducerstate-machine core used by the event-sourcing side; - shibuya — subscription and worker supervision, with pgmq and Kafka adapters;
- pgmq-hs — the Postgres-native message
queue behind
keiro-pgmqwork queues;
and the wider ecosystem — hasql and effectful for database access and effect handling, and Streamly for streaming reads and worker loops.
The eight published packages below share the 0.22.0.0 release. jitsurei
is the repository's worked-example package. See Getting Started
for application dependencies and Deploy Ordering
before upgrading an existing database.
keiro/— the framework library (command cycle, snapshots, read models, projections, process managers, routers, timers, durable workflows, inbox/outbox, telemetry). Seekeiro/README.mdfor the full overview.keiro-core/— dependency-light contract modules (Keiro.Codec,Keiro.EventStream,Keiro.Integration.Event,Keiro.Prelude,Keiro.Snapshot.Policy,Keiro.Stream) shared by the other packages.keiro-pgmq/— PostgreSQL job-queue (PGMQ) integration: a reusable Postgres-backed work queue built onpgmq-hsand shibuya's pgmq adapter.keiro-dsl/— typed-specification (.keiro) toolchain for aggregates, process managers, routers, integration, queues, read models, and durable workflows: language inspection / parse / check / scaffold / harness / diff.keiro-migrations/— nativepg-migratecomponent and CLI for the Kiroku and Keiro PostgreSQL schemas, plus verified legacy-Codd import evidence.keiro-ops/— schema-checked operational CLI and embeddable command tree for inspection, safe preview/--forcerepair, stable JSON, workflow/timer hooks, replay audits, and typed catalog rebuilds.keiro-ops-http/— opt-in HTTP operations, shared WebSocket first-page feeds, one-listener composition, and preview/confirm mutations.keiro-test-support/— shared PostgreSQL test fixtures for the test suites.jitsurei/— guide-backed, runnable worked examples, including one-catalog live/async application and a mixed clear/preserve rebuild with fencing and resume, that depend onkeiro.
Use the project's Nix development shell. It supplies GHC 9.12.4, PostgreSQL 18, Z3, and the repository verification tools:
nix develop
z3 --version
cabal build all --enable-tests --enable-benchmarks
cabal test all --test-show-details=direct
just user-documentation-validateThe tests create ephemeral PostgreSQL databases. For the full repository gate,
run nix develop -c just verify. Its demo run creates and removes a private
database; it preserves the interactive JITSUREI_DATABASE.
To run the worked examples interactively from the shell:
just jitsureiUse JITSUREI_DATABASE=keiro_inspection_demo just jitsurei for a fresh demo
database when testing a changed unreleased migration. See
Run And Operate Jitsurei for the
individual demos and embedded operations commands.
- User-facing documentation starts at
docs/user/README.md. - The DSL reference covers stable Language 5 and candidate Language 6 at
docs/user/keiro-dsl-reference.md. - Migration setup and operations start at
docs/user/migrations.md. - Long-form, guide-backed examples start at
docs/guides/README.mdand use thejitsureipackage as their executable source. - Operations transports: HTTP, WebSocket feeds, and composition.
- Motivation and comparison to adjacent systems:
docs/why-keiro.md. - Profile-governed design research starts at
docs/research/index.md; implementation plans live underdocs/masterplans/anddocs/plans/.
The event-sourcing core, hardened replay validation, snapshots, fenced read
models/projections, process managers, routers, timers, transactional messaging,
dead-letter tooling, named-step durable execution, typed-spec scaffolding, and
native migrations are implemented — production-shaped for controlled early
use, not yet a 1.0. keiro is Haskell-only and single-region Postgres by design;
async delivery remains at-least-once, with transactional projection deduplication
while receipts are retained. Language 6 ships as a candidate in the released
toolchain; it has not acquired a stable language compatibility contract.
Languages 1–4 are deprecated, and Languages 1–5 plus legacy positional managers
are scheduled to retire before 1.0. See
docs/user/production-status.md.
BSD-3-Clause.