Skip to content

Repository files navigation

Grain

Grain is a constrained expression space or domain specific language for building event sourced systems with a uniform architecture.

Why Grain?

Grain exists to eliminate variance in how an information system is constructed.

Whether it's humans writing the code or AI, Grain enforces a single architectural paradigm and eliminates architectural drift as an error category. This is required in order to use AI to generate prolific amounts of source code for applications that have to act as a system of record and survive for 5 to 10 years or longer.

Without this, there is too much variance in how both humans and AI build information systems over time and this leads to the classic feeling of "We need re-write the system because no one can understand or work with it anymore" or in the AI era "This system has drifted too far from the original design and I don't understand how it works anymore."

Grain solves this problem end-to-end for information systems (a specific category of software) by providing a constrained grammar designed to eliminate novelty in the building process and act as a rock bottom floor that constrains the decision space of both humans and AI.

What is the paradigm?

The paradigm is CQRS and Event Sourcing.

This combination of approaches has the effect of enabling a long lived information system to be flexible and tolerant to change over time. As a system built this way matures, it naturally leads to the executable code artifact, that is the implmentation, to become more self-describing, more declarative, and an unignorable ambient signal that AI attends to when working on an application.

The reason that Event Sourcing is a better paradigm for this AI future than classic approaches which rely on mutable point-in-time relational databases and object oriented programming are myriad and the reader is encouraged to go look into this.

Grain's Grammar

Grain's grammar was not invented by us, we delegate out to Event Modeling by Adam Dymitruk. In this way, we inherit the ability to express any information system and we stand on the shoulder of those who have come before us, which is usually preferable to inventing new methods without cause.

Grain makes this grammar executable by providing 6 macros. Given that Grain is built with Clojure, we've essentially extended Clojure and specialized it for this purpose with these macros. This is what makes Grain a true Domain Specific Language for solving this kind of problem. The added benefits of choosing Clojure are too many to convey in any one place. It's a language designed for building information systems and reducing incidental complexity, so it has every primitive that we could ever need as a platform.

Full documentation with code examples: docs/core-concepts.md

  • defcommand — Commands are the C in CQRS. A command is a request to change the state of the system. It makes decisions and enforces business logic and invariants and produces zero or more events.
  • defquery — Queries are the Q in CQRS. Q query is a composition of domain data by way of Read Models that serves a screen or some other surface that users both human and automated interact with.
  • defreadmodel — Read Models are reductions over event streams that project the current state of the world resulting in a perspective about a set of facts that occurred over time. Concretely, these tend to be domain entities constructed by way of business logic. If you're coming from the relational database paradigm, Read Models tend to be like your tables with rows and columns, except that in Event Sourced systems, entities are emergent, rather than determined upfront.
  • defprocessor — Todo Processors are reactive background automations. They can watch for events that they are interested in and then react, usually this means executing Commands.
  • defperiodic — Periodic Tasks can be thought of as cron job triggers. They can emit an event on a schedule and they will always be paired with a Todo Processor that actually handles the work.
  • defschemas - Schemas force us to declare the shape of all the data in a Grain application.
  • Event — Events are the facts that we record in the event store database, from these the current state of the world can always be projected or re-projected, and this is at the core of why systems built this way are more flexible than the alternative.

Getting Started

Add to your deps.edn:

obneyai/grain-core-v2
{:git/url "https://github.com/ObneyAI/grain.git"
 :git/sha "6817ba3ab82b7fc916150ab4c783d5a1b36d2919" ;; update to latest commit sha
 :deps/root "projects/grain-core-v2"}

See bases/example-base and components/example-service for a complete example application. Run development/src/example_app_demo.clj to start and interact with the example system.

For multi-instance deployments, add the control plane package.

Example App: Grain Todo List

grain-todo-list is a compact teaching app for learning how to build with Grain. It demonstrates command handlers, event schemas, read models, query handlers, todo processors, periodic tasks, server-rendered Datastar UI, auth/session flow, and Integrant system composition in a small Clojure project.

The app repository includes its own README, agent notes in AGENTS.md, and a deeper architecture reference in doc/pattern-compendium.md.

Grain Sessions walks through the app as a teaching series:

Packages

Full package details and deps.edn snippets: docs/packages.md

Package Summary
grain-core-v2 Multi-tenant CQRS/Event Sourcing with in-memory event store and event tailing
grain-control-plane Distributed coordination — coordinator election, tenant leases, routing
grain-datastar Reactive server-rendered UIs with Datastar over SSE, including distributed live updates
grain-code-agent-tools Dev-only nREPL tools for coding agents working against live Grain apps
grain-event-store-postgres-v3 Multi-tenant Postgres backend with RLS, per-tenant advisory locks, and Fressian serialization
grain-event-store-sqlite-v3 Embedded single-process backend — WAL mode, tenant-scoped events with indexed tag filtering, Fressian serialization
grain-mulog-aws-cloudwatch-emf-publisher AWS CloudWatch metrics & dashboards

Multi-Tenancy

Every event-store operation is scoped to a :tenant-id, and the Postgres backend enforces isolation with Row-Level Security and per-tenant advisory locks. Start with an in-memory event store for quick iteration, then swap in SQLite for embedded single-process deployments or Postgres for multi-instance — a single line change either way.

For multi-instance deployments, an opt-in control plane coordinates tenant assignment across nodes using event-sourced leases — no external coordination service required.

Distributed Coordination

Full documentation: docs/distributed-coordination.md

The grain-control-plane package provides coordinator election, tenant lease management, and tenant-aware routing — all event-sourced on the shared Postgres event store. No external coordination service required.

Datastar (Reactive UI)

Full documentation: docs/datastar.md | UI DSL: docs/datastar-ui.md

Grain integrates with Datastar for reactive server-rendered UIs. Queries return hiccup that streams to the browser over SSE — the server re-renders when domain events fire and Datastar patches the DOM. In multi-node deployments, the event tailer can feed each node's local pub/sub from the shared event store so live updates reach the node holding the SSE connection.

Code Agent Tools

Full documentation: docs/code-agent-tools.md

The grain-code-agent-tools package provides dev-only nREPL tools for coding agents working against a live Grain app. Agents can inspect registered commands, queries, read models, processors, periodic triggers, schemas, projections, events, and runtime diagnostics as plain EDN, then validate payloads against the schema registry before invoking commands or queries.

Status

Grain is MIT licensed. We use it in production, but it's actively evolving. The core CQRS/Event Sourcing components are stable. The control plane is new and under active development.

More Information

About

Build Reasonable Applications with Clojure in the World of Natural Language Programming

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages