Governance and payments for AI agents on x402 and MPP (Stellar)
Multi-agent consensus · Spend policies · Escrow · x402 facilitator · Real-time dashboard
Sentinel is the governance layer. It answers whether a payment is allowed: multi-agent voting, spend rules (policy), and a clear approve or reject outcome. It does not move funds or call Trustless Work.
ShieldPay is the payments layer. After Sentinel approves, it funds escrow (Trustless Work), proxies HTTP to the hosted x402 facilitator (OpenZeppelin + Stellar on channels.openzeppelin.com), forwards verify / settle, releases or refunds escrow as needed, and coordinates MPP-style session logic for the MVP.
Together they form one stack; either piece can be discussed on its own for integrators.
Autonomous agents can burn API and on-chain budget in loops, retry storms, or bad deploys. Documented incidents run to tens of thousands of USD in days. Sentinel + ShieldPay aim to block or throttle before settlement, with alerts and operator controls (e.g. kill-switch) where the product specifies them.
| Area | Description |
|---|---|
| @oppialabs/sentinel-sdk | Shared types, policy engine, consensus coordinator, agent registry (no escrow) |
| ShieldPay API | Trustless Work escrow (fund / release / refund), proxy /verify · /settle to the hosted facilitator, MPP session hooks, built-in voting agents |
| MCP Server | 4 tools for Claude Code: request_payment, get_policy, get_transactions, register_agent |
| Dashboard | Next.js UI, Supabase Realtime for transactions, votes, MPP sessions, policies, agents |
| x402 | x402 v2, exact scheme, Stellar testnet/mainnet via hosted facilitator |
| Hosted Agents | LLM-backed consensus agents (OpenAI / Anthropic) with encrypted key storage |
| Notifications | Webhook (HMAC-SHA256) + Email via Resend; 5 event types |
| Data | Supabase: policies, agents, consensus config, transactions, votes, MPP sessions |
- Node.js 20+ (LTS recommended)
- npm 10+ (workspaces; root pins
packageManagerinpackage.json) - Supabase project (URL + anon key for dashboard, service role for API/SDK)
- Facilitator API key (testnet): Generate testnet key
Optional:
- Supabase CLI for
npm run supabase:start/npm run db:migratewhen using local or linked projects
-
Clone the repository
git clone https://github.com/Oppia-Software-Labs/sentinel.git cd sentinel -
Install dependencies
npm install
-
Build the workspace (compiles
@oppialabs/sentinel-sdkand Next apps)npm run build
-
Configure environment variables
Each app has its own
.env.example— copy it to.env.localand fill in the values:cp apps/shieldpay-api/.env.example apps/shieldpay-api/.env.local cp apps/dashboard/.env.example apps/dashboard/.env.local cp apps/shieldpay-mcp/.env.example apps/shieldpay-mcp/.env.local
File Purpose apps/shieldpay-api/.env.localFacilitator URL + API key, Trustless Work, Supabase service role, Soroban contract apps/dashboard/.env.localNEXT_PUBLIC_SUPABASE_URL,NEXT_PUBLIC_SUPABASE_ANON_KEYapps/shieldpay-mcp/.env.localSHIELDPAY_API_URL,SHIELDPAY_OWNER_ID,SHIELDPAY_AGENT_ID,SUPABASE_URL,SUPABASE_ANON_KEYHosted facilitator (testnet) — set at minimum:
OZ_RELAYER_URL=https://channels.openzeppelin.com/x402/testnet OZ_RELAYER_API_KEY=<your_key>
Do not commit
.envor.env.local. They are gitignored. -
Apply database migrations (when migrations exist in
supabase/migrations/)npm run supabase:start # optional: local Supabase npm run db:migrate # supabase db push
-
Start development
npm run dev
App Port URL Dashboard 3000 http://localhost:3000 ShieldPay API 4000 http://localhost:4000 Run a single app:
npm run dev:dashboard npm run dev:api
The MCP server exposes ShieldPay to Claude Code as 4 callable tools.
-
Build and start
# production npm run build -w shieldpay-mcp npm run start -w shieldpay-mcp # or development (watch mode) npm run dev -w shieldpay-mcp
-
Required env vars (in
apps/shieldpay-mcp/.env.local)SHIELDPAY_API_URL=http://localhost:4000 SHIELDPAY_OWNER_ID=<your_owner_id> SHIELDPAY_AGENT_ID=<your_agent_id> SUPABASE_URL=<your_supabase_url> SUPABASE_ANON_KEY=<your_supabase_anon_key>
-
Wire into Claude Code — register with the Claude Code CLI:
claude mcp add shieldpay \ --scope user \ -e SHIELDPAY_API_URL=http://localhost:4000 \ -e SHIELDPAY_OWNER_ID=<your_owner_id> \ -e SHIELDPAY_AGENT_ID=claude-code \ -e SUPABASE_URL=<your_supabase_url> \ -e SUPABASE_ANON_KEY=<your_supabase_anon_key> \ -- node <absolute_path_to_sentinel>/apps/shieldpay-mcp/dist/index.js
Verify it connected:
claude mcp get shieldpayAvailable MCP tools:
request_payment,get_policy,get_transactions,register_agent.
| Endpoint | Method | Description |
|---|---|---|
/api/proxy/verify |
POST | Policy-only check; forwards to OZ Relayer if approved |
/api/proxy/settle |
POST | Full consensus + policy + escrow + x402 settlement. Supports resourceUrl for auto-fetch |
/api/agents |
GET | List agents for an owner (?ownerId=) |
/api/agents |
POST | Register agent (custom HTTP endpoint or hosted LLM) |
/api/agents |
DELETE | Deactivate an agent |
/api/agents/risk |
POST | Built-in risk agent (retry storm / velocity detection) |
/api/agents/cost |
POST | Built-in cost agent (daily / hourly / per-tx caps) |
/api/agents/logic |
POST | Built-in logic agent (LLM semantic validation via OpenAI) |
/api/agents/hosted |
POST | Invoke a registered hosted LLM agent |
/api/agents/test |
POST | Validate LLM config (API key + sample run) before registration |
/api/mpp |
POST | MPP session lifecycle: open, charge, close, kill, kill_all |
/api/notifications/dispatch |
POST | Internal notification dispatch (webhook + email) |
/api/openapi |
GET | OpenAPI 3.0 spec |
Browser-side proxies + UI helpers:
| Endpoint | Method | Description |
|---|---|---|
/api/agents |
POST / DELETE | Proxy to ShieldPay agent routes |
/api/policy |
POST | Mirror policy to Supabase |
/api/kill |
POST | Trigger kill-all MPP sessions |
/api/notifications/config |
GET / POST / DELETE | Manage notification configs |
/api/notifications/test |
POST | Test-dispatch a notification |
Turborepo + npm workspaces. Clear package boundaries:
| Layer | Location | Responsibility |
|---|---|---|
| On-chain governance | contracts/sentinel-governance |
Soroban contract (Rust, soroban-sdk): policy, quorum, agent registry, verdicts. Not an npm workspace; build and deploy with the Soroban/Stellar toolchain. |
| Governance library | packages/sentinel-sdk |
Types, verify / evaluate, SorobanClient, policy, consensus, Supabase mirror. Invokes the contract over RPC. No Trustless Work, no HTTP to the x402 facilitator. |
| Payments API | apps/shieldpay-api |
HTTP entry from agents. Calls @oppialabs/sentinel-sdk, then escrow (Trustless Work), facilitator (/verify, /settle), MPP routes, built-in voting agents. |
| MCP Server | apps/shieldpay-mcp |
MCP server for Claude Code. Exposes ShieldPay as 4 tools. |
| Dashboard | apps/dashboard |
Next.js UI + Supabase Realtime (browser client only). |
Dependency rule: apps/* may depend on packages/sentinel-sdk. The SDK must not depend on apps/* or call Trustless Work / facilitator URLs (those stay in ShieldPay API). The contract crate under contracts/ is independent of npm workspaces.
┌─────────────────────────────────────┐
│ apps/shieldpay-api │
Agents ──HTTP──► │ proxy · escrow · facilitator · MPP │
└──────────────┬──────────────────────┘
│ import
▼
┌─────────────────────────────────────┐
│ packages/sentinel-sdk │
│ types · soroban · policy · │
│ consensus · supabase mirror │
└──────────────┬──────────────────────┘
│ RPC / transactions
▼
┌─────────────────────────────────────┐
│ contracts/sentinel-governance │
│ Soroban wasm (testnet / deploy) │
└─────────────────────────────────────┘
┌────────────────────────┬────────────────────────┐
▼ ▼
apps/dashboard Supabase
(Realtime UI) (Postgres mirror)
apps/shieldpay-mcp
(MCP tools for Claude Code)
sentinel/
├── package.json # workspaces, turbo scripts, packageManager
├── turbo.json
├── tsconfig.json
├── package-lock.json
├── .gitignore
├── README.md
│
├── supabase/
│ └── migrations/
│ ├── 20260410120000_initial_schema.sql
│ ├── 20260410130000_mpp_sessions_lifecycle_columns.sql
│ ├── 20260410140000_transactions_add_soroban_tx_id.sql
│ ├── 20260410150000_mpp_sessions_owner_id_to_text.sql
│ └── 20260410160000_owner_id_to_text.sql
│
├── contracts/
│ └── sentinel-governance/ # Soroban smart contract (Rust cdylib)
│ ├── Cargo.toml # soroban-sdk 25.x
│ └── src/
│ ├── lib.rs # contract entry
│ ├── types.rs
│ ├── errors.rs
│ └── test.rs
│
├── packages/
│ └── sentinel-sdk/ # @oppialabs/sentinel-sdk — publishable-style package
│ ├── package.json
│ ├── tsconfig.json
│ └── src/
│ ├── index.ts # verify(), evaluate(), re-exports
│ ├── types.ts # shared domain types
│ ├── soroban/ # SorobanClient, loadSorobanConfig
│ ├── policy/ # evaluatePolicy (engine)
│ ├── consensus/ # coordinator, registry, quorum
│ └── supabase/ # mirrorTransaction, mirrorVotes, mirrorAgent, mirrorPolicy
│
└── apps/
├── shieldpay-api/ # Next.js 15, port 4000
│ ├── .env.example
│ ├── README.md # API docs (endpoints, env vars)
│ └── src/
│ ├── app/
│ │ ├── docs/page.tsx # Swagger UI
│ │ └── api/
│ │ ├── openapi/route.ts # OpenAPI spec
│ │ ├── proxy/verify/route.ts
│ │ ├── proxy/settle/route.ts
│ │ ├── agents/route.ts # register + list + deactivate agents
│ │ ├── agents/risk/route.ts
│ │ ├── agents/cost/route.ts
│ │ ├── agents/logic/route.ts
│ │ ├── agents/hosted/route.ts
│ │ ├── agents/test/route.ts
│ │ ├── mpp/route.ts
│ │ └── notifications/dispatch/route.ts
│ └── lib/
│ ├── escrow/trustless-work.ts # fund / release / refund
│ ├── mpp/session-manager.ts # MPP lifecycle + Supabase mirror
│ └── supabase/server.ts # service role client
│
├── shieldpay-mcp/ # MCP server for Claude Code
│ ├── package.json
│ ├── .env.example
│ └── src/
│ └── index.ts # 4 MCP tools
│
└── dashboard/ # Next.js 15, port 3000
└── .env.example
| Script | Description |
|---|---|
npm run dev |
Turbo dev (dashboard, shieldpay-api, SDK watch) |
npm run build |
Production build for all packages that define build |
npm run dev:api |
turbo dev --filter=shieldpay-api |
npm run dev:dashboard |
turbo dev --filter=dashboard |
npm run supabase:start |
supabase start |
npm run supabase:stop |
supabase stop |
npm run db:migrate |
supabase db push |
| Command | Description |
|---|---|
npm run build -w shieldpay-mcp |
Compile MCP server |
npm run start -w shieldpay-mcp |
Run compiled MCP server |
npm run dev -w shieldpay-mcp |
Run MCP server in watch mode |
| Technology | Role |
|---|---|
| Next.js 15 | App Router for shieldpay-api and dashboard |
| React 19 | UI |
| TypeScript 5.7 | Shared typing across workspaces |
| Turborepo | Task orchestration |
| npm workspaces | @oppialabs/sentinel-sdk linked via file:../../packages/sentinel-sdk |
| Technology | Role |
|---|---|
Soroban (contracts/sentinel-governance) |
On-chain policy, quorum, agent registry, verdicts; invoked by @oppialabs/sentinel-sdk over RPC |
| Supabase | Postgres + Realtime for transactions, votes, sessions, policies |
| Trustless Work | Escrow API used from ShieldPay API after Sentinel approves (fund / release / refund) |
| @stellar/mpp | MPP flows on Stellar (with compatible @stellar/stellar-sdk / mppx peers) |
| Resend | Email delivery for notifications |
| OpenAI / Anthropic | Hosted LLM agents (gpt-4o-mini, claude-* models) for consensus voting |
| Item | Detail |
|---|---|
| Hosted facilitator | https://channels.openzeppelin.com/x402/testnet (testnet) |
| Endpoints | /verify, /settle, /supported (x402 v2) |
| Auth | Authorization: Bearer <OZ_RELAYER_API_KEY> |
Self-hosting a Relayer + plugin is optional; see OpenZeppelin facilitator guide.
Agent → HTTP → ShieldPay API (proxy)
↓
@oppialabs/sentinel-sdk: verify (policy) or evaluate (policy + consensus)
↓
Soroban contract (`contracts/sentinel-governance`) via RPC / txs
↓
If reject → response to agent (no escrow)
If approve → ShieldPay: Trustless Work fund-escrow
↓
HTTPS → hosted x402 facilitator (/verify or /settle as designed)
↓
Stellar settlement → ShieldPay: release or refund escrow
- API template:
apps/shieldpay-api/.env.example - Dashboard template:
apps/dashboard/.env.example - MCP template:
apps/shieldpay-mcp/.env.example - Facilitator docs: Built on Stellar x402
Required groups:
- ShieldPay API — facilitator base URL + API key, Trustless Work, Supabase service role,
STELLAR_NETWORK, optional notification vars. - Dashboard — public Supabase URL and anon key only.
- MCP Server —
SHIELDPAY_API_URL,SHIELDPAY_OWNER_ID,SHIELDPAY_AGENT_ID,SUPABASE_URL,SUPABASE_ANON_KEY.
| Doc | Purpose |
|---|---|
| apps/shieldpay-api/README.md | ShieldPay API endpoint docs |
| apps/shieldpay-mcp/README.md | MCP server setup and tool reference |
- Fork the repository and create a branch (
feature/…orfix/…). - Keep changes scoped; match existing TypeScript and Next patterns.
- Run
npm run buildbefore opening a PR. - Open a Pull Request against the main development branch.
Open an issue on GitHub for bugs or integration questions.
Built by Oppia Labs