Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .rulesync/commands/pre-pr.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
targets:
- '*'
description: 'Run the full pre-PR gate locally - `pnpm verify` plus the drift check CI runs (`pnpm check:drift`), which `pnpm verify` alone does NOT cover. Catches stale catalog/openapi/agent-docs before push.'
description: 'Run the full pre-PR gate locally - `pnpm verify` plus the drift check CI runs (`pnpm check:drift`), which `pnpm verify` alone does NOT cover. Catches stale catalog/agent-docs before push.'
---

Run the same gate CI enforces, in order. Stop at the first failure and report it.
Expand Down
5 changes: 2 additions & 3 deletions .rulesync/commands/regen.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
---
targets:
- '*'
description: 'Regenerate all derived artifacts - oRPC OpenAPI spec, Drizzle client, and the machine-readable docs/catalog.json. Run after any change to Drizzle tables or oRPC contracts.'
description: 'Regenerate all derived artifacts - Drizzle client and the machine-readable docs/catalog.json. Run after any change to Drizzle tables or oRPC contracts.'
---

Run `pnpm regen` in the repo root.

This runs in order (see root `package.json`):

1. `turbo run check:types` - emits `docs/openapi.json` from the composed oRPC contract and
regenerates any per-package codegen registered with turbo.
1. `pnpm gen:tsconfig` - synchronizes TypeScript path aliases.
2. `pnpm gen:drizzle` (`scripts/generate-all.mjs`) - discovers every module's
`src/**/drizzle.config.ts` and runs `drizzle-kit generate` per module, against that module's own
co-located `drizzle/migrations/` history (ADR-0027).
Expand Down
2 changes: 1 addition & 1 deletion .rulesync/commands/scaffold-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ The scaffold ships a buildable module - a `list` route wired end to end (contrac
3. `contract/index.ts` - Zod input/output schemas for the routes (the single source of wire truth).
4. `service/<name>.service.ts` - business logic; inject `DRIZZLE` + `EVENT_BUS` + adapter ports via the constructor; never inline fetch/SQL. Audit every mutation.
5. `router/index.ts` - oRPC routes with imported schemas; admin routes call `await adminGuard.assert(context)` first.
6. `pnpm regen` (OpenAPI + migration + catalog), then `pnpm verify`.
6. `pnpm regen` (migration + catalog), then `pnpm verify`.

Tell the user what was generated and what remains to fill in.
2 changes: 1 addition & 1 deletion .rulesync/commands/scaffold-route.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: 'Add an oRPC route stub to an existing module. Args: <domain> <modu

Parse $ARGUMENTS as: <domain> <module> <method> <path>. The domain is the module's dir under `packages/core/src/`.

Before adding, call the MCP tool `query-openapi` with the path to confirm the route doesn't already exist.
Before adding, call the MCP tool `list-routes` to confirm the route doesn't already exist.

Run `pnpm gen route <domain> <module> <method> <path>` in the repo root. The generator adds BOTH a contract procedure (in the module's `contract/index.ts`) and a matching router handler - no inline Zod in the router.

Expand Down
2 changes: 1 addition & 1 deletion .rulesync/rules/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ The always-on core of the code standard: what you must obey while typing. Detail
- Inline `fetch`/`axios` in module code - third-party access is a port + adapter bound at the root.
- Comments. The only exception is a fact the code cannot contain (external-system behaviour, a spec constraint) and JSDoc on a public export. A rationale is not a fact - it goes in the commit or an ADR.
- Deep (`../../`+) relative imports that leave your zone/module, imports of another module's internals, import cycles, deep `dist/`/`src/` paths into another package.
- Hand-edited generated files: migrations, `docs/openapi.json`, `docs/catalog.json`, per-tool agent mirrors.
- Hand-edited generated files: migrations, `docs/catalog.json`, per-tool agent mirrors.

## Always

Expand Down
18 changes: 9 additions & 9 deletions .rulesync/rules/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ Before acting on any non-trivial request - and before delegating - run the `enha

## Architecture pillars

1. **Zod-first contracts.** Every shape is a Zod schema; types are `z.infer`'d, never hand-written. Cross-cutting schemas in `packages/core/src/contracts/schemas/`; each module OWNS its route contract + req/res schemas + `z.infer`'d types in its `contract/` dir - the single source of wire truth, nothing else re-declares a wire shape. `composeContract` (`@openora/core/contracts`) owns only `health`; the composition root (`tools/gen/build-contract.ts` here, the consumer's entry when deployed) composes each enabled module's `/contract` slice into the one runtime contract the SDK links against. ADR-0021/0025.
2. **oRPC + Hono.** oRPC owns route definition + Zod validation + OpenAPI emit; its `OpenAPIHandler` mounts on a Hono server. DI is a functional `Container` (`@openora/core/server`) - typed-token factories, no decorators, no `reflect-metadata`. ADR-0009.
1. **Zod-first contracts.** Every shape is a Zod schema; types are `z.infer`'d, never hand-written. Cross-cutting schemas in `packages/core/src/contracts/schemas/`; each module OWNS its route contract + req/res schemas + `z.infer`'d types in its `contract/` dir - the single source of wire truth, nothing else re-declares a wire shape. `composeContract` (`@openora/core/contracts`) owns only `health`; the consumer composition root composes each enabled module's `/contract` slice into the one runtime contract the SDK links against. ADR-0021/0025.
2. **oRPC + Hono.** oRPC owns route definition + Zod validation; its `OpenAPIHandler` mounts on a Hono server with a live OpenAPI reference. DI is a functional `Container` (`@openora/core/server`) - typed-token factories, no decorators, no `reflect-metadata`. ADR-0009.
3. **Plugin host.** Typed plugin objects are the only way new functionality enters. Everything (core modules included) loads through `extensions.config.ts`.
4. **Headless.** Backend modules + contracts + SDK surface only. UI lives in the consumer, which imports `@openora/core/react` (hooks, typed client, auth, realtime). No UI packages here.
5. **Explicit > magic.** No auto-discovery, no decorators. Everything greppable; every wiring point a typed call.
Expand Down Expand Up @@ -51,13 +51,13 @@ packages/
docs/
adr/ # architecture decision records
catalog.json # generated surface (routes/schemas/adapters/slots/events); read by @openora/mcp
tools/ # grouped: gen/ (gen.ts scaffolder, build-contract, gen-openapi, gen-catalog), lint/ (oxlint plugins, verify-module-shape), create/, db/ (seed), setup/
tools/ # grouped: gen/ (gen.ts scaffolder, gen-catalog), lint/ (oxlint plugins, verify-module-shape), create/, db/ (seed), setup/
extensions.config.ts # the single registry of enabled plugins
```

## Where does X go? (decision tree)

- **New business domain** (eg "tournaments") -> `pnpm gen module <domain> <name>` creates `packages/core/src/<domain>/<name>/`, wires the domain barrels + the `@openora/core` exports map + the `/contract` slice in `tools/gen/build-contract.ts`, and registers it in `extensions.config.ts`. Every module owns its `drizzle.config.ts` + migration history. ADR-0024/0025/0027.
- **New business domain** (eg "tournaments") -> `pnpm gen module <domain> <name>` creates `packages/core/src/<domain>/<name>/`, wires the domain barrels + the `@openora/core` exports map, and registers it in `extensions.config.ts`. Every module owns its `drizzle.config.ts` + migration history. ADR-0024/0025/0027.
- **Extend/override an existing module** -> overlay plugin: `pnpm gen plugin <name>` -> `extensions/<name>/plugin.ts` (repo root here; the consumer's app when deployed).
- **New HTTP route** -> the module's `router/index.ts` via `pnpm gen route <module> <method> <path>`. Player routes resolve the caller from `x-user-id`; admin routes MUST be guarded (next).
- **Admin-only route** -> `plugin.ts` resolves `AdminGuard` (`c.get(ADMIN_GUARD)`, seeded by `createApp`) and passes it into the router; `await adminGuard.assert(context)` is the handler's FIRST line. The single admin-enforcement point - never re-implement the role check.
Expand Down Expand Up @@ -105,13 +105,13 @@ Scripts are grouped by prefix - `check:*` reports, `fix:*` rewrites, `gen:*` emi
```
pnpm setup # first time: docker + db + mcp + summary
pnpm dev # turbo dev (docs, mcp)
pnpm regen # tsconfig paths + openapi emit + drizzle generate + catalog
pnpm regen # tsconfig paths + drizzle generate + catalog
pnpm db:seed # demo data (idempotent; admin@oss.dev / password123)
pnpm verify # the full gate: every check:* + test:unit + test:integration + test:tools, in parallel
pnpm test:unit # infra-free suite (~4s); *.int.test.ts run in test:integration (docker pg + redis)
pnpm db:setup:test:fresh # recreate the shared e2e db after editing an already-applied migration
pnpm check:boundaries # just the whole-graph boundary + cycle gate
pnpm check:drift # catalog/openapi staleness (CI-only; not part of verify)
pnpm check:drift # catalog staleness (CI-only; not part of verify)
pnpm fix:lint # oxlint --fix; pair with fix:format
pnpm -F @openora/core vitest run <path> # one test file/dir, eg src/iam/__tests__
```
Expand Down Expand Up @@ -148,9 +148,9 @@ For platform development (this repo); consumer agents ship in `tools/templates/c

## Working rules for agents

- Use the `oss-dev` MCP server (`.mcp.json`, pre-approved) for read-only inspection: `read-agents-md`, `list-modules`, `describe-module`, `list-routes`, `list-extension-points`, `query-openapi`, `get-drizzle-schema`, `propose-table-change`, `schema-get`, `docs-search`, `db-query-readonly`. Faster than grep, reflects current state.
- Before a route: `query-openapi`. Before a table: `propose-table-change`. After any change: `pnpm verify --filter <package>`; fix failures before continuing.
- Use the `oss-dev` MCP server (`.mcp.json`, pre-approved) for read-only inspection: `read-agents-md`, `list-modules`, `describe-module`, `list-routes`, `list-extension-points`, `get-drizzle-schema`, `propose-table-change`, `schema-get`, `docs-search`, `db-query-readonly`. Faster than grep, reflects current state.
- Before a route: `list-routes`. Before a table: `propose-table-change`. After any change: `pnpm verify --filter <package>`; fix failures before continuing.
- Read the touched module's `AGENTS.md` before editing it; keep it updated when invariants or extension seams change. Every `AGENTS.md` (this one included) stays lean: only what code can't say - invariants, rationale, gotchas, extension seams. Never route/table/event listings or "see `contract/`" pointers; agents already know to read `contract/`, `schema/`, `docs/catalog.json`. Claude Code loads them via generated per-module `CLAUDE.md` stubs (`tools/gen/gen-claude-stubs.mjs`, gitignored).
- Small PRs scoped to one module; cross-module changes need human approval. Never commit unless asked; never push without explicit per-action confirmation.
- ASCII only in code; short dashes (-) only, never long dashes.
- **Never run two agents that both call `pnpm regen` (or `pnpm sync:agents`) against the same working tree.** Both rewrite shared generated state - drizzle migration journals, `docs/catalog.json`, `docs/openapi.json` - and the second run silently discards the first agent's freshly generated migration. The tree then holds a new enum value or table with NO migration: unit tests, lint and `boundaries` all still pass, so it surfaces at deploy, not in CI. Parallelise agents only across disjoint modules with regen serialised afterwards by one owner, and `git status -- '**/drizzle/migrations/**'` before handing off.
- **Never run two agents that both call `pnpm regen` (or `pnpm sync:agents`) against the same working tree.** Both rewrite shared generated state - drizzle migration journals and `docs/catalog.json` - and the second run silently discards the first agent's freshly generated migration. The tree then holds a new enum value or table with NO migration: unit tests, lint and `boundaries` all still pass, so it surfaces at deploy, not in CI. Parallelise agents only across disjoint modules with regen serialised afterwards by one owner, and `git status -- '**/drizzle/migrations/**'` before handing off.
4 changes: 2 additions & 2 deletions .rulesync/subagents/contract-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Stance: assume the change is BROKEN until you trace it working - review to falsi

## Grounding

If the orchestrator passed a base ref + changed-file list, use them - do not re-scope the diff. Otherwise: `git diff origin/dev...HEAD --name-only`. READ each changed file before judging it - never infer behavior from a hunk. Compare route changes against the committed `docs/openapi.json`. Cite the rule doc (`conventions`, `docs/standards/*.md`, root `AGENTS.md`) or ADR each finding rests on.
If the orchestrator passed a base ref + changed-file list, use them - do not re-scope the diff. Otherwise: `git diff origin/dev...HEAD --name-only`. READ each changed file before judging it - never infer behavior from a hunk. Compare route changes against the module contract. Cite the rule doc (`conventions`, `docs/standards/*.md`, root `AGENTS.md`) or ADR each finding rests on.

## Checklist

Expand All @@ -29,7 +29,7 @@ If the orchestrator passed a base ref + changed-file list, use them - do not re-

- [ ] Zod schemas live in the module's `contract/`/`schemas/` or core contracts - no ad-hoc schemas in handlers; no `z.any()`/`z.unknown()` in public contracts.
- [ ] Every oRPC procedure has typed `.input()` and `.output()`; no hand-written response types (all `z.infer`'d).
- [ ] Breaking changes to existing routes flagged (vs committed `docs/openapi.json`).
- [ ] Breaking changes to existing routes flagged (vs the module contract).

### Drizzle

Expand Down
2 changes: 1 addition & 1 deletion .rulesync/subagents/dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Your prompt contains requirements + acceptance criteria. Build to those. If the

1. Read root `AGENTS.md` (decision tree, boundaries, forbidden patterns) and the sibling rules (`conventions`, `messaging-and-microservices`) plus the `docs/standards/` file matching what you are changing. Follow exactly.
2. Read the touched module's `AGENTS.md` and any related `docs/adr/`.
3. Inspect current state via `oss-dev` MCP: `list-modules`, `describe-module`, `list-routes` (collision check), `query-openapi`, `get-drizzle-schema`, `propose-table-change` (before any table), `schema-get`.
3. Inspect current state via `oss-dev` MCP: `list-modules`, `describe-module`, `list-routes` (collision check), `get-drizzle-schema`, `propose-table-change` (before any table), `schema-get`.
4. Pick the home via the decision tree. Use the scaffolders (`pnpm gen module|route|plugin|adapter|job-worker`) - don't hand-write skeletons.
5. Library API in doubt (Hono, oRPC, Drizzle, Zod, better-auth)? Check current docs via context7/web search - don't code from memory.

Expand Down
5 changes: 2 additions & 3 deletions .rulesync/subagents/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ claudecode:
- mcp__oss-dev__describe-module
- mcp__oss-dev__list-routes
- mcp__oss-dev__list-extension-points
- mcp__oss-dev__query-openapi
- mcp__oss-dev__schema-get
- mcp__oss-dev__docs-search
- mcp__oss-dev__read-agents-md
Expand All @@ -28,7 +27,7 @@ You keep the OSS docs honest. Read the code first, write the docs second - never

- **Edit docs only.** Never touch `apps/`, `packages/`, `tools/`, `extensions.config.ts`, schemas, services, routers, plugins.
- **Never edit generated mirrors** (`AGENTS.md`, `CLAUDE.md`, `.codex/config.toml`, `.github/copilot-instructions.md`, `.claude/`+`.github/` subagent/command files) - edit the `.rulesync/` source, then `pnpm gen:agents`.
- **Never touch generated artifacts** (`docs/openapi.json`, `docs/catalog.json`, drizzle migrations) - `pnpm regen` owns them.
- **Never touch generated artifacts** (`docs/catalog.json`, drizzle migrations) - `pnpm regen` owns them.
- **No new docs unless asked**; if a fact has no home, raise it. **Don't invent** - if you can't verify a claim from code, omit it.

## Ground each claim in code
Expand All @@ -37,7 +36,7 @@ You keep the OSS docs honest. Read the code first, write the docs second - never
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| Repo map / "what lives where" | `ls apps/ packages/` - every named dir must exist and match its `package.json`/`AGENTS.md` |
| Module roster / domain claims | `mcp__oss-dev__list-modules` + `extensions.config.ts` |
| Route / adapter / extension claims | `list-routes`, `list-extension-points`, `query-openapi` |
| Route / adapter / extension claims | `list-routes`, `list-extension-points` |
| Scaffolder flags + templates | `tools/gen/gen.ts`, `packages/core/generators/src/config.ts`, `tools/create/create-igaming-app.ts`, `ls tools/templates/` |
| MCP tools listed in agent docs | the `server.tool(...)` registrations in `apps/mcp-server-dev/src/main.ts` |
| ADR "is" claims | if Status is Accepted but the code disagrees, the ADR is stale - add a dated Update block |
Expand Down
2 changes: 1 addition & 1 deletion .rulesync/subagents/expert.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ You are a senior iGaming product/domain expert who has shipped multiple real-mon
## Grounding (do this first)

1. Read root `AGENTS.md` (mission, pillars, decision tree) so requirements map onto how this platform is built.
2. Inventory what exists: `list-modules`, `list-routes`, `list-extension-points`, `query-openapi` via the `oss-dev` MCP; read active modules' `AGENTS.md`. Don't spec what already ships.
2. Inventory what exists: `list-modules`, `list-routes`, `list-extension-points` via the `oss-dev` MCP; read active modules' `AGENTS.md`. Don't spec what already ships.
3. Read `docs/catalog.json` for the adapter surface - which vendor ports exist, wired vs stubbed.

## How you work
Expand Down
4 changes: 2 additions & 2 deletions .rulesync/subagents/module-author.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ You are an expert TypeScript / Hono / oRPC engineer implementing a module for th

1. Read root `AGENTS.md` + the `conventions` sibling rule + matching `docs/standards/` files, especially `database.md` and `module-structure.md`. Follow exactly.
2. Read an existing module (eg `packages/core/src/wallet/`) for the exact file shape.
3. Check current state via `oss-dev` MCP: `list-modules`, `describe-module`, `list-routes`, `query-openapi` (route collisions), `get-drizzle-schema`, `propose-table-change` (before ANY table).
3. Check current state via `oss-dev` MCP: `list-modules`, `describe-module`, `list-routes` (route collisions), `get-drizzle-schema`, `propose-table-change` (before ANY table).
4. Unanswered domain question in the brief? STOP and spawn `expert` before writing code.
5. Library API in doubt (Hono, oRPC, Drizzle, Zod)? Check current docs via context7/web search - don't code from memory.

Expand All @@ -49,7 +49,7 @@ Creates the module as a standalone package with all required files and registers
| `plugin.ts` | `Plugin<CoreTokenCatalog>` object - DI wiring only. |
| `AGENTS.md` | ONLY what code can't say: invariants, rationale, gotchas, extension seams. No route/table/layout listings - they duplicate `contract/`/`schema/` and drift. |

Headless repo: build no UI. After filling in: `pnpm regen` (migration + OpenAPI + catalog), then `pnpm verify` and fix everything.
Headless repo: build no UI. After filling in: `pnpm regen` (migration + catalog), then `pnpm verify` and fix everything.

## Finish criteria

Expand Down
2 changes: 1 addition & 1 deletion .rulesync/subagents/operator.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ You are a technical founder standing up a new online igaming on top of `@openora

## Verify outside-in

- Don't trust docs - run things. `list-modules`/`list-routes`/`query-openapi` (MCP) for the declared surface; boot the probe app + `pnpm db:seed`, hit endpoints via curl to confirm they work, not just that they're declared.
- Don't trust docs - run things. `list-modules`/`list-routes` (MCP) for the declared surface; boot the probe app + `pnpm db:seed`, hit endpoints via curl to confirm they work, not just that they're declared.
- Check each module's ports + `adapters/` to confirm vendor seams are real and overridable (KYC/PSP/notifications). `docs/catalog.json` marks each adapter wired vs stub - note stub-only ones.

## Readiness checklist (score Have / Partial / Missing, with the specific gap)
Expand Down
Loading
Loading