Quickstart
Get Taps running locally in under 30 seconds with Docker Compose.
1. Clone and start
git clone git@github.com:l1feai/taps.git cd taps docker compose up -d
2. Open the dashboard
Dashboard runs at http://localhost:3099. API at http://localhost:8080.
3. Create your first tap
curl -X POST http://localhost:8080/v1/taps \
-H "Content-Type: application/json" \
-d '{
"title": "Deploy v3.1 to production",
"priority": "critical",
"tap_type": "approval",
"agent": { "id": "deploy-bot", "name": "Deploy Bot" },
"risk_level": "high"
}'4. Approve it
Open the dashboard, find your tap in the inbox, and swipe right or click Approve. Or use the API:
curl -X POST http://localhost:8080/v1/taps/{id}/respond \
-H "Content-Type: application/json" \
-d '{"payload": {"type": "selection", "option_key": "approve"}, "source": "cli"}'API Reference
All endpoints are under /v1/. Authentication uses dev mode (no auth required) or OpenAgent sessions in production.
/v1/tapsCreate a new tap/v1/tapsList taps (with ?status= filter)/v1/taps/{id}Get tap detail/v1/taps/{id}/respondApprove or deny a tap/v1/taps/{id}Cancel a tap/v1/taps/{id}/eventsGet tap audit events/v1/routing-rulesList routing rules/v1/routing-rulesCreate routing rule/v1/routing-rules/{id}Delete routing rule/v1/escalation-policiesList escalation policies/v1/escalation-policiesCreate escalation policy/v1/streamWebSocket event stream/healthHealth checkCore Concepts
Tap
A decision request from an agent to a human. Contains a title, priority, risk level, approval policy, and response options. Created via POST /v1/taps.
Priority
Four levels: critical, high, normal, low. Determines inbox sort order and notification urgency. Critical taps trigger bell badge notifications.
Risk Level
Five levels: none, low, medium, high, critical. Displayed as a visual indicator on tap cards. Used in routing conditions for escalation.
Tap Type
Five types: approval (yes/no), choice (multiple options), input (freeform text), acknowledgment (just confirm), form (multi-field). Determines the response UI.
Principal
The authenticated identity making a request. Can be a human (via AccessKit/Omerta) or an agent (via OpenAgent session). Dev mode uses a local principal.
Routing Rule
A condition → action pair that processes taps when they're created. Conditions: priority threshold, agent match, tag match. Actions: route to user, require multi-approval, elevate priority.
Escalation Policy
A series of steps triggered when a tap isn't responded to. Steps: remind, route to backup, elevate priority, auto-deny, auto-approve. Each step has a delay in seconds.
Authentication
Taps supports 4 authentication paths, evaluated in order:
x-accesskit-context header from Omerta sidecar. Canonical in platform deployments.
Authorization: Bearer {session_jwt}. OpenAgent or human JWT sessions.
Authorization: OpenAgent {signature}. DID-based challenge-response.
TAPS_DEV_MODE=true. No auth required. Returns a local deterministic principal.
Routing Rules
Route taps based on conditions. Rules are evaluated in order by their order field.
{
"name": "High-value multi-approval",
"condition": {
"type": "priority_at_least",
"priority": "high"
},
"action": {
"type": "require_multi_approval",
"min_approvers": 2
},
"order": 1,
"enabled": true
}Condition Types
priority_at_least— matches taps at or above a priorityfrom_agent— matches taps from a specific agent IDhas_tag— matches taps with a specific tag
Action Types
route_to_user— route to a specific user (UUID)require_multi_approval— require N approverselevate_priority— bump to a higher prioritysuppress— drop the tap silently
Escalation Policies
Define what happens when taps aren’t responded to in time.
{
"name": "Standard Escalation",
"steps": [
{ "delay_secs": 0, "action": { "type": "remind" } },
{ "delay_secs": 900, "action": { "type": "remind" } },
{ "delay_secs": 1800, "action": { "type": "elevate_priority", "to": "critical" } },
{ "delay_secs": 3600, "action": { "type": "auto_deny" } }
]
}WebSocket Stream
Real-time event stream at ws://localhost:8080/v1/stream. Per-tenant isolation — events are scoped to the authenticated principal’s org.
const ws = new WebSocket("ws://localhost:8080/v1/stream");
ws.onmessage = (msg) => {
const event = JSON.parse(msg.data);
console.log(event.event_type, event.tap_id);
// "tap.created", "tap.responded", "tap.expired", "tap.cancelled"
};Docker Deployment
The Docker Compose stack includes PostgreSQL, the Rust API, and the Next.js dashboard.
Development
docker compose up -d # Dashboard: http://localhost:3099 # API: http://localhost:8080
Production (with automatic HTTPS)
TAPS_DOMAIN=taps.yourdomain.com \ docker compose -f docker-compose.prod.yml up -d
Environment Variables
TAPS_DEV_MODEEnable dev mode (no auth required)falseTAPS_DATABASE_URLPostgreSQL connection stringpostgres://localhost/tapsTAPS_BIND_ADDRAPI bind address0.0.0.0:8080RUST_LOGLog levelinfo