# PatchPass – Agent Guidelines ## What is PatchPass? **A human approval layer for AI agents.** Agents submit structured change requests (code diffs, config updates, custom values); humans review and approve them in the browser; agents then verify the platform-signed decision through the API before applying anything. Packaged as a single `docker compose` stack. --- ## Repo layout ``` Backend/ Node.js + TypeScript API (rjweb-server) src/ index.ts server bootstrap + static UI serving + notFound SPA fallback lib/ service layer + shared utilities ChangeRequestService.ts the request lifecycle — REST and MCP both call this AgentService.ts agent CRUD (human-owned) Authentication.ts session (human) + API key (agent) resolution Signing.ts HMAC-SHA256 approval receipts ChangeNormalization.ts diff normalization + content hashing Limits.ts rate/pending/agent-count limits Notifications.ts, WsHub.ts realtime notifications SystemCrons.ts expiry + auto-delete jobs DataManager.ts global (admin) settings mcp/ MCP JSON-RPC server + tools middlewares/, RouteAuth.ts routes/ api/ human-facing REST (auth, account, agents, change-requests, notifications, admin, global) v1/ agent-facing REST (/v1/change-requests) mcp.ts MCP endpoint (/mcp) ws.ts WebSocket (/api/ws/notifications) tests/ Vitest integration tests prisma/schema.prisma UI/ React + TypeScript + Tailwind (Vite), builds to UI/build Dockerfile docker-compose.yml .gitea/workflows/deploy.yml ``` --- ## Stack | Layer | Technology | |---|---| | Backend | Node.js + TypeScript (strict), rjweb-server | | ORM | Prisma 7 (`@prisma/adapter-pg`) | | Database | PostgreSQL | | Frontend | React + Tailwind CSS (Vite) | | Package manager | pnpm (Backend and UI are separate pnpm workspaces) | | Backend tests | Vitest | --- ## Development workflow ### Branch strategy ``` feature/ → dev → main ``` ### Running locally ```bash # Backend cd Backend pnpm dev # esbuild + node, http://localhost:5000 # UI (separate terminal) cd UI pnpm dev # vite on :3000, proxies /api and /v1 to :5000 ``` ### Before committing 1. **Backend lint:** `cd Backend && pnpm lint` 2. **Backend tests:** `cd Backend && pnpm test` 3. **UI lint:** `cd UI && pnpm lint` 4. **UI build check:** `cd UI && pnpm build` Never commit code that fails lint or tests. --- ## Key rules ### The service layer is the single source of truth `ChangeRequestService.ts` contains ALL request lifecycle logic and authorization. The REST routes (`routes/v1`, `routes/api`) and the MCP tools (`lib/mcp/tools`) are thin adapters that call it. **Do not duplicate authorization or business logic** in a route or tool — add it to the service. ### Request state machine States: `PENDING`, `CHANGES_REQUESTED`, `APPROVED`, `REJECTED`, `EXPIRED`, `CONSUMED`, `CANCELLED`. - Decisions are only allowed on `PENDING`. - Agent updates are only allowed on `PENDING` / `CHANGES_REQUESTED`. - `REQUEST_CHANGES` requires a comment (≤500 chars) and resets to `PENDING` on agent resubmit (`resubmitted=true`). - No mutation after `APPROVED`, `REJECTED`, `EXPIRED`, `CONSUMED`, or `CANCELLED`. - Approvals are single-use: `consume` moves `APPROVED → CONSUMED`. ### Signing Approve/reject decisions are signed with HMAC-SHA256 over a fixed canonical field order (see `Signing.ts`). The signature binds the decision to `content_hash`. Never reorder the canonical fields — it breaks every existing signature. ### Content hashing `computeContentHash` hashes `{title, description, normalizedChanges}` with key-sorted canonical JSON and LF-normalized diffs. Equivalent inputs (CRLF vs LF, key order) must hash identically; any semantic change must change the hash. Covered by tests. ### Limits `Limits.ts` centralizes: 15 requests/agent/hour, 5 agents/human, 1–10 pending/agent (default 5), expiry 60s–12h (default 30 min), auto-delete ≥7 days. Enforce through these helpers, not ad hoc. ### Auth - Humans: session cookie (`patchpass_session`), bcrypt passwords, optional TOTP 2FA. - Agents: one API key each, `x-api-key` header. Resolution is in `Authentication.ts`; routes use `requireSession` / `requireAgent` / `requireAdmin` from `RouteAuth.ts`. Disabled humans/agents are rejected. ### Admin First registered user is `ADMIN`. Global settings (`registration_enabled`, `requests_enabled`) live in `DataManager.ts`. Admin viewing another user's request payload is explicit and audited (`recordAudit`). Never remove the last admin. ### UTC & pagination All timestamps are UTC ISO strings at the API boundary. History and admin logs are paginated. --- ## Database migrations – MANDATORY rules > **Never use `prisma db push` or `prisma db pull` to evolve the schema.** When you change `prisma/schema.prisma`: 1. Create a migration: `cd Backend && pnpm migrate` (`prisma migrate dev`), give a short slug. 2. Commit the generated `prisma/migrations/_/migration.sql` with the schema change. 3. Never hand-edit an applied `migration.sql` — create a new migration. 4. Production/CI: `pnpm migrate:deploy`. Prisma 7: the datasource URL lives in `prisma.config.ts` via `env("DATABASE_URL")`, not in `schema.prisma`. The client uses the `PrismaPg` adapter — do not remove it. Run `pnpm generate` for TS types without a migration. --- ## General coding rules - TypeScript strict mode is on. Avoid `any` without reason (it is a lint warning). - Do not use `console.*` in the Backend. Use `createLogger(component)` from `lib/logger.ts`. - UI state uses React built-ins (Context + hooks) — no external state library. - Follow existing conventions: route handlers in `routes/`, shared logic in `lib/`, MCP tools in `lib/mcp/tools/`. --- ## Keeping CLAUDE.md and AGENTS.md in sync – MANDATORY `CLAUDE.md` (Claude Code) and `AGENTS.md` (all other AI agents) must always reflect the same rules. Any rule added, removed, or amended in one must be mirrored in the other **in the same commit**. If they drift, fix the gap before continuing.