A lightweight, typed Go execution library for building reusable actions, resilient pipelines, and deterministic DAG workflows. Independent of concrete transports, persistence implementations, AI vendor SDKs, and identity providers.
An action owns its request, response, execution, and lifecycle. The Kernel owns lifecycle, concurrency safety, and execution semantics. Extensions implement backend drivers and explicit middleware layers; they do not fork the builder or alter execution semantics.
type UserRequest struct { ID string `json:"id"` }
type User struct { ID, Name string }
lookupUser := action.New("user.lookup",
func(ctx context.Context, req UserRequest) (User, error) {
return User{ID: req.ID, Name: "Alice"}, nil
}).
Timeout(2 * time.Second).
Retry(2, action.ExponentialBackoff(25*time.Millisecond, 2*time.Second)).
Build()
user, err := lookupUser.Do(ctx, UserRequest{ID: "usr-42"})Request and response types are inferred from the handler signature without reflection on the hot path. The builder chain compiles middleware at initialization time, so per-call cost is a constant: iterator closure, hook wrappers, panic recovery.
Seven packages, each with one job. No framework-shaped dependency maze — the Kernel does not bundle concrete database drivers, transport libraries, or vendor SDKs.
actionobserveai/dagxctxxerrstreamringbufThe Kernel supports type-erased and dynamic execution boundaries (AI tool-calling agents, plugin registries, generic HTTP routers) without weakening typed internal handlers.
act := action.New("user.lookup", lookupHandler).Build()
// 1. Direct type-erased call: 0 heap allocations on matching Req or *Req pointer
result, err := act.DoAny(ctx, UserRequest{ID: "usr-42"})
// 2. Universal Invoker: automatically decodes and coerces dynamic payloads
result, err = action.InvokeAny(ctx, act, map[string]any{"id": "usr-42"})
// 3. Coerce: converts dynamic structures (JSON, maps, strings) into target types
req, err := action.Coerce[UserRequest](untypedInput)
// 4. Dynamic lifting: lifts AnyAction into *Builder[any, any] for composition
dynamicAct := action.Dynamic(act).Build()Seven composition primitives connect typed actions without inventing intermediate adapter structs. Each one compiles to a single *BuiltAction that is safe for concurrent use.
Connect two actions sequentially (A → B). PipeWith inserts an inline transform function so you do not write a wrapper struct just to bridge two shapes.
Execute same-typed actions sequentially, piping output of one into the input of the next. Useful for layered validators and reducers.
T → T → TRoute execution conditionally using a router function. Branch keeps types; BranchAny works on type-erased registries.
router → A | BRun a fallback chain. The first non-error result wins; remaining actions are cancelled. Inputs must be idempotent.
A || B || CExecute typed actions concurrently over the same request (scatter-gather). Order is preserved in the returned slice.
scatter / gatherRun heterogeneous actions concurrently and collect results into a map[string]any keyed by branch name.
FanOut executes a slice of requests concurrently with bounded maxConcurrency. Race returns the first successful result and cancels losing attempts.
bounded · first-wins// Pipeline with zero-allocation inline field transform
pipeline := action.PipeWith("user.process",
fetchUserAct,
func(ctx context.Context, u User) (string, error) { return u.Email, nil },
sendEmailAct,
).Build()
// Heterogeneous concurrent execution
reviewer := action.ParallelNamed[string]("review.suite", map[string]action.AnyAction{
"security": checkSecurityAct,
"linter": runLinterAct,
}).Build()
results, err := reviewer.Do(ctx, "package main...")Retries, backoff, circuit breaking, dedup, coalesce, rate limiting, load shedding, distributed locks, sagas, and state machines. Each is a one-line builder method; each is independently testable.
Retry(n, backoff) retries only transient errors via xerr.IsTransient. RetryIf takes a custom predicate; RetryAll retries on any non-nil error for idempotent batch jobs.
ExponentialBackoff(base, max) doubles per attempt. ExponentialJitter adds ±30% random jitter to mitigate thundering-herd spikes. Plus LinearBackoff(step) and ConstantBackoff(d).
Adaptive(AdaptiveConfig{}) applies a breaker with dynamic timeout scaling and half-open state recovery. SmartResilience / InferredResilient drive retry + breaker automatically from xerr.Kind, fast-failing 4xx errors without consuming retries.
Dedup(keyFn) singleflight collapses concurrent identical calls. Coalesce(coalescer, keyFn) shares in-flight results; a canceled waiter may exit without terminating the background execution for other callers.
ConcurrencyLimit(n) enforces an in-process ceiling with atomic counters. RateLimit, RateLimitWithKey, and RateLimitDistributed provide token-bucket admission control.
Evaluates CPU percentage and goroutine count against priority tiers (PriorityCritical, PriorityNormal, PriorityLow), dropping non-essential traffic when thresholds are exceeded.
ExclusiveFenced(mutex, ttl, keyFn) acquires a LockLease with a monotonically increasing fence counter. An internal ticker renews the lease at ttl / 3. Lease loss cancels the action context immediately to abort in-flight work.
NewSaga[Req, Res] coordinates distributed transactions with compensating Undo functions in reverse LIFO order. NewStateMachine guards entity lifecycle transitions, rejecting disallowed ones with xerr.KindConflict.
act := action.New("fetch.data", coreHandler).
Timeout(2 * time.Second).
Retry(3, action.ExponentialJitter(100*time.Millisecond, 2*time.Second)).
Idempotent().
Cache(30*time.Second, keyFn, cacheStore).
Dedup(keyFn).
ConcurrencyLimit(10).
RateLimit(100, 50).
ExclusiveFenced(distLock, 10*time.Second, keyFn).
Build()Fencing contract notice: fencing is only effective if the downstream database or storage operation validates the token (e.g. UPDATE ... WHERE fence >= @fence). The Kernel coordinates lease lifecycle and cancellation; it cannot enforce fencing on storage engines that do not verify the token.
Cache, idempotency, and Once give you safe coordination under load. Every miss is singleflight-protected; every back-fill is automatic.
Cache(ttl, keyFn, layers...) coordinates L1 (local memory) through LN (distributed). Cache hits return without invoking the handler. Slower-layer hits back-fill faster layers. With no layers passed, an internal thread-safe cache with a background janitor is created.
Once() memoizes the result or error of the first execution indefinitely. Ideal for static configuration loaders that must run exactly once per process.
.Idempotent() / .IdempotentWithConfig(cfg) register metadata. IdempotencyCoordinator defines atomic claim semantics — Claim, Complete, Release — with leased in-progress locks and request hash validation to detect duplicate payload conflicts.
In-memory reference implementation of the coordinator. Swap in Redis, Postgres, or any durable store by implementing the same three-method contract.
reference implStreams are lazy, cancellable, and composable. The consumer decides when work is pulled; the action owns lifecycle hooks and terminal behavior. Per-item cost is zero allocations — only a constant per-call overhead (iterator closure, hook wrappers, panic recovery).
stream := action.NewStream("telemetry.stream",
func(ctx context.Context, req Query) (iter.Seq2[Record, error], error) {
return func(yield func(Record, error) bool) {
for i := 0; i < req.Limit; i++ {
if ctx.Err() != nil {
yield(Record{}, ctx.Err())
return
}
if !yield(Record{ID: i}, nil) {
return // Consumer stopped early
}
}
}, nil
})
seq, err := stream.Do(ctx, Query{Limit: 100})
for record, err := range seq {
// Zero heap allocation streaming
}CollectStream materializes an iterator into an in-memory slice when streaming is not required. The stream package adds composable operators — Map, Filter, Take, Batch, Reduce, FlatMap, WithContext — none of which allocate per item.
The ai/dag package compiles directed acyclic graphs into deterministic, concurrent execution layers. Cycle detection via Kahn's algorithm. Namespaced outputs. Pooled state. Sub-graph nesting. Mermaid export. Durable checkpoint/resume for human-in-the-loop.
graph, err := dag.New("order.workflow").
AddNode("validate", "val_out", validateAction).
AddNode("reserve", "res_out", reserveAction).
AddNode("charge", "chg_out", chargeAction).
AddEdge("validate", "reserve").
AddEdge("validate", "charge").
Compile()
initialState := dag.AcquireState()
defer initialState.Release()
finalState, err := graph.Execute(ctx, initialState)
defer finalState.Release()
res, err := dag.GetNodeOutput[ReserveResult](finalState, "reserve")Compiles layers using Kahn's algorithm. Circular dependencies return xerr.KindConflict at Compile() time — never at runtime.
Node outputs are stored under tasks.<node_id>.output to prevent key collisions during parallel execution. No accidental overwrite between concurrent branches.
State instances utilize sync.Pool. Read operations during layer execution are zero-lock. Callers must call state.Release() when finished.
A compiled DAG can be converted into an action via .AsAction() and embedded directly as a node in a parent DAG. Hierarchical composition without copy-paste.
graph.ToMermaid() exports deterministic, formatted Mermaid flowchart diagrams. Wire it into your CI to keep diagrams in lock-step with the executed graph.
Workflows requiring asynchronous human intervention (approvals, manual reviews, external callbacks) halt via dag.ErrSuspended. Partial state is preserved. Resume later by re-executing with a populated State; completed nodes are skipped automatically.
When a node returns dag.ErrSuspended, Execute returns (partialState, dag.ErrSuspended) without purging the state from memory. When re-executing with an existing state, any node whose output key is already present in State is skipped — ensuring non-idempotent upstream actions do not re-run.
Context guards inspect metadata attached to context.Context. Authentication (decoding JWTs, session lookups, certificate validation) is handled at transport boundaries; the Kernel enforces authorization, quotas, immutability, and audit at the action edge.
RequireAuth(), RequireTenant(), RequireRole(role), RequireAnyRole(roles...), RequirePermission(perm) (with wildcard *), RequireFeature(flags...), RequireAnyFeature(flags...).
RequireCreationLimit(resource, checkFn) checks resource quotas on entity creation (ID == 0). ImmutableWhen(guardFn, reason) aborts execution if an entity is in a locked or terminal state.
TrackPIIAccess(tracker, purpose) records personal data access reasons for regulatory compliance. Audited(logger, category, detailsFn) records audit events on successful execution. Transactional(runner) wraps execution inside an application-provided TxRunner.
xerr categories: BadRequest, Unauthorized, Forbidden, NotFound, Conflict, Validation, TooManyRequests, Timeout, Unavailable, Internal, CircuitBreaker. IsTransient(err) drives retry decisions; Public(requestID) returns sanitized API responses.
xctx.NewScope(parent) returns a pooled *RequestScope. Typed accessors: WithUserID, WithTenantID, WithRoles, WithPermissions, WithFeatures, WithTraceID. CloneForAsync(ctx) clones metadata into a detached context — preserving tracing while decoupling from the parent cancellation tree.
xerr.Sprint(err) renders error trees with sanitized user stack traces in development (ENV=dev) and structured one-line outputs in production. Never leaks internal causes or stack frames to end users.
// Categories: BadRequest, Unauthorized, Forbidden, NotFound, Conflict,
// Validation, TooManyRequests, Timeout, Unavailable, Internal, CircuitBreaker.
return xerr.NotFound("user not found")
return xerr.Unavailable("database connection dropped", originalErr)
if xerr.IsTransient(err) {
// safe to retry — the kernel's Retry policy already checks this
}
appErr := xerr.From(err)
// Public returns a sanitized ErrorResponse suitable for API responses
// without leaking internal causes or stack traces.
writeJSON(w, appErr.Public(requestID))The optional observe package emits vendor-neutral lifecycle events. Sinks are concurrency-safe and receive structured observe.Event records with action Duration and complete Request/Response payload references for latency and token/cost attribution. Nil hooks and no-op sinks evaluate with zero heap allocations on the hot path.
type fanoutSink struct{ sinks []observe.Sink }
func (f *fanoutSink) Emit(ctx context.Context, e observe.Event) {
for _, s := range f.sinks { s.Emit(ctx, e) }
}
sink := &fanoutSink{sinks: []observe.Sink{
observe.NewSlogSink(slog.Default()),
observe.NewMetricsSink(),
observe.NewPrometheusSink(),
observe.NewMemorySink(100),
observe.NewJSONLSink(os.Stdout, 4096),
}}
act := action.New("user.find", findUser).
AnyHook(observe.Hook(sink)).
Build()executedRequest, Response, DurationerrorError, DurationretryAttempt, Error, Durationcache_hitRequest, Response, Durationcache_missRequest, DurationcanceledRequest, DurationpanicRecovered, Request, DurationdeduplicatedRequest, DurationcoalescedRequest, DurationEvery event includes Time, Duration, Kind, Action, and available correlation identifiers (ExecutionID, TraceID, SpanID). Context cancellations emit canceled and are not duplicated as error events. Recovered panics emit a panic event followed by an error event containing the resulting xerr.KindInternal error.
The Kernel provides execution semantics and safety contracts. Applications supply the external integrations. This boundary is what keeps the Kernel small and your business logic yours.
observe captures lifecycle events and execution duration locally. Forwarding events to OpenTelemetry collectors, Datadog, or external brokers belongs to application sinks.dag.ErrSuspended), partial state preservation, and memoized resumption. Applications supply the human interfaces (webhooks, email dispatch, approval dashboards) and durable persistence for state snapshots.context.Context. Authentication (decoding JWTs, session lookups, certificate validation) is handled at transport boundaries.dag.State, xctx.RequestScope) must be explicitly released by the caller to prevent resource leaks.go run-ableComplete, runnable examples are located in the examples/ directory of the repository. Each one demonstrates a specific Kernel capability end-to-end.
Multi-layer parallel DAG execution with typed outputs.
ai/dagDeduplication, multi-layer caching, exponential jitter retry, and hooks.
resilience stackSequential pipelines (Pipe) and bounded concurrency (FanOut).
Monotonic fencing token renewal and lease-loss cancellation.
ExclusiveFencedTransient error recovery during parallel fan-out.
Parallel · recoveryConstant O(1) memory processing using Go 1.23+ iter.Seq2.
Embedding compiled DAGs as executable nodes within parent DAGs.
.AsAction()Request coalescing under high concurrent load.
Coalesce · DedupCustom predicates, transient-only retries, and universal retry policies.
Retry · RetryIf · RetryAllEnd-to-end lifecycle observation with Prometheus, Slog, JSONL, and Metrics sinks.
observe.HookComposed stream operators over large datasets without buffering.
stream operatorsCombining typed actions with stream pipelines.
action ↔ streamThe Kernel avoids reflection on execution paths, relies on immutable structures post-build, and compiles middleware chains at initialization time. Streaming is O(1) in memory. Per-item cost is zero allocations; only a constant per-call overhead is paid.
# Verify formatting
gofmt -l .
# Run static analysis
go vet ./...
# Run test suite with race detector
go test -race ./...
# Benchmark core dispatch and allocation profiles
go test ./... -run '^$' -bench=. -benchmemNexss is not a collection of unrelated packages. Each layer has one job and a precise boundary: the Kernel executes, Flow composes, and domain packages give the work meaning.
Start with a typed action. Add a stream when the work becomes incremental. Compile a DAG when the graph becomes the product. Nexss gives every layer a place to live.