PlanVault is an AI agent execution runtime that adds fault-tolerant planning, BYOK secret injection, and human-in-the-loop approval gates to any AI agent stack without rewriting your existing tools or infrastructure.
- Fault-tolerant, auditable runs — every step is event-sourced; failed plans replay from the last committed state without re-running completed tool calls. Full run history is available via
GET .../historyfor debugging and compliance audit. - Secrets never enter prompts — API keys and credentials are stored encrypted and injected post-planning into tool call parameters as scoped references. The LLM sees a placeholder; the raw value is only bound at execution time.
- Human-in-the-loop approval gates — plans requiring sensitive actions (sending emails, writing to production databases, placing orders) can pause at a
confirm_plan_requiredcheckpoint until an operator approves or rejects via API.
Import any REST API into the PlanVault tool catalog by uploading an OpenAPI 3.x spec via the Admin API. No SDK required — PlanVault generates typed tool definitions automatically.
Wrap an existing LangGraph agent as a PlanVault HTTP tool so the governed planner can call it as one step within a larger execution plan, including retries, secret injection, and approval gates.
→ examples/02-langgraph-webhook/
Register a Node.js stdio MCP server with PlanVault so its tools are available to any session in your organisation — with the same audit trail, RBAC, and secret injection as HTTP tools.
→ examples/03-mcp-host-nodejs/
Implement a FastAPI tool server that holds execution pending human approval before performing irreversible actions such as sending messages or modifying production records.
→ examples/04-hitl-approval-gate/
Trigger PlanVault sessions from an n8n automation and stream results back into your workflow — combining no-code orchestration with governed AI execution.
→ examples/05-n8n-integration/
Self-contained samples for the Runtime API, inbound webhooks, and MCP.
| Path | Description |
|---|---|
| frontend/react-chat | React + SSE chat client with plan graph, slots, HITL modal, and signal delivery |
| webhooks/kafka-trigger | Kafka consumers → HMAC-signed inbound webhook (Python, Java, Scala) |
| mcp/python-sqlite | stdio MCP server over SQLite (Python, FastMCP) |
| low-code/n8n | n8n workflow exports (inbound trigger + outbound tool demo) |
| scripts/bash-e2e | curl + jq session smoke test with HITL and signal delivery |
Copy .env.example to .env and fill values. PLANVAULT_BASE_URL defaults to https://api.planvault.ai (no trailing slash; examples strip it when building paths).
PlanVault can be deployed inside your own AWS or GCP VPC — your data never leaves your network. An air-gapped option is available for regulated environments.
See the security and deployment documentation for architecture details, BYOK encryption, and data residency guarantees. Docker Compose and Helm chart references are available to design partners — contact us at planvault.ai for access.
| Resource | URL |
|---|---|
| Product guide | planvault.ai/docs |
| API reference | planvault.ai/api-docs |
| Security & data residency | planvault.ai/security |
| Early access | planvault.ai |
All authenticated Runtime calls use /api/v1/projects/{projectId}/… with Authorization: Bearer <project-api-key>. Full OpenAPI spec: planvault.ai/api-docs.
- Project in the URL — all authenticated Runtime calls use
/api/v1/projects/{projectId}/…(theprojectIdmust match the project API key). There is noX-Project-Idheader. SetPLANVAULT_PROJECT_IDforscripts/bash-e2eandVITE_PLANVAULT_PROJECT_ID(or the UI field) for the React sample. - Send prompts —
POST /api/v1/projects/{projectId}/sessions/{id}/messageswith{"message":"..."}(optionalIdempotency-Key). The API answers202 AcceptedwithmessageIdwhile planning runs asynchronously. Track progress with SSEGET .../projects/{projectId}/sessions/{id}/chatorGET .../history— there is noGET .../messages/{messageId}/statuson current servers. Legacy paths withoutprojectIdandPOST .../promptare removed. - HITL / plan actions —
POST /api/v1/projects/{projectId}/sessions/{id}/actionswith{"action":"approve"},reject, orfill_slots(as inreact-chat/ bash script). wait_for_signalcallbacks — when the planner calls the nativewait_for_signaltool the session pauses and the SSE stream emits anawaiting_signalevent (tokenId,nodeId,expiresAt,onTimeout). An external system delivers the signal viaPOST /api/v1/projects/{projectId}/callbacks/{tokenId}withAuthorization: Bearer {tokenId}:{secret}(thesecretis available in the session's tool-call context). Body must be a JSON object. Response codes:200 {}(delivered),200 {"code":"SIGNAL_ALREADY_DELIVERED"}(idempotent),409 {"code":"SIGNAL_PAYLOAD_CONFLICT"}(different body for completed token),410 {"code":"SIGNAL_EXPIRED"}(token timed out),404(bad token or wrong secret). SSE emitssignal_received(tokenId,nodeId,payloadKeys) when the signal resumes the session, orsignal_timed_out(tokenId,nodeId,policy) on expiry.GET .../historypersists all three event types.- Tools — ingest into the org catalog with Admin
POST /admin/v1/orgs/{orgId}/tools(201 +toolId) andPUT /admin/v1/orgs/{orgId}/tools/{toolId}for full replace. Runtime (project key):GET /api/v1/projects/{projectId}/tools, integrations listGET .../tools?type=integration, enable/update withPUT .../tools/integrations/{alias}, plus batch endpoints — see API documentation. - Create session —
POST /api/v1/projects/{projectId}/sessionswith optionalcontextVars,externalUserId,tags,secrets(see OpenAPI; this repo sendscontextVarsas a JSON object, often{}). Sending the first user turn is a separatePOST .../messagescall. - Planner output: org/project settings set
plannerMode(e.g.structured_json,python_dsl). The Runtime SSEstarted/slots_requiredpayloads include a displayplanGraph({ "nodes": [...] }withkind:assignment,call,if,for,reply,fail). Clients can ignore unknown fields. - SSE: besides tool and confirmation events, the server may emit
slots_plan_summary(optional plain-language text shortly afterslots_required, uses org/projectutilityModelwhen set),run_phase(selecting_tools,planner_llm, …), andreplan.GET .../sessions/{id}/historypersists the same streamed shapes plus extra types that never appear on the live SSE connection (e.g.prompt,tool_selection,plan_summary,slots_cancelled,llm_reply). - Org LLM credentials (Admin API): organisations can store multiple named cloud vendor keys —
POST /admin/v1/orgs/{orgId}/llm/providerswith JSONname,vendor,apiKey(verify withPOST .../providers/{providerId}/verify; update withPATCH .../providers/{providerId}). Model allow-list entries can useprovider=cloud:{uuid}. Custom backends are under/admin/v1/orgs/{orgId}/llm/custom-providers(custom:{uuid}in models). Discover models viaGET .../custom-providers/{providerId}/models. Full route tables: API documentation. - HTTP errors from the API use RFC 7807
application/problem+json(e.g. admin/planner may returntype:urn:planvault:problem:MODEL_UNSUPPORTED_FEATUREwhen structured JSON is forced but the model does not support it; deleting an org tool still referenced by saved tool scenarios withoutconfirmDeleteScenarios=truemay returnurn:planvault:problem:TOOL_DELETE_BLOCKED_BY_SCENARIOS, HTTP 409). - Request correlation — You may send optional
X-Request-Id(orX-Correlation-ID, W3Ctraceparent). The API echoesX-Request-Idon responses and setsinstanceon error bodies to the same opaque id when known (use for support / log grep). Browserfetchcan read the header because CORS exposes response headers. The bash and React samples sendX-Request-Id; Kafka workers add one per outbound webhook POST. See the PlanVault api-docs. - Public inbound webhooks (
POST /api/v1/orgs/.../webhooks/...): many rejections (bad HMAC, wrong trigger, disabled trigger) return HTTP 404 with a generic problem body — do not assume 403. See API documentation.
This repository is licensed under the Apache License 2.0. See NOTICE for scope. CONTRIBUTING.md applies to contributions.
CI: GitHub only runs workflows from the repo root .github/workflows/. This tree includes .github/workflows/ci.yml for when planvault-examples is its own repository.