Quickstart

Get Taps running locally in under 30 seconds with Docker Compose.

1. Clone and start

bash
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

bash
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:

bash
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.

POST/v1/tapsCreate a new tap
GET/v1/tapsList taps (with ?status= filter)
GET/v1/taps/{id}Get tap detail
POST/v1/taps/{id}/respondApprove or deny a tap
DELETE/v1/taps/{id}Cancel a tap
GET/v1/taps/{id}/eventsGet tap audit events
GET/v1/routing-rulesList routing rules
POST/v1/routing-rulesCreate routing rule
DELETE/v1/routing-rules/{id}Delete routing rule
GET/v1/escalation-policiesList escalation policies
POST/v1/escalation-policiesCreate escalation policy
GET/v1/streamWebSocket event stream
GET/healthHealth check

Core 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:

Path 0AccessKit Context

x-accesskit-context header from Omerta sidecar. Canonical in platform deployments.

Path 1Bearer Token

Authorization: Bearer {session_jwt}. OpenAgent or human JWT sessions.

Path 2OpenAgent Challenge

Authorization: OpenAgent {signature}. DID-based challenge-response.

Path 4Dev Mode

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.

json
{
  "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 priority
  • from_agent — matches taps from a specific agent ID
  • has_tag — matches taps with a specific tag

Action Types

  • route_to_user — route to a specific user (UUID)
  • require_multi_approval — require N approvers
  • elevate_priority — bump to a higher priority
  • suppress — drop the tap silently

Escalation Policies

Define what happens when taps aren’t responded to in time.

json
{
  "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.

javascript
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

bash
docker compose up -d
# Dashboard: http://localhost:3099
# API: http://localhost:8080

Production (with automatic HTTPS)

bash
TAPS_DOMAIN=taps.yourdomain.com \
  docker compose -f docker-compose.prod.yml up -d

Environment Variables

TAPS_DEV_MODEEnable dev mode (no auth required)false
TAPS_DATABASE_URLPostgreSQL connection stringpostgres://localhost/taps
TAPS_BIND_ADDRAPI bind address0.0.0.0:8080
RUST_LOGLog levelinfo