Docs · Getting started
Quickstart
From an empty checkout to a real ALLOW, a real DENY and a real approval.
1 · Start Postgres and Redis
pnpm localnet:upPublished on 5432 and 6380. Port 6380 is deliberate: 6379 is usually a developer's own Redis, and nothing here should write into it.
2 · Apply migrations
DATABASE_URL="postgresql://bengar:bengar_dev_only@127.0.0.1:5432/bengar" \
pnpm --filter @bengar/gateway migrateA database behind on migrations fails confusingly: the Gateway refuses to serve an ALLOW it cannot record, which reads as a dependency being unavailable.
3 · Start the Gateway
pnpm --filter @bengar/gateway build
DATABASE_URL="postgresql://bengar_app:app_dev_only@127.0.0.1:5432/bengar" \
REDIS_URL="redis://127.0.0.1:6380" \
NODE_ENV=test LOG_LEVEL=error GATEWAY_PORT=8080 \
node -e 'import("./apps/gateway/dist/index.js").then(m=>m.main())'
curl -s http://127.0.0.1:8080/healthz4 · Provision a sandbox project
pnpm sandbox:provisionThis creates the things that have no self-service surface yet: a project, an API key, an agent, a signed permit and a policy. It prints export lines.
The API key is shown once and stored nowhere — the same rule a production key follows. Lose it and provision again.
5 · Your first ALLOW, and a DENY
cd examples/sandbox-node
pnpm allow # ALLOW — proceed. reason=allowed
pnpm deny # DENY — do not proceed. reason=policy_deniedSame agent, same permit, same resource; a larger amount. The refusal arrived as a value, not an exception — the system worked and said no.
6 · An approval
A larger amount again produces REQUIRE_APPROVAL. That is not an allow: an obligation is opened and the action must not proceed until a person discharges it.
AVAILABLE Approve or reject, with a passkey — /projects/:id/approvals/:id
Where: Approvals → an approval → Review and approve
First: APPROVER, an enrolled passkey, and a provisioned Custody approval key — all three now have a screen.
Requires: APPROVER
7 · Verify what happened
Every decision wrote an audit event. Fetch its proof with GET /v1/projects/:id/audit/:auditId/proof, and check it against an anchored root.
What this does not set up
- A chain. Authorization does not need one; anchoring does.
- Custody. Approval signing needs it; ordinary decisions do not.
- A Console login. The sandbox is API-side.