# 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>/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`
