6.2 KiB
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/<name> → dev → main
Running locally
# 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
- Backend lint:
cd Backend && pnpm lint - Backend tests:
cd Backend && pnpm test - UI lint:
cd UI && pnpm lint - 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_CHANGESrequires a comment (≤500 chars) and resets toPENDINGon agent resubmit (resubmitted=true).- No mutation after
APPROVED,REJECTED,EXPIRED,CONSUMED, orCANCELLED. - Approvals are single-use:
consumemovesAPPROVED → 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-keyheader. Resolution is inAuthentication.ts; routes userequireSession/requireAgent/requireAdminfromRouteAuth.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 pushorprisma db pullto evolve the schema.
When you change prisma/schema.prisma:
- Create a migration:
cd Backend && pnpm migrate(prisma migrate dev), give a short slug. - Commit the generated
prisma/migrations/<timestamp>_<name>/migration.sqlwith the schema change. - Never hand-edit an applied
migration.sql— create a new migration. - 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
anywithout reason (it is a lint warning). - Do not use
console.*in the Backend. UsecreateLogger(component)fromlib/logger.ts. - UI state uses React built-ins (Context + hooks) — no external state library.
- Follow existing conventions: route handlers in
routes/, shared logic inlib/, MCP tools inlib/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.