Quickstart
From a fresh checkout to your first enforced decision. Every command below is copy-pasteable and matches the repository's package.json scripts.
1. Install and configure
ActPass is a Next.js app with a Postgres (Drizzle) backend. Install dependencies, then create your .env file. It must be .env; ActPass ignores .env.local. npm run db:setup scaffolds it for you, or copy .env.example by hand.
npm install
npm run db:setup # interactive: scaffolds .env (POSTGRES_URL etc.)The variables that matter on day one (all verified against .env.example):
| Variable | Purpose |
|---|---|
POSTGRES_URL | Postgres connection string. Required. |
AUTH_SECRET | Session signing secret. Required. |
BASE_URL | App URL, e.g. http://localhost:3000. |
ACTPASS_API_KEYS | Dev-only gateway keys as <key>:<tenantId> pairs, e.g. sk_demo_a:1. Production uses the DB-backed key store (POST /api/v1/keys). |
ACTPASS_DEFAULT_MODE | Per-tenant default mode: monitor | warn | enforce | strict (default enforce). |
ACTPASS_SIGNING_KEY_JWK | Ed25519 private JWK for passport signing. Optional in dev (ephemeral key is generated); set it in production. |
2. Migrate and seed the database
npm run db:migrate # apply Drizzle migrations (also runs on `npm run dev` via predev)
npm run db:seed # dev seed - creates the login below
npm run db:seed:actpass # optional: demo ActPass data (agents, policies, evidence)The dev seed creates a login you can use immediately: email test@test.com, password admin123. The seed refuses to run in production, precisely because that credential is public.
npm run dev # http://localhost:3000 - sign in as test@test.com / admin1233. Get an API key
Create a gateway key from the dashboard or via POST /api/v1/keys (shown once, stored hashed). For a purely local run, the ACTPASS_API_KEYS dev pair from step 1 works as a bearer token too.
export ACTPASS_API_KEY="sk_demo_a" # or an apk_... key minted via POST /api/v1/keys4. Make your first preflight call
Ask ActPass whether an action should proceed. Nothing executes here: preflight is a pure decision.
curl -X POST http://localhost:3000/api/v1/actions/preflight \
-H "Authorization: Bearer $ACTPASS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tool": "stripe.refund.create",
"resource": "stripe:charge:ch_123",
"args": { "amount": 4900, "currency": "usd" },
"agent_id": "support_agent",
"user_id": "user_456",
"goal": "resolve_refund_request",
"mode": "monitor"
}'{
"decision": "deny",
"reason_code": "tool.unknown",
"risk_tier": "critical",
"tool_manifest_hash": "",
"policy_hash": "",
"evidence_event_id": "184",
"explain": {
"summary": "Tool stripe.refund.create is not in the approved manifest registry.",
"matched_rules": [],
"next_steps": ["blocked"]
}
}That deny is the product working. A fresh tenant has no approved tool manifests and no policies, so ActPass fails closed, and the decision is already sealed in the evidence chain (evidence_event_id).
To flip it to allow, register the tool manifest (POST /api/v1/tools/ingest) and create a starter policy in Dashboard → Policies, then re-run the same curl. (npm run db:seed:actpasssets up a working demo tenant if you'd rather start from that.)
5. Wrap a real action with the SDK
guard() combines the decision and the execution: your execute callback only runs when the decision is allow (or warn).
npm install @actpass/sdkimport { createActPass } from '@actpass/sdk';
const actpass = createActPass({
apiKey: process.env.ACTPASS_API_KEY!,
agentId: 'support_agent',
baseUrl: 'http://localhost:3000', // omit to use the hosted API
});
const { decision, result } = await actpass.guard({
goal: 'resolve_refund_request',
tool: 'stripe.refund.create',
resource: 'stripe:charge:ch_123',
args: { amount: 4900, currency: 'usd' },
mode: 'enforce',
execute: async () => stripe.refunds.create({ charge: 'ch_123', amount: 4900 }),
});
if (decision.decision !== 'allow') {
console.log('Blocked:', decision.reason_code, decision.explain.summary);
}6. Roll out with modes
Adoption is gradual by design. Start in monitor, watch the dashboard, then enforce.
| Mode | Behavior | Use it when |
|---|---|---|
monitor | Decisions are recorded but nothing is blocked. | First week: learn what your agents actually do. |
warn | Violations surface as warnings; actions still proceed. | Tuning policies with your team watching. |
enforce | Denies block. require_approval pauses for a human. | Production default. |
strict | Enforce, plus high/critical-risk tools require a passport. | Payments, deploys, data exports. |
monitor for a few days, review what would have been blocked under enforce in the dashboard, fix the false positives in their policy, and flip the switch with confidence.