# Agent Guidelines — Mosaic Stack ## Required Load Order 1. `~/.config/mosaic/SOUL.md` 2. `~/.config/mosaic/STANDARDS.md` 3. `~/.config/mosaic/AGENTS.md` 4. `~/.config/mosaic/guides/E2E-DELIVERY.md` 5. `AGENTS.md` (this file) 6. Runtime-specific guide: `~/.config/mosaic/runtime//RUNTIME.md` ## Project Context Mosaic Stack is a self-hosted, multi-user AI agent platform. It is a TypeScript monorepo with a NestJS gateway, Next.js dashboard, Pi SDK agent runtime, and Discord/Telegram plugin architecture. ### Stack - **API:** NestJS with Fastify (`apps/gateway`) - **Web:** Next.js 16 with React 19 (`apps/web`) - **ORM and database:** Drizzle ORM, PostgreSQL 17, and pgvector (`packages/db`) - **Authentication:** BetterAuth (`packages/auth`) - **Agent runtime:** Pi SDK (`apps/gateway`, `packages/mosaic`) - **Queue:** Valkey 8 (`packages/queue`) - **Build:** pnpm workspaces and Turborepo - **CI:** Woodpecker CI - **Observability:** OpenTelemetry and Jaeger ### Package Map | Package | Purpose | Key Dependencies | | ------------------ | ----------------------------- | -------------------------------- | | `apps/gateway` | NestJS API + WebSocket hub | Fastify, Socket.IO, Pi SDK, OTEL | | `apps/web` | Next.js dashboard | React 19, Tailwind | | `packages/types` | Shared TypeScript contracts | class-validator | | `packages/db` | Drizzle schema and migrations | drizzle-orm, postgres | | `packages/auth` | BetterAuth configuration | better-auth, @mosaicstack/db | | `packages/brain` | Structured data layer | @mosaicstack/db | | `packages/queue` | Valkey task queue and MCP | ioredis | | `packages/coord` | Mission coordination | @mosaicstack/queue | | `packages/mosaic` | Unified `mosaic` CLI and TUI | Ink, Pi SDK, commander | | `plugins/discord` | Discord channel plugin | discord.js | | `plugins/telegram` | Telegram channel plugin | Telegraf | ## Architecture and Code Conventions 1. Gateway is the single API surface; all clients connect through it. 2. Pi SDK is ESM-only; gateway and CLI code must remain ESM. 3. Use `"type": "module"`, NodeNext module resolution, and `.js` extensions in imports. 4. Keep typed Socket.IO events in `@mosaicstack/types` to enforce client/server contracts. 5. Import OTEL tracing before NestJS bootstrap (`import './tracing.js'`). 6. Use explicit `@Inject()` decorators in NestJS because tsx/esbuild does not emit decorator metadata. 7. Keep DTOs in `*.dto.ts` files at module boundaries. 8. BetterAuth owns authentication tables; their schema is defined in `@mosaicstack/db`. 9. Create a task-specific scratchpad for non-trivial work. ## Development Workflow Requirements: Node.js 20+, pnpm 10.6.2, and Docker Compose when optional local services are needed. ```bash pnpm install --frozen-lockfile pnpm preflight # Optional local queue service only; do not start the full Compose stack. docker compose up -d valkey ``` The pre-push hook requires: ```bash pnpm preflight && pnpm typecheck && pnpm lint && pnpm format:check ``` Software delivery also requires the applicable tests. Common repository commands are: ```bash pnpm typecheck # TypeScript checks across the workspace pnpm lint # ESLint across the workspace pnpm test # Checkout tests and package Vitest suites pnpm format:check # Prettier check pnpm build # Build all packages and applications ``` ## Branch Model and Merge Process — `main` and `next` (CANONICAL) **Every contribution targets `next` first. No exceptions.** Features, fixes, tests, docs, and policy changes all take the same route; urgency changes queue priority, never the route. Agents never commit to or merge into `main`. | Branch | Role | Who merges into it | | ------ | ---------------------------------------------------------------- | --------------------------------------------------------------------------- | | `next` | Integration trunk — the only PR target for contributions | The designated merge-gate agent, after all gates pass. Never the PR author. | | `main` | Stable/release line — receives promotion merges from `next` only | Jason only (or an agent he explicitly delegates for a named promotion). | ### Contribution sequencing (in order, no skipping) 1. **Issue first.** Work is tracked in a Gitea issue before a branch exists. The issue number appears in the branch name and the PR body. 2. **Branch from the current `origin/next` head.** Name it `feat/…`, `fix/…`, `docs/…`, or `test/…` with the issue number (e.g. `docs/1214-branch-process`). Record the base SHA in the PR body. 3. **Develop with evidence.** Applicable tests accompany the change. Hooks are never bypassed (`--no-verify` is prohibited). Stage explicit paths — never `git add -A`. 4. **Open the PR against `next`.** The body states: scope, base SHA, verification commands with results, and any known pre-existing failures on the base — documented, not retried to green and not absorbed silently. 5. **CI must be terminal-green on the exact head.** All bounded Woodpecker steps succeed (`verify-terminal-green` contract). Pipelines for fork PRs start `blocked`; a maintainer approves the run — approving CI is not approving the PR. 6. **Independent review. Self-merge is prohibited** — for every agent, on every PR, including trivial ones. Where the change touches protected or contract-bearing content, the reviewer verifies the exact head (exact-byte/exact-blob comparison), not a description of it. An `AMEND` verdict returns the PR to its author; the reviewer's gate stays held until a fresh exact head passes. 7. **Merge into `next`** happens only after CI green + review pass, pinned to the reviewed head SHA (a post-review push voids the review). 8. **Promotion `next` → `main`** is a deliberate, Jason-owned reconciliation merge — not part of any contribution's lifecycle. Contributors are done at step 7. ### Responsibilities - **Contributor** — base pinning, green CI, evidence in the PR body, responding to AMEND verdicts, never merging own work. - **Reviewer / merge gate** — independent verification on the exact head; holds and lifts gates; executes the merge into `next`. - **Orchestrator / adjudicator** — cross-PR sequencing, disposition when PRs collide, conflict adjudication. - **Jason** — `next` → `main` promotions, merge-authority grants, collaborator and token provisioning. Agents cannot grant themselves or each other any of these. ### Hotfixes and divergence - A hotfix follows the same path: branch from `next`, PR to `next`, gates, merge, then an expedited Jason-owned promotion if `main` needs it urgently. Committing the fix to `main` directly is prohibited even under pressure. - **Never land work on `main` that is not on `next`.** This has happened (issue #1152's goal controller reached `main` without reaching `next`) and every later PR paid for it. If it happens anyway: transplant the work onto a `next`-based branch with provenance-preserving commits (`git cherry-pick -x` or explicit SHA references in the messages), PR it through the normal gates, and let promotion re-align `main`. Do not hand-patch `main` to compensate. - Force-pushing a branch you do not own is prohibited; rebasing your own PR branch is fine before review, and voids any review already given. ## Database and Local Runtime Safety - Current local data-layer work uses in-process PGlite; leave `DATABASE_URL` unset. - PostgreSQL execution is held until KBN-101-00, KBN-101-03, and KBN-101-05 land. - Do not invoke a migration runner, initialization SQL, or the Compose PostgreSQL service from this checkout. - Do not start Gateway/Web or run root `pnpm dev` as a local PGlite route. The current dotenv loader can inherit a daemon PostgreSQL DSN; KBN-101-02 must make that path fail closed first. - Migration artifact generation is offline and does not authorize PostgreSQL access: ```bash pnpm --filter @mosaicstack/db db:generate ``` ## docs/TASKS.md — Schema (CANONICAL) The `agent` column specifies the required model for each task. **This is set at task creation by the orchestrator and must not be changed by workers.** | Value | When to use | Budget | | --------- | ----------------------------------------------------------- | -------------------------- | | `codex` | All coding tasks (default for implementation) | OpenAI credits — preferred | | `glm-5.1` | Cost-sensitive coding where Codex is unavailable | Z.ai credits | | `haiku` | Review gates, verify tasks, status checks, docs-only | Cheapest Claude tier | | `sonnet` | Complex planning, multi-file reasoning, architecture review | Claude quota | | `opus` | Major cross-cutting architecture decisions ONLY | Most expensive — minimize | | `—` | No preference / auto-select cheapest capable | Pipeline decides | Pipeline crons read this column and spawn accordingly. Workers never modify `docs/TASKS.md` — only the orchestrator writes it. **Full schema:** ``` | id | status | description | issue | agent | repo | branch | depends_on | estimate | notes | ``` - `status`: `not-started` | `in-progress` | `done` | `failed` | `blocked` | `needs-qa` - `agent`: model value from table above (set before spawning) - `estimate`: token budget e.g. `8K`, `25K`