Skip to content

GES Extension: Read models, projections, and searchability

Part of the Git Event Store specification family. Extends the core specification (../git-event-store-spec.md); RFC-2119 keywords per core §0.1. An implementation claims this extension per core §1. The decision-loop rule (a projection informs a command; the decider plus append CAS authorizes it) is core append semantics — see core §10.0. Section and requirement numbering is retained from the pre-family document for E-ID and cross-reference stability.


Git is not a query engine (§11.6): there is no secondary index over event content. Queries such as “all events with kundennummer = 4711” are served at three levels; implementations SHOULD document which they offer.

16b.1. Native scan (forensic / agent). Because each commit appends exactly one event (§5.2), git log -S<literal> --all (pickaxe) and git log -G<regex> --all locate the commits that introduced matching content, and git grep searches tree content. This is O(history), not indexed, but requires no infrastructure and is directly usable by an agent (git log -S4711). Implementations MAY expose this as a find command. It MUST NOT be presented as a scalable hot query path.

16b.2. Stream modeling. When the query key is a stream identity, the stream ref already groups those events (refs/ges/<store>/streams/<key>); no search is needed. This covers stream-scoped queries only.

16b.3. Projections (the primary answer). Any cross-cutting or hot query MUST be served by a read model (§16c), i.e. a maintained lookup index (e.g. kundennummer → [event ids]). The event store is the write model and source of truth; queries hit derived read models. This is the canonical event-sourcing stance: do not query the store, query a projection.


16c.1. A projection folds events into a query-optimized view and records how far it has processed. The processed-position cursor MUST be durable; implementations SHOULD store it as a ref:

refs/ges/<store>/projections/<name>/cursor → last processed commit

16c.2. Catch-up subscription. On run, a projection reads cursor..tip for each subscribed stream, applies events via a pure fold, then advances the cursor. Because the fold is pure and events are the source of truth, a read model is disposable and rebuildable: dropping it and replaying from position 0 reconstructs it exactly, so read-model loss is not data loss. Schema changes are handled by rebuild.

16c.3. Location. A read model MAY live outside Git (SQLite .gitignore’d, PostgreSQL, DuckDB, a search index) as a disposable cache, or inside Git (a ref pointing at an index tree) to travel with the repository. External is RECOMMENDED for mutable, random-access views; Git is a poor substrate for those.

16c.4. Notification. Git has no native push. A post-commit (local) or post-receive (server) hook SHOULD trigger catch-up; otherwise the projection polls ref tips. The hook is the subscription mechanism.

16c.5. Global-order basis. A projection spanning multiple streams SHOULD fold over the global stream’s total order (§20, C22). globalPosition of a local, not-yet-sequenced append is provisional (§20.3); a projection requiring authoritative order MUST either track only the sequenced prefix or tolerate reordering of the provisional tail.

16c.6. Emmett distinguishes inline projections (updated within the append operation) from async projections (cursor-driven subscriptions); a GES binding maps these to same-operation read-model writes and hook/poll catch-up respectively. Exact API MUST be reconciled with the installed Emmett version.



Moved verbatim from the companion catalog (../ges-review-and-ears.md); IDs unchanged.

  • E-16b-1 Where native scan is offered, the store shall locate events using pickaxe or grep.
  • E-16b-2 The store shall serve cross-cutting or hot queries from a read model rather than by scanning the store.
  • E-16b-3 The documentation shall state that native scan is not a scalable hot query path.
  • E-16c-1 The projection runner shall record its processed position as a durable cursor.
  • E-16c-2 When triggered, the projection runner shall apply events from its cursor to the tip via a pure fold.
  • E-16c-3a The projection runner shall advance the cursor only after the read-model write succeeds. (covers R4)
  • E-16c-3b The projection runner shall be idempotent under replay. (covers R4)
  • E-16c-4a While a projection spans multiple streams, the projection runner shall not assume a global order across streams.
  • E-16c-4b Where a multi-stream projection requires a total order, the projection runner shall impose a synthetic order.

Git Event Store is an independent open specification for an event store that uses Git as its storage component. It is not affiliated with or endorsed by the Git Project or Software Freedom Conservancy. Git and the Git logo are either registered trademarks or trademarks of Software Freedom Conservancy, Inc., corporate home of the Git Project, in the United States and/or other countries.

Git Event Store is not affiliated with or endorsed by Kurrent, the maker of KurrentDB (formerly EventStoreDB). "Event store" is used here as the generic name of the event-sourcing storage pattern.