Type-safe event coordination for Go with zero dependencies.
Emit events with typed fields, hook listeners, and let capitan handle the rest with async processing and backpressure.
Events carry typed fields with compile-time safety.
// Define typed keys
orderID := capitan.NewStringKey("order_id")
total := capitan.NewFloat64Key("total")
// Define a signal
orderCreated := capitan.NewSignal("order.created", "New order placed")
// Emit with typed fields
capitan.Emit(ctx, orderCreated,
orderID.Field("ORD-123"),
total.Field(99.99),
)Each signal queues to its own worker — isolated, async, backpressure-aware.
// Hook a listener — extract typed values directly
capitan.Hook(orderCreated, func(ctx context.Context, e *capitan.Event) {
id, _ := orderID.From(e) // string
amount, _ := total.From(e) // float64
process(id, amount)
})
// Observe all signals — unified visibility across the system
capitan.Observe(func(ctx context.Context, e *capitan.Event) {
log.Info("event", "signal", e.Signal().Name())
})Type-safe at the edges. Async and isolated in between.
go get github.com/zoobz-io/capitanRequires Go 1.24+.
package main
import (
"context"
"fmt"
"github.com/zoobz-io/capitan"
)
// Define signals and keys as package-level variables
var (
orderCreated = capitan.NewSignal("order.created", "New order placed")
orderID = capitan.NewStringKey("order_id")
total = capitan.NewFloat64Key("total")
)
func main() {
// Hook a listener
capitan.Hook(orderCreated, func(ctx context.Context, e *capitan.Event) {
id, _ := orderID.From(e)
amount, _ := total.From(e)
fmt.Printf("Order %s: $%.2f\n", id, amount)
})
// Emit an event (async with backpressure)
capitan.Emit(context.Background(), orderCreated,
orderID.Field("ORDER-123"),
total.Field(99.99),
)
// Gracefully drain pending events
capitan.Shutdown()
}| Feature | Description | Docs |
|---|---|---|
| Typed Fields | Built-in keys for primitives; NewKey[T] for any custom type |
Fields |
| Per-Signal Workers | Each signal gets its own goroutine and buffered queue | Architecture |
| Observers | Cross-cutting handlers that see all signals (or a whitelist) | Concepts |
| Configuration | Buffer sizes, rate limits, drop policies, panic handlers | Configuration |
| Graceful Shutdown | Drain pending events before exit | Best Practices |
| Testing Utilities | Sync mode, event capture, isolated instances | Testing |
- Type-safe — Typed fields with compile-time safety, including custom structs
- Zero dependencies — Standard library only
- Async by default — Per-signal workers with backpressure
- Isolated — Slow listeners don't affect other signals
- Panic-safe — Listener panics recovered, system stays running
- Testable — Sync mode and capture utilities for deterministic tests
Capitan enables a pattern: packages emit, concerned parties listen, services observe.
Your domain packages emit events when meaningful things happen. Other packages hook the signals they care about. Service-level concerns — audit trails, structured logging, metrics collection — observe everything through a unified stream.
// In your order package
capitan.Emit(ctx, orderCreated, orderID.Field(id), total.Field(amount))
// In your notification package
capitan.Hook(orderCreated, sendConfirmationEmail)
// In your audit service
capitan.Observe(writeToAuditLog)Three packages, one event flow, zero direct imports between them.
Full documentation is available in the docs/ directory:
- Overview — What capitan provides
- Quickstart — Get started in minutes
- Core Concepts — Signals, keys, fields, listeners, observers
- Architecture — Per-signal workers, event pooling, backpressure
- Configuration — Buffer sizes, panic handlers, runtime metrics
- Context — Request tracing, cancellation, timeouts
- Errors — Error propagation, severity levels, retry patterns
- Testing — Sync mode, event capture, isolated instances
- Best Practices — Signal design, listener lifecycle, performance
- Persistence — Event storage and replay
- aperture — OpenTelemetry observability
- herald — Message broker bridge (Kafka, NATS)
- ago — Workflow orchestration (Experimental)
- API Reference — Complete function and type documentation
- Fields Reference — All built-in and custom field types
- Testing Reference — Test utilities API
See CONTRIBUTING.md for guidelines. Run make help for available commands.
MIT License — see LICENSE for details.