Forge event-driven services in Go.
Crucible is a multi-module Go toolkit for building event-driven services. Its design philosophy is thin seams, no-op defaults, no forced dependencies: every cross-cutting concern (logging, tracing, metrics, IDs, time) is a small, consumer-providable interface with a do-nothing default. You bring your logger, your tracer, your clock. Crucible never makes you adopt its choices, and never leaks a third-party type into a public signature.
The state engine is the extreme end of this: stdlib-only, with no injected
IO at all. The IO modules carry the heavier seams via injection, but follow the
same rule. Defaults are no-ops, nothing third-party is forced on the consumer.
Guides, concepts, the food-delivery example, and the generated API reference live in the documentation site:
Each module is independently versioned (per-module SemVer) and carries its own stability label.
| Module | What it is | Status |
|---|---|---|
state |
Full-featured, domain-agnostic statechart engine. Stdlib-only, no IO. | experimental |
state/analysis |
Static model-checking and path enumeration over a machine's IR. | experimental |
state/evolution |
Diffs two machine definitions and classifies the SemVer bump. | experimental |
state/conformance |
Reusable harness for driving golden scenarios against a machine. | experimental |
state/expr |
Rich expression tier: CEL-backed guards type-checked against the context schema. | experimental |
telemetry |
Vendor-neutral tracing/metrics interface for the IO modules. Stdlib-only. | experimental |
telemetry/slog |
log/slog adapter for the telemetry interface. |
experimental |
telemetry/otel |
OpenTelemetry adapter for the telemetry interface. | experimental |
telemetry/datadog |
Datadog adapter for the telemetry interface. | experimental |
broker |
Message broker seam: publish/subscribe transport with injected adapters. | planned |
sink |
Egress seam: fan emitted effects out to many destinations, fire-and-forget. | experimental |
source |
Ingress seam: consume streams and drive statecharts; ack on durable transition. | experimental |
source/kafka |
Kafka/RedPanda Inlet over franz-go: group consumer, mark-commit-after-process. | experimental |
source/jetstream |
NATS JetStream Inlet over nats.go: pull consumer, ack/nak/term, MaxAckPending. | experimental |
source/redis |
Redis Streams Inlet over go-redis: consumer group, XACK/pending-claim, DLQ. | experimental |
source/cloudevents |
CloudEvents codec with structured and binary content modes. | experimental |
source/cdc |
Change-data-capture codec: decode Debezium/OpenCDC change events, drive by key. | experimental |
source/statemachine |
Bridge: an inbound message drives a transition, ack tied to the durable commit. | experimental |
source also ships composable reliability middleware as its own opt-in modules
(source/retry, source/dlq, source/idempotency, source/schema) and an
in-memory source/memsource test source, each experimental.
Early and evolving. state is a complete, embeddable statechart engine, covering
hierarchical, parallel, and final states, history, guard combinators, delayed
transitions, invoked services, an actor model, snapshots, and JSON
(de)serialization, backed by its analysis, evolution, and conformance
packages. telemetry, sink, and source (with all their adapters, codecs, and
middleware) are released and documented; broker is planned. Treat every API as
experimental until it reaches v1.
Two kinds of seam frame the work ahead, and both build on the engine without reaching into the kernel: the IO edges where effects leave and events arrive, and the serializable IR as a first-class artifact anything can read or write.
The kernel emits effects as pure data; a small family of bring-your-own-adapter IO seams moves events to and from the outside world, each defaulting to a no-op and forcing nothing third-party on the consumer:
-
broker(planned): pub/sub transport. Publish emitted events and subscribe machines to external streams. -
sink: egress fan-out. Dispatch emitted effects to many outlets (SQL, Dynamo, StatsD, and more), fire-and-forget. Docs. -
source: ingress. Subscribe external streams and drive machines, with the ack tied to a durable transition; the symmetric counterpart tosink. Docs. Thesource/cdccodec decodes Debezium/OpenCDC change-event topics into typed change events; a native database write-ahead-log connector (logical replication slot, binlog) remains future work.
A small set of tools works the IR directly:
- Visual editor (planned): a browser workbench over the IR. Author, simulate,
and inspect machines, with reachability and version-diff overlays from the existing
analysisandevolutionpackages. - IR CLI (exploring): headless IR tooling for CI. Lint reachability and nondeterminism, render diagrams, and classify version diffs straight from a machine's IR.
Durable state and event persistence is tracked separately with the durable
runtime, not here.
Contributions are welcome. See CONTRIBUTING.md for dev setup, the Mage targets, conventional commits, and the DCO sign-off requirement. By participating you agree to the Code of Conduct.
Licensed under the Apache License, Version 2.0. See NOTICE for attribution.
