Files
patchpass/AGENTS.md
T
Space-Banane 7e05dd918c
Deploy / Build (push) Successful in 28s
Deploy / Test & Lint (push) Failing after 29s
Deploy / Build and Push Docker Image (push) Has been skipped
Patchpass V1
2026-07-18 20:14:44 +02:00

148 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```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, 110 pending/agent (default 5), expiry 60s12h (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/<timestamp>_<name>/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.