Patchpass V1
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
# PatchPass
|
||||
|
||||
**A human approval layer for AI agents.**
|
||||
|
||||
> Review changes. Approve intent. Let agents proceed.
|
||||
|
||||
Agents submit structured change requests containing code diffs, configuration updates, or custom values. Humans review and approve them in the browser, then agents verify the platform-signed decision through the API before applying anything.
|
||||
|
||||
---
|
||||
|
||||
## How it works
|
||||
|
||||
```
|
||||
Agent PatchPass Human
|
||||
│ create_request ───────────► │ │
|
||||
│ (diffs/config/custom) │ normalize · hash · store │
|
||||
│ ◄─── request_id + URL ────────│ ──── notify (WS) ──────────► │ reviews in browser
|
||||
│ │ │ APPROVE / REJECT / REQUEST_CHANGES
|
||||
│ get_request ──────────────► │ ◄──── signed decision ──────│
|
||||
│ ◄─── state + receipt ─────────│ │
|
||||
│ consume_approval ─────────► │ mark CONSUMED (single-use) │
|
||||
│ ◄─── receipt (HMAC) ──────────│ │
|
||||
│ apply changes │ │
|
||||
```
|
||||
|
||||
- **Decisions are platform-signed.** Approvals and rejections carry an HMAC-SHA256 receipt bound to the exact reviewed content (`content_hash`). If the agent changes anything after approval, the receipt no longer matches.
|
||||
- **Approvals are single-use.** An agent must `consume` an approval before proceeding; it cannot be replayed.
|
||||
- **Two ways in for agents:** a REST API (`/v1/...`) and an MCP server (`/mcp`), both authenticated with a per-agent API key and backed by the same service layer.
|
||||
|
||||
## Request states
|
||||
|
||||
`PENDING` · `CHANGES_REQUESTED` · `APPROVED` · `REJECTED` · `EXPIRED` · `CONSUMED` · `CANCELLED`
|
||||
|
||||
No update is possible after approval, rejection, expiry, consumption, or cancellation. A `REQUEST_CHANGES` decision requires a comment and returns the request to the agent, which can `update_request` to resubmit (highlighted in the UI as **UPDATED**).
|
||||
|
||||
## Limits
|
||||
|
||||
| Limit | Value |
|
||||
|---|---|
|
||||
| Requests per agent per hour | 15 |
|
||||
| Agents per human | 5 |
|
||||
| Simultaneous pending requests per agent | 1–10 (human-configured, default 5) |
|
||||
| Request expiry | default 30 min, max 12 h |
|
||||
|
||||
## Tech stack
|
||||
|
||||
| Layer | Technology |
|
||||
|---|---|
|
||||
| Backend | Node.js + TypeScript, [rjweb-server](https://server.rjweb.dev) |
|
||||
| ORM | Prisma 7 (`@prisma/adapter-pg`) |
|
||||
| Database | PostgreSQL |
|
||||
| Frontend | React + TypeScript + Tailwind CSS (Vite), served by the backend |
|
||||
| Realtime | rjweb WebSocket channels |
|
||||
| Tests | Vitest |
|
||||
|
||||
## Repository layout
|
||||
|
||||
```
|
||||
Backend/ Node + TypeScript API (rjweb-server) + Prisma
|
||||
src/
|
||||
index.ts server bootstrap + static UI serving
|
||||
lib/ service layer, auth, signing, limits, crons, MCP tools
|
||||
routes/ REST (/api, /v1), MCP (/mcp), WebSocket (/api/ws)
|
||||
tests/ Vitest integration tests
|
||||
prisma/schema.prisma
|
||||
UI/ React + Tailwind frontend (builds to UI/build)
|
||||
Dockerfile multi-stage build (UI + backend)
|
||||
docker-compose.yml backend + postgres
|
||||
.gitea/workflows/ CI: build · lint · test · push image
|
||||
```
|
||||
|
||||
## Running locally
|
||||
|
||||
Prerequisites: Node 24+, pnpm, and Postgres (or Docker).
|
||||
|
||||
```bash
|
||||
# 1. Start Postgres (Docker)
|
||||
docker run -d --name patchpass-db \
|
||||
-e POSTGRES_USER=patchpass -e POSTGRES_PASSWORD=patchpass -e POSTGRES_DB=patchpass \
|
||||
-p 5433:5432 postgres:16-alpine
|
||||
|
||||
# 2. Backend
|
||||
cd Backend
|
||||
cp ../example.env .env # then edit DATABASE_URL / INSTANCE_SECRET
|
||||
pnpm install
|
||||
pnpm generate
|
||||
pnpm migrate # apply migrations
|
||||
pnpm dev # http://localhost:5000
|
||||
|
||||
# 3. UI (separate terminal, for hot-reload dev)
|
||||
cd UI
|
||||
pnpm install
|
||||
pnpm dev # http://localhost:3000 (proxies /api to :5000)
|
||||
```
|
||||
|
||||
For a production-style run, `cd UI && pnpm build` — the backend then serves `UI/build` at `/`.
|
||||
|
||||
### Tests
|
||||
|
||||
```bash
|
||||
cd Backend
|
||||
pnpm test # spins up against the test database (see vitest.config.ts)
|
||||
```
|
||||
|
||||
## Deploying
|
||||
|
||||
```bash
|
||||
cp example.env .env # set DATABASE_URL=...@db:5432/..., a strong INSTANCE_SECRET
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The backend applies migrations on boot and serves the UI. The first account to register becomes the **admin**.
|
||||
|
||||
## Connecting an agent
|
||||
|
||||
Create an agent in the UI, then use its API key.
|
||||
|
||||
**OpenClaw** — add to `~/.openclaw/openclaw.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"patchpass": {
|
||||
"transport": "streamable-http",
|
||||
"url": "https://your-host/mcp",
|
||||
"headers": { "x-api-key": "pp_agent_..." }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**REST**:
|
||||
|
||||
```bash
|
||||
curl -X POST https://your-host/v1/change-requests \
|
||||
-H "x-api-key: pp_agent_..." -H "Content-Type: application/json" \
|
||||
-d '{"title":"Bump timeout","changes":[{"type":"config","path":"timeout","before":30,"after":60,"content_type":"integer"}]}'
|
||||
```
|
||||
|
||||
Tell your agent: *before taking any consequential action, call `create_request`, wait for approval, then `consume_approval` before proceeding.*
|
||||
|
||||
## Privacy & data
|
||||
|
||||
Humans can export all their data as JSON and delete their account (cascading to agents, requests, and notifications) from **Settings**. Agent icon URLs are fetched once for validation and never stored. See the in-app Privacy Policy and Terms of Service.
|
||||
|
||||
## License
|
||||
|
||||
MIT-0
|
||||
Reference in New Issue
Block a user