Contract-first. Headless. Swappable everywhere.
Openora is a contract spine with a plugin host and adapter seams around it. Contracts compile straight to a typed API and SDK - no UI ships in the framework itself, so your frontend, vendors and infrastructure all plug in through the same swap points.
- The API is oRPC + Hono - not a REST-and-controllers framework.
- The framework is headless. No UI ships in the core repo - your frontend lives in your own consumer app and talks to the typed API.
- Every domain is folded into a single published package, @openora/core, exposed through per-domain subpaths like @openora/core/wallet.
- AGENTS.md files regenerate automatically from one source of truth, so Claude Code, Copilot and other agents stay in sync without manual editing.
Source of truth: docs/architecture.md and the ADRs under docs/adr/ in the Openora repo.
From contract to running service.
Solid dependencies flow top to bottom; adapter seams cut across every layer so any vendor or surface can be swapped freely.
Contracts
Cross-cutting Zod schemas plus a composed oRPC contract - each module owns its own slice. The typed client is inferred straight from the contract, so there is no client to regenerate; an OpenAPI spec is emitted alongside it. Every type is inferred from the schema, never hand-written.
API runtime
One list of enabled plugins feeds the plugin host (definePlugin), which composes a typed-token container - lazy, last-wins, no decorators - into a Hono + oRPC handler. The API layer stays a thin caller of createApp().
Platform services
Shared infrastructure every module can depend on: Drizzle-backed storage, auth with admin guards, a logger, and the typed event bus. Single-tenant today - multi-brand hardening is on the roadmap.
Business modules
One folder per domain. A module can import the engine zones and a sibling's read-only schema - but never a sibling's internals. Cross-domain talk goes through events, command ports or shared contracts only.
Vendor adapters
Concrete implementations of a module's adapter interfaces - payments, KYC, game aggregators, chat. The interface is the seam; the implementation underneath is always swappable.
The swap points.
This is the reason the framework is headless and extensible - one side declares an interface, the other implements it, and you can swap the implementation freely.
Coupled to topics, not to routes.
The API layer is a backend-for-frontend: it triggers commands and serves reads. Modules never call each other directly.
A module emits through the typed event bus; any number of other modules can subscribe - fan-out, not point-to-point. Consumers must be idempotent, and a throwing subscriber is logged and isolated instead of taking the caller down with it.
Placing a bet - wallet debit, balance check, RNG result - and pre-action gates like KYC or jurisdiction checks run inside a single database transaction. Events record what already happened; they never move funds themselves.
The event bus is a typed facade over a swappable message broker. What ships today is the in-process default plus the MESSAGE_BROKER port. A durable driver - Kafka/Redpanda for a regulated audit/ledger/replay stream, NATS JetStream for lighter fan-out - is an overlay you bind yourself, with zero module changes.
Server-sent events, behind the REALTIME_TRANSPORT seam, are for talking to the client only - chat and live feeds - never the transport between modules.
The no-cross-domain-imports rule plus the broker seam mean a hot module - game aggregator, wallet - can be extracted into its own deployable later without touching its code.
Modular monolith today, microservices later.
A fresh scaffold runs as one deployable. When a hot module - bonus, game aggregator - needs to scale on its own, you extract the service. Module code never changes, only the deployment topology does.
$ pnpm create:app my-gaming-core $cd my-gaming-core && pnpm install $ docker compose up -d # postgres $pnpm db:migrate && pnpm dev ✔ api on :3001
No opinion about hosting - bare metal, your own Kubernetes cluster, or any major cloud, since the framework only assumes a Postgres-compatible database and a Node runtime.
A hash-chained audit trail for every state change.
Every mutation is append-only and chained to the previous entry - nothing can be silently edited or deleted after the fact. Reverting a mistaken grant creates a new, compensating entry instead of erasing history, which is exactly what a licensing review asks for.



Designed by the engineers who write the contracts, not a sales deck
Build it. Evolve it.
Own it.
Whether you're building from scratch, extending a legacy platform or planning a gradual migration, the framework gives you the freedom to evolve without vendor lock-in.