Architecture
Rooster is a pnpm monorepo of @rooster/* packages with one deployable app.
Packages
Section titled “Packages”| Package | Responsibility |
|---|---|
config |
Env loading + validation (zod); DB-driver + platform selection |
schema |
zod domain entities, enums, DTOs, ids — the validation source of truth |
db |
Drizzle schema (SQLite + Postgres), migrations, repositories, drivers, seed |
core |
Domain services, permissions, status transitions, audit, onboarding |
auth |
better-auth config, the identity bridge, enrollment gating, scopes |
mcp |
MCP server: tools + resources + the stateless Streamable-HTTP transport |
server (app) |
The Hono deployable: auth + /mcp + discovery + /onboard |
Dependency direction (never cycles): config ← db ← core ←
{auth, mcp} ← server. schema is depended on by everyone. Core is
transport-agnostic — it depends only on db + schema.
Request → action flow
Section titled “Request → action flow”- An agent sends
Authorization: Bearer …toPOST /mcp. - The server resolves the token (
auth.resolveMcpIdentity) → maps the OAuthclientIdto its bound Agent → anActorIdentity(effective scopes = token grant ∩ agent allowance). core.resolveActor()loads the principal and computes the effective org role from memberships → an Actor.- A per-request MCP server is built bound to that Actor; a tool calls a core service.
- Every mutation: authorize (role floor and, for agents, token scope) →
validate input with the schema DTO → enforce
orgIdscoping in the repository → write → append an audit record attributed to the trusted principal.
Database portability
Section titled “Database portability”One repository implementation serves both dialects because the two Drizzle schemas are kept structurally identical: ids and timestamps are TEXT (app-generated UUIDs, ISO-8601 strings), arrays/JSON are TEXT (JSON-encoded), and booleans are normalized. The Postgres driver bridges its instance into the libSQL-typed repository factory at a single boundary.