skilj-codegen 0.0.1

build.rs codegen for skilj's own declarative bounded-context format (Codeberg issue #5's narrower cut, see docs/architecture.md §16/§17) - turns a .skilj.toml file's event/command type shapes into real Rust EventType/CommandType impls, the shared per-bounded-context event enum, and its BoundedContextEvent impl. decide() bodies stay hand-written Rust the generated code calls into; Projection generation is deliberately out of scope, see §17.
Documentation

SklilJ

skilj is a Rust library for building event-sourced, DDD-style applications backed by Postgres, using a Dynamic Consistency Boundary (DCB) instead of classic per-aggregate event sourcing - a command's consistency check spans exactly the tags it needs, not one fixed aggregate boundary. It exposes a GraphQL surface and a REST surface, and is built to guide an AI coding agent toward a correct, well-structured solution: the domain model is spec-first, data is encrypted/decrypted consistently, every surface is access-controlled, and adding a new event/command/projection follows one repeatable shape.

See specs/skilj.allium for the full behavioural specification, and docs/architecture.md for how it's built in Rust.

Crates

Crate What it is
skilj The main facade - a thin wrapper over skilj-core/skilj-graphql/skilj-rest. Start here.
skilj-core The domain engine: entities, rules, the plugin API, and persistence. Zero web-framework dependency.
skilj-graphql The GraphQL surface - a runtime-rebuilt dynamic schema and resolvers, independently usable.
skilj-rest The REST surface - narrowly-scoped, AccessToken-authenticated routes for agents and automated callers.
skilj-macros Two narrowly-scoped proc-macros used internally (re-exported through skilj-core, not usually added directly).
skilj-codegen Optional build.rs codegen: turns a declarative .skilj.toml bounded-context file into real Rust EventType/CommandType impls.
skilj-tui cargo install skilj-tui - a Ratatui operator console, a pure GraphQL client for any skilj deployment.
skilj-inspector cargo install skilj-inspector - a read-only Ratatui console that talks directly to Postgres, for when skilj-graphql isn't running.

skilj-demo (in this repo, not published) is a full worked example - two bounded contexts (banking, courses) showing what the DCB buys over classic per-aggregate event sourcing.

Getting started

[dependencies]
skilj = "0.0"

See skilj-demo for a complete, runnable example, and .claude/skills/skilj/ for a Claude Code skill that walks an AI agent through adding a new event/command/projection to an existing bounded context.

License

Licensed under either of

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project, as defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions.

See CONTRIBUTING.md for how to build, test, and submit changes, CODE_OF_CONDUCT.md for community expectations, SECURITY.md for how to report a vulnerability, and CHANGELOG.md for release notes.

Reading events over REST

If you're a machine caller holding an EventReadToken (an AI agent, a remote workflow, an adapter), there are three ways to read a token's event stream, each trading off differently. Pick based on how your own process fails, not just on which is "best":

Who remembers where you are If your process crashes mid-read Best for
Client-tracked (GET /v1/events?after=...) You do You resume exactly where you left off — you control the position You already persist a checkpoint somewhere (a database row, a file) and want full control
Server-tracked, auto-advance (GET /v1/events/consume?mode=auto) SkilJ does, per token You lose whatever you were served but hadn't finished handling — SkilJ won't send it again Quick integrations, stateless workers, scripts — no checkpoint to manage at all, occasional missed events on crash is fine
Server-tracked, manual-ack (GET /v1/events/consume?mode=manual + POST /v1/events/consume/ack) SkilJ does, per token, but only once you confirm You get the same events again next time — nothing is lost Processing that must never silently drop an event, as long as your handler is safe to run twice on the same event (idempotent)

A few things that trip people up:

  • One token = one read position. If you want two independent places in the stream (say, two worker instances), mint two EventReadTokens rather than trying to share one — there's no separate "consumer name" to pass.
  • Auto-advance and manual-ack are a one-time choice per token. Whichever mode a token's first consume call uses is the mode it keeps for that token's lifetime. Want to switch? Use a new token.
  • Manual-ack can redeliver duplicates, on purpose. If you fetch a batch and crash before acknowledging it, the next fetch serves the same batch again. This library doesn't de-duplicate for you — your handler needs to be safe to run twice on the same event (e.g. keyed by the event's own sequence).
  • Mixing modes on one token is allowed but not coordinated. GET /v1/events (client-tracked) never reads or moves a token's server-side cursor, so using both against the same token gives you two positions that know nothing about each other.

See §7 of docs/architecture.md for the full wire contract (routes, request/response shapes, error codes), and entity ReadCursor in specs/skilj.allium for the underlying behavioural guarantee.