PuddleJumper is a governance control plane that sits between AI agents (or human operators) and production systems. Every action passes through an approval gate before being dispatched to its target connector.
Sign in via GitHub, Google, or Microsoft OAuth at /pj. Tokens are JWT-based with role + tenant scoping.
POST to /api/pj/execute with an intent, mode, and plan. The governance engine evaluates it and creates an approval request.
If a chain template is assigned, approval routes through sequential or parallel steps. Each step is decided independently. All steps at the same order must approve before the next order activates.
Approve or reject via the Admin UI or POST /api/approvals/:id/decide. Rejections are terminal — all subsequent steps are skipped.
Once fully approved, dispatch sends the action to a registered connector: GitHub, Slack, or a generic webhook. Retries use exponential backoff.
Use the Admin Dashboard for queue, chain, and dispatch visibility. Prometheus metrics at /metrics now include chain-step counters/latency and stuck-step alert signals.
# From monorepo root
pnpm install
cd apps/puddlejumper
# Set minimum env vars
export JWT_SECRET=dev-secret
export AUTH_ISSUER=puddle-jumper
export AUTH_AUDIENCE=puddle-jumper-api
# Start
npx tsx src/api/server.ts
# → http://localhost:3002/pj
# From monorepo root (/n8drive)
fly deploy --app publiclogic-puddlejumper
n8drive/
├── packages/core/ @publiclogic/core — JWT auth, middleware, CSRF, cookies
├── packages/vault/ @publiclogic/vault — Vault policy provider
├── apps/logic-commons/ @publiclogic/logic-commons — OAuth providers, session routes, audit store
├── apps/puddlejumper/ The governance control plane application
│ ├── public/ Static assets (admin.html, guide.html, workspace)
│ ├── src/api/ Express server, routes, middleware
│ │ ├── server.ts App factory + route wiring + health/ready endpoints
│ │ ├── routes/ auth, config, prr, access, governance,
│ │ │ approvals, chainTemplates, admin, webhookAction,
│ │ │ workspaceCollaboration, workspaceUsage
│ │ ├── rateLimit.ts SQLite-backed rate limiting
│ │ └── vaultRoutes.ts Vault integration endpoints
│ ├── src/engine/ Business logic
│ │ ├── approvalStore Approval CRUD + status machine
│ │ ├── chainStore Chain templates, steps, parallel progression
│ │ ├── workspaceStore Workspace + member management
│ │ ├── idempotencyStore Idempotent request handling
│ │ ├── dispatch DispatcherRegistry + dispatchers:
│ │ │ dispatchers/ GitHub, Slack, SharePoint, Webhook
│ │ ├── governanceEngine Policy evaluation + approval gate
│ │ └── approvalMetrics Prometheus-format counters & histograms
│ └── test/ 500+ tests for auth, governance, chains, dispatch
├── web/ Next.js frontend (Vercel)
│ └── src/app/ Pages: home, login, dashboard, governance,
│ approvals, admin, vault
├── ops/ Runbooks, DR plan, operational handoff
├── Dockerfile Multi-stage build (Fly.io)
└── fly.toml Deployment config (app: publiclogic-puddlejumper)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/login | public | Built-in login (dev/test) |
| GET | /api/auth/github/login | public | GitHub OAuth redirect |
| GET | /api/auth/google/login | public | Google OAuth redirect |
| GET | /api/auth/microsoft/login | public | Microsoft OAuth redirect |
| GET | /api/auth/status | public | Current auth state |
| GET | /api/session | public | Session info |
| POST | /api/refresh | public | Refresh JWT |
| GET | /api/identity | user | Current identity |
| POST | /api/auth/logout | public | Logout + revoke |
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/pj/execute | user | Submit action for governance evaluation |
| GET | /api/prompt | admin | System prompt |
| GET | /api/core-prompt | user | Core prompt |
| POST | /api/evaluate | deploy | Evaluate action against policies |
| GET | /api/pj/identity-token | optional | MS Graph identity exchange |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/approvals | user | List approvals (filter by status) |
| GET | /api/approvals/:id | user | Get approval detail |
| POST | /api/approvals/:id/decide | user | Approve or reject (chain-aware) |
| POST | /api/approvals/:id/dispatch | user | Dispatch approved action to connector |
| GET | /api/approvals/:id/chain | user | Chain progress for approval |
| GET | /api/approvals/count/pending | user | Count of pending approvals |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/chain-templates | admin | List all templates |
| GET | /api/chain-templates/:id | admin | Get single template |
| POST | /api/chain-templates | admin | Create template (supports parallel steps) |
| PUT | /api/chain-templates/:id | admin | Update template |
| DELETE | /api/chain-templates/:id | admin | Delete template |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/runtime/context | user | Runtime context |
| GET | /api/config/tiles | user | UI tiles config |
| GET | /api/config/capabilities | user | Capabilities list |
| GET | /api/capabilities/manifest | user | Full capability manifest |
| GET | /api/pj/actions | user | Available actions |
| GET | /api/admin/stats | admin | Operational dashboard stats |
| GET | /api/admin/audit | admin | Auth audit log |
| GET | /api/admin/audit/export | admin | Audit export (CSV/JSON) |
| GET | /api/workspace/usage | user | Workspace usage & limits |
| GET | /health | public | Health check (db + volume + secrets) |
| GET | /ready | public | Readiness probe (db ping) |
| GET | /metrics | token | Prometheus metrics |
Operational observability includes approval queue metrics, chain-step throughput/latency, and the ChainStepStuck24h alert runbook path for triage.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/prr/intake | optional | Submit PRR |
| GET | /api/prr | user | List PRRs |
| POST | /api/prr/:id/status | user | Update PRR status |
| POST | /api/prr/:id/close | user | Close PRR |
| POST | /api/access/request | optional | Submit access request |
| POST | /api/access/request/:id/status | user | Update access request status |
| POST | /api/access/request/:id/close | user | Close access request |
| POST | /api/pj/actions/webhook | user | Fire webhook action |
Chain templates support both sequential and parallel step routing. Steps sharing the same order value run in parallel.
N all activate simultaneously when order N is reachedN must be approved before order N+1 activates{
"name": "Dual-review then release",
"steps": [
{ "label": "Security Review", "approverRole": "security", "order": 0 },
{ "label": "Legal Review", "approverRole": "legal", "order": 0 },
{ "label": "Release Manager", "approverRole": "release", "order": 1 }
]
}
// Step 0: Security + Legal run in parallel
// Step 1: Release Manager runs only after both order-0 steps approve