# OGraph **Event Sourcing + Projection + Reaction engine for Agent ecosystems.** Part of the [Uncaged](https://github.com/oc-xiaoju/uncaged) ecosystem. ## Philosophy 1. **Event is fact** — immutable, append-only, no logic 2. **Projection is cache** — lazy, closed-world, on-demand computation 3. **Intelligence lives in the Agent, not the Engine** — Agent-in-the-Loop ### Why not Kafka? | | Kafka | OGraph | |---|---|---| | Metaphor | Ballistic missile (design, fire) | Guided missile (adjust in flight) | | Pipeline | Pre-defined by humans | Agent defines/adjusts at runtime | | Computation | Eager (continuous update) | **Lazy** (on-demand) | | JOIN | ✅ KTable synchronized | ❌ Projections are independently lazy | | Aggregation | Pre-set materialized views | Actor (Agent) assembles in real-time | | Core assumption | Humans design everything upfront | **Agent-in-the-Loop: runtime decisions** | Traditional Event Sourcing (Kafka, EventStoreDB) assumes pipelines are designed, deployed, and maintained by human developers. OGraph assumes an Agent with decision-making capability dynamically defines Projections, adjusts Watch lists, and assembles aggregations at runtime. This is not a feature trade-off. It's a paradigm difference. ### Lazy Update — a logical necessity 1. Agent can define new Projections at any time → can't assume all Projections are deployed 2. → Must be Lazy (compute on demand) 3. → No consistent cross-Projection snapshot → abandon JOIN Each step is logically inevitable. From a single assumption — "Agent defines Projections at runtime" — the entire computation model follows. ## Three-Layer Modeling ### Layer 1: Event — Facts Immutable records of what happened. No judgment, no derived logic. ### Layer 2: Projection — Cache Deterministic computation over event streams. Core constraint: **computational closure** — expression inputs are only `$state`, `$event`, `$params`. Cannot query other Projections or make external calls. ### Layer 3: Actor — Behavior Observes multiple Projections, executes complex logic and side effects. Watch lists are **dynamic** — derived from data, not hardcoded. ## Packages | Package | Description | npm | |---|---|---| | [`@uncaged/ograph`](packages/engine/) | CF Worker engine — events, projections, reactions | [![npm](https://img.shields.io/npm/v/@uncaged/ograph)](https://www.npmjs.com/package/@uncaged/ograph) | | [`@uncaged/ograph-cli`](packages/cli/) | CLI for managing OGraph instances | [![npm](https://img.shields.io/npm/v/@uncaged/ograph-cli)](https://www.npmjs.com/package/@uncaged/ograph-cli) | | [`@uncaged/ograph-dispatcher`](packages/dispatcher/) | Local daemon — polls projections, notifies Agent when idle | | ## Quick Start ```bash npm install -g @uncaged/ograph-cli ograph deploy # Deploy to Cloudflare Workers ograph event-defs list # List event types ograph events emit # Emit events ograph schema # View all definitions ``` ## Development ```bash npm install npm test # Run all tests (163+) cd packages/engine && npm run dev # Local dev server ``` ## Architecture - **D1** for storage (events, projections, reactions) - **Hono** for API routing - **Lazy incremental reduce** — projections track `last_event_id` for O(delta) updates - **Projection health** — errored projections stop updating, auto-recover when fixed - **Dynamic handlers** — `new Function()` sandboxed execution with emit/log/kv API injection - **API Key** — `ogk_` prefix, SHA-256 hash, event type whitelist - **Structured errors** — `{ error: { code, message } }` ## License MIT --- *Built by 小橘 🍊 & 小墨 🖊️ — NEKO + KUMA Teams*