Base URL: http://<bridge-host>:8080
All request and response bodies use application/json.
Protected API routes require a Bearer token or Basic authentication in the Authorization header. There are two authentication methods:
Obtain a session token via the login endpoint. Tokens expire after 8 hours.
Authorization: Bearer a1b2c3d4e5f6...
For postgres auth backend only. Create a personal API token via the dashboard or API, then use it with Basic authentication:
Authorization: Basic base64(username:token)
Where token is a personal API token (format: apat_...).
Public routes that do not require authentication:
POST /api/v1/auth/loginGET /api/v1/health/api/v1/internal/*
The following POST endpoints are exempt from user authentication. They are used by Skiff and Gate for internal communication:
POST /api/v1/sessions/{id}/transcriptPOST /api/v1/sessions/{id}/statusPOST /api/v1/sessions/{id}/proxy-log
Rate limiting: after 5 failed login attempts within 15 minutes, the account is locked for 30 minutes.
Most API endpoints are scoped to a team. The auth middleware resolves the active team using the X-Alcove-Team request header:
X-Alcove-Team: <team-id>
- If
X-Alcove-Teamis set, the middleware validates that the authenticated user is a member of that team. On success, the resolved team ID is used for all resource queries. If the user is not a member (and not an admin), the middleware falls back to the user's personal team. - If
X-Alcove-Teamis omitted, the user's personal team is used automatically.
Every user has a personal team created at signup. Shared teams can be created via the Teams API. Resources (sessions, workflows, credentials, catalog selections) belong to the active team and are not visible to other teams.
curl example:
# List sessions scoped to a specific team
curl http://localhost:8080/api/v1/sessions \
-H "Authorization: Bearer $TOKEN" \
-H "X-Alcove-Team: 550e8400-e29b-41d4-a716-446655440000"Authenticate and receive a session token.
Request body:
{
"username": "admin",
"password": "secret"
}Response (200):
{
"token": "a1b2c3d4e5f6...",
"username": "admin"
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Login successful |
| 400 | Invalid request body |
| 401 | Invalid credentials or account locked |
| 405 | Method not allowed (must be POST) |
curl example:
curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "secret"}'Pass the token in the Authorization header on all subsequent requests:
curl http://localhost:8080/api/v1/sessions \
-H "Authorization: Bearer a1b2c3d4e5f6..."Personal API tokens provide a way to authenticate CLI and API requests without using your password. They are only available with the postgres auth backend.
List current user's personal API tokens.
Response (200):
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"username": "admin",
"name": "laptop CLI",
"created_at": "2026-04-13T10:30:00Z",
"last_accessed_at": "2026-04-13T15:45:00Z"
}
]Create a new personal API token.
Request body:
{
"name": "laptop CLI"
}Response (201):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"username": "admin",
"name": "laptop CLI",
"token": "apat_a1b2c3d4e5f6789012345678901234567890",
"created_at": "2026-04-13T10:30:00Z"
}Important: The token field is only returned once at creation time for security reasons.
Revoke a personal API token.
Response (200):
{
"deleted": true
}Use the token as a password with Basic authentication:
curl http://localhost:8080/api/v1/sessions \
-u "admin:apat_a1b2c3d4e5f6789012345678901234567890"Or with explicit Basic auth header:
curl http://localhost:8080/api/v1/sessions \
-H "Authorization: Basic $(echo -n 'admin:apat_a1b2c3d4e5f6789012345678901234567890' | base64)"These endpoints are only available when AUTH_BACKEND=rh-identity. They allow SSO users to associate Token Based Registry (TBR) identities with their account for API authentication.
List the current user's TBR identity associations.
Response (200):
{
"associations": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "alice@redhat.com",
"tbr_org_id": "12345",
"tbr_username": "alice",
"created_at": "2026-04-08T10:00:00Z",
"updated_at": "2026-04-08T10:00:00Z"
}
]
}Create a new TBR identity association for the authenticated user.
Request body:
{
"tbr_org_id": "12345",
"tbr_username": "alice"
}Response (201):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "alice@redhat.com",
"tbr_org_id": "12345",
"tbr_username": "alice",
"created_at": "2026-04-08T10:00:00Z",
"updated_at": "2026-04-08T10:00:00Z"
}Status codes:
| Code | Description |
|---|---|
| 201 | Association created successfully |
| 400 | Invalid request body or missing fields |
| 409 | TBR identity already associated with a user |
Remove a TBR identity association. Users can only delete their own associations.
Response (200):
{
"deleted": true
}Status codes:
| Code | Description |
|---|---|
| 200 | Association deleted successfully |
| 404 | Association not found or not owned by user |
curl examples:
# List associations
curl http://localhost:8080/api/v1/auth/tbr-associations \
-H "X-RH-Identity: <base64-encoded-saml-identity>"
# Create association
curl -X POST http://localhost:8080/api/v1/auth/tbr-associations \
-H "Content-Type: application/json" \
-H "X-RH-Identity: <base64-encoded-saml-identity>" \
-d '{"tbr_org_id": "12345", "tbr_username": "alice"}'
# Delete association
curl -X DELETE http://localhost:8080/api/v1/auth/tbr-associations/550e8400-e29b-41d4-a716-446655440000 \
-H "X-RH-Identity: <base64-encoded-saml-identity>"Start a new session for execution. Bridge creates a session, dispatches it to a Skiff pod, and returns the session record.
The submitter is read from the X-Alcove-User header (set automatically by the auth middleware). If absent, defaults to "anonymous".
Request body:
{
"prompt": "Fix the failing test in cmd/bridge/main_test.go",
"repo": "https://github.com/example/myproject.git",
"provider": "anthropic",
"model": "claude-sonnet-4-20250514",
"timeout": 1800,
"budget_usd": 5.00,
"debug": false,
"scope": {
"services": {
"github": {
"repos": ["example/myproject"],
"operations": ["clone", "create_pr_draft", "read_prs"]
},
"jira": {
"repos": ["MYPROJECT"],
"operations": ["read_issues", "search_issues", "add_comment"]
}
}
}
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
prompt |
string | yes | The instruction for Claude Code | |
repo |
string | no | Git repository URL to clone | |
provider |
string | no | first configured | LLM provider name |
model |
string | no | provider default | Model override |
timeout |
int | no | 3600 | Session timeout in seconds |
budget_usd |
float | no | Maximum spend for this session | |
debug |
bool | no | false | Enable debug mode |
scope |
object | no | empty (no access) | Authorized external operations |
Response (201):
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"task_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"submitter": "admin",
"prompt": "Fix the failing test in cmd/bridge/main_test.go",
"repo": "https://github.com/example/myproject.git",
"provider": "anthropic",
"scope": {
"services": {
"github": {
"repos": ["example/myproject"],
"operations": ["clone", "create_pr_draft", "read_prs"]
}
}
},
"status": "running",
"started_at": "2026-03-25T14:30:00Z"
}Status codes:
| Code | Meaning |
|---|---|
| 201 | Session dispatched and created |
| 400 | Invalid body or missing prompt |
| 401 | Missing or invalid token |
| 500 | Dispatch failed |
curl example:
curl -X POST http://localhost:8080/api/v1/sessions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Add unit tests for the auth package",
"repo": "https://github.com/example/myproject.git",
"timeout": 1800
}'List sessions with optional filters. Results are ordered by started_at descending.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by outcome: running, completed, error, timeout, cancelled |
repo |
string | Filter by prompt text (substring match, case-insensitive). Note: named repo for compatibility but searches the prompt field. |
since |
string | Only sessions started at or after this timestamp (RFC 3339) |
until |
string | Only sessions started at or before this timestamp (RFC 3339) |
page |
int | Page number (default: 1) |
per_page |
int | Results per page, 1-100 (default: 50) |
Response (200):
{
"sessions": [
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"task_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"submitter": "admin",
"prompt": "Add unit tests for the auth package",
"provider": "anthropic",
"scope": { "services": {} },
"status": "completed",
"started_at": "2026-03-25T14:30:00Z",
"finished_at": "2026-03-25T14:45:12Z",
"exit_code": 0,
"duration": "15m12s",
"artifacts": [
{ "type": "pr", "url": "https://github.com/example/myproject/pull/42" }
]
}
],
"count": 1,
"total": 42,
"page": 1,
"per_page": 50,
"pages": 1
}curl example:
# List all completed sessions
curl "http://localhost:8080/api/v1/sessions?status=completed" \
-H "Authorization: Bearer $TOKEN"
# List sessions for a specific repo since a date
curl "http://localhost:8080/api/v1/sessions?repo=myproject&since=2026-03-01T00:00:00Z" \
-H "Authorization: Bearer $TOKEN"
# Paginate results (page 2, 20 per page)
curl "http://localhost:8080/api/v1/sessions?page=2&per_page=20" \
-H "Authorization: Bearer $TOKEN"Get full session detail including transcript and proxy log.
Response (200):
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"task_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"submitter": "admin",
"prompt": "Add unit tests for the auth package",
"provider": "anthropic",
"scope": { "services": {} },
"status": "completed",
"started_at": "2026-03-25T14:30:00Z",
"finished_at": "2026-03-25T14:45:12Z",
"exit_code": 0,
"duration": "15m12s",
"transcript": [
{
"type": "assistant",
"content": "I'll start by reading the existing tests...",
"ts": "2026-03-25T14:30:05Z"
}
],
"proxy_log": [
{
"timestamp": "2026-03-25T14:31:00Z",
"method": "POST",
"url": "https://api.anthropic.com/v1/messages",
"service": "anthropic",
"decision": "allow",
"status_code": 200,
"session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
]
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Session found |
| 400 | Missing session ID |
| 404 | Session not found |
curl example:
curl http://localhost:8080/api/v1/sessions/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
-H "Authorization: Bearer $TOKEN"Cancel a running session or delete a completed session.
Query parameters:
action=delete- Delete the session permanently (default is cancel)
Cancel a running session:
Sends a cancel signal via NATS and stops the Skiff pod.
Response (200):
{
"status": "cancelled",
"session": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}Delete a completed session:
Permanently removes the session record, transcript, and proxy log. Only sessions in terminal states (completed, error, timeout, cancelled) can be deleted.
Response (200):
{
"status": "deleted",
"session": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Session cancelled or deleted |
| 400 | Session not found, not running (for cancel), or not in terminal state (for delete) |
| 403 | Access denied (not session owner) |
curl examples:
# Cancel a running session
curl -X DELETE http://localhost:8080/api/v1/sessions/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
-H "Authorization: Bearer $TOKEN"
# Delete a completed session
curl -X DELETE "http://localhost:8080/api/v1/sessions/f47ac10b-58cc-4372-a567-0e02b2c3d479?action=delete" \
-H "Authorization: Bearer $TOKEN"Bulk delete sessions based on criteria. Only sessions in terminal states can be deleted.
Request body:
{
"status": "error",
"before": "7d"
}Parameters:
status(optional): Delete sessions with specific status (completed,error,timeout,cancelled)before(optional): Delete sessions finished before date/time (RFC3339) or duration (e.g.,7d,30d)ids(optional): Array of specific session IDs to delete
Response (200):
{
"deleted_count": 42
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Sessions deleted successfully |
| 400 | Invalid request parameters |
| 401 | Authentication required |
curl examples:
# Delete all error sessions older than 7 days
curl -X DELETE http://localhost:8080/api/v1/sessions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "error", "before": "7d"}'
# Delete specific sessions by ID
curl -X DELETE http://localhost:8080/api/v1/sessions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids": ["f47ac10b-58cc-4372-a567-0e02b2c3d479", "550e8400-e29b-41d4-a716-446655440000"]}'
# Delete all completed sessions before a specific date
curl -X DELETE http://localhost:8080/api/v1/sessions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "completed", "before": "2023-01-01T00:00:00Z"}'Retrieve the transcript for a session. Returns the full transcript as a JSON response. Skiff flushes transcript events to the database every 5 seconds, so polling this endpoint at a similar interval provides near-real-time updates for running sessions.
Response (200):
{
"session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"transcript": [
{
"type": "assistant",
"content": "Analyzing the code...",
"ts": "2026-03-25T14:30:05Z"
},
{
"type": "tool",
"tool": "Read",
"input": { "file_path": "/src/main.go" },
"ts": "2026-03-25T14:30:10Z"
}
]
}Client implementation note: The dashboard polls this endpoint every 5 seconds while the session status is running, and shows a live indicator. This is the same approach used for the proxy log tab. The ?stream=true query parameter activates an SSE endpoint on the server (returns Content-Type: text/event-stream), but the dashboard does not use it because both EventSource and fetch()+ReadableStream are incompatible with the Akamai + Turnpike proxy chain in OpenShift staging deployments.
Status codes:
| Code | Meaning |
|---|---|
| 200 | Transcript returned |
| 404 | Session or transcript not found |
curl example:
curl http://localhost:8080/api/v1/sessions/$SESSION_ID/transcript \
-H "Authorization: Bearer $TOKEN"Retrieve the Gate proxy log for a session. Returns all proxied requests with allow/deny decisions.
Response (200):
{
"session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"proxy_log": [
{
"timestamp": "2026-03-25T14:31:00Z",
"method": "POST",
"url": "https://api.anthropic.com/v1/messages",
"service": "anthropic",
"decision": "allow",
"status_code": 200,
"session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
},
{
"timestamp": "2026-03-25T14:32:00Z",
"method": "GET",
"url": "https://api.github.com/repos/example/myproject",
"service": "github",
"operation": "read",
"decision": "allow",
"status_code": 200,
"session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
]
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Proxy log returned |
| 404 | Session or proxy log not found |
These endpoints are called by Skiff and Gate sidecars to report data back to Bridge. They are not typically called by external clients.
Append transcript events to a session.
Request body:
{
"events": [
{
"type": "assistant",
"content": "I found the bug in line 42.",
"ts": "2026-03-25T14:35:00Z"
},
{
"type": "tool",
"tool": "Edit",
"input": { "file_path": "/src/main.go", "old_string": "foo", "new_string": "bar" },
"ts": "2026-03-25T14:35:05Z"
}
]
}Response (200):
{
"appended": 2
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Events appended |
| 400 | Invalid body or empty events array |
| 500 | Database error |
Update the outcome of a session. Typically sent by Skiff when the task finishes.
Request body:
{
"status": "completed",
"exit_code": 0,
"artifacts": [
{
"type": "pr",
"url": "https://github.com/example/myproject/pull/42"
},
{
"type": "commit",
"ref": "abc1234"
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
status |
string | yes | One of: completed, error, timeout, cancelled |
exit_code |
int/null | no | Process exit code |
artifacts |
array | no | Outputs produced by the task |
Response (200):
{
"updated": true
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Status updated |
| 400 | Invalid body or missing status |
| 404 | Session not found |
| 500 | Database error |
Append proxy log entries to a session. Called by Gate sidecars.
Request body:
{
"entries": [
{
"timestamp": "2026-03-25T14:31:00Z",
"method": "POST",
"url": "https://api.anthropic.com/v1/messages",
"service": "anthropic",
"decision": "allow",
"status_code": 200,
"session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
]
}Response (200):
{
"appended": 1
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Entries appended |
| 400 | Invalid body or empty entries array |
| 500 | Database error |
List configured LLM providers.
Response (200):
{
"providers": [
{
"name": "anthropic",
"type": "anthropic",
"model": "claude-sonnet-4-20250514",
"max_budget_usd": 10.0
},
{
"name": "vertex",
"type": "google-vertex",
"model": "claude-sonnet-4-20250514",
"max_budget_usd": 25.0
}
]
}curl example:
curl http://localhost:8080/api/v1/providers \
-H "Authorization: Bearer $TOKEN"Manage encrypted LLM provider credentials. Credential material is stored encrypted with AES-256-GCM and never returned in API responses.
List all credentials (without secrets).
Response (200):
{
"credentials": [
{
"id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
"name": "anthropic",
"provider": "anthropic",
"auth_type": "api_key",
"project_id": "",
"region": "",
"created_at": "2026-03-20T10:00:00Z",
"updated_at": "2026-03-20T10:00:00Z"
}
],
"count": 1
}Create a new credential.
Request body:
{
"name": "vertex-prod",
"provider": "google-vertex",
"auth_type": "service_account",
"credential": "{\"type\":\"service_account\",\"project_id\":\"my-project\",...}",
"project_id": "my-project",
"region": "us-central1"
}| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Display name (used for provider lookup) |
provider |
string | yes | Provider type: anthropic, google-vertex, github, gitlab, or jira |
auth_type |
string | yes | One of: api_key, service_account, adc, pat, basic |
credential |
string | yes | Raw credential material (API key or JSON service account key) |
project_id |
string | no | GCP project ID (Vertex only) |
region |
string | no | GCP region (Vertex only) |
api_host |
string | no | Custom API host URL (e.g., self-hosted GitLab instance) |
Response (201):
{
"id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
"name": "vertex-prod",
"provider": "google-vertex",
"auth_type": "service_account",
"project_id": "my-project",
"region": "us-central1",
"created_at": "2026-03-25T14:00:00Z",
"updated_at": "2026-03-25T14:00:00Z"
}Status codes:
| Code | Meaning |
|---|---|
| 201 | Credential created |
| 400 | Missing required fields or invalid body |
| 500 | Storage error |
curl examples:
# Create an Anthropic API key credential
curl -X POST http://localhost:8080/api/v1/credentials \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "anthropic",
"provider": "anthropic",
"auth_type": "api_key",
"credential": "sk-ant-..."
}'
# Create a GitHub PAT credential
curl -X POST http://localhost:8080/api/v1/credentials \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "github",
"provider": "github",
"auth_type": "pat",
"credential": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}'
# Create a JIRA Cloud credential (email:api_token for Basic auth)
curl -X POST http://localhost:8080/api/v1/credentials \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "jira",
"provider": "jira",
"auth_type": "basic",
"credential": "user@example.com:your-jira-api-token"
}'Get a single credential's metadata (without secret material).
Response (200):
{
"id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
"name": "anthropic",
"provider": "anthropic",
"auth_type": "api_key",
"project_id": "",
"region": "",
"created_at": "2026-03-20T10:00:00Z",
"updated_at": "2026-03-20T10:00:00Z"
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Credential found |
| 404 | Credential not found |
Delete a credential.
Response (200):
{
"deleted": true
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Credential deleted |
| 404 | Credential not found |
curl example:
curl -X DELETE http://localhost:8080/api/v1/credentials/$CRED_ID \
-H "Authorization: Bearer $TOKEN"Internal endpoint used by Gate sidecars to refresh LLM tokens. This is not protected by auth middleware. Gate calls this endpoint when an OAuth2 token (Vertex AI) nears expiry.
Request body:
{
"session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"refresh_secret": "session-token-value"
}Response (200):
{
"token": "ya29.a0AfH6SM...",
"token_type": "bearer",
"expires_in": 3600,
"provider": "google-vertex"
}For API key providers, token_type is "api_key" and expires_in is 0.
Status codes:
| Code | Meaning |
|---|---|
| 200 | Token acquired |
| 400 | Missing required fields |
| 500 | Token acquisition failed |
Schedules are defined in YAML agent definition files (via the schedule: field) and synced from agent repos. The API provides read-only access to synced schedules. To create, update, or delete schedules, edit the YAML files in your agent repos and trigger a sync.
List all schedules.
Response (200):
{
"schedules": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "nightly-tests",
"cron": "0 2 * * *",
"prompt": "Run the full test suite and fix any failures",
"repo": "https://github.com/example/myproject.git",
"provider": "anthropic",
"scope_preset": "",
"timeout": 3600,
"enabled": true,
"last_run": "2026-03-25T02:00:00Z",
"next_run": "2026-03-26T02:00:00Z",
"created_at": "2026-03-20T10:00:00Z"
}
],
"count": 1
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Schedules listed |
| 405 | Method not allowed (only GET is supported) |
| 500 | Database error |
curl example:
curl http://localhost:8080/api/v1/schedules \
-H "Authorization: Bearer $TOKEN"Get a single schedule.
Response (200): same shape as a single item in the list response.
Status codes:
| Code | Meaning |
|---|---|
| 200 | Schedule found |
| 404 | Schedule not found |
| 405 | Method not allowed (only GET is supported) |
User management is available only when Bridge uses the PostgreSQL auth backend. These endpoints are not registered when using the in-memory auth store.
List all users.
Response (200):
{
"users": [
{
"username": "admin",
"created_at": "2026-03-20T10:00:00Z"
}
],
"count": 1
}Create a new user.
Request body:
{
"username": "developer",
"password": "strong-password-here"
}Response (201):
{
"username": "developer",
"created": "true"
}Status codes:
| Code | Meaning |
|---|---|
| 201 | User created |
| 400 | Missing username or password |
| 409 | Username already exists |
curl example:
curl -X POST http://localhost:8080/api/v1/users \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"username": "developer", "password": "strong-password-here"}'Note: GET /api/v1/users/{username} is not supported. Only DELETE is available for individual users.
Delete a user.
Response (200):
{
"deleted": true
}Status codes:
| Code | Meaning |
|---|---|
| 200 | User deleted |
| 404 | User not found |
Change a user's password.
Request body:
{
"password": "new-strong-password"
}Response (200):
{
"updated": true
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Password changed |
| 400 | Missing password |
| 404 | User not found |
Health check endpoint. Does not require authentication.
Response (200):
{
"status": "healthy",
"runtime": "podman",
"db": true
}When the database is unreachable, returns status 503:
{
"status": "degraded",
"runtime": "podman",
"db": false
}Status codes:
| Code | Meaning |
|---|---|
| 200 | All systems healthy |
| 503 | Database unreachable (degraded) |
curl example:
curl http://localhost:8080/api/v1/healthTools are managed via YAML definitions in agent repos. The API provides read-only access to synced tools. Builtin tools (github, gitlab, jira) are always available.
List all registered tools (builtin and custom).
Response (200):
{
"tools": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "github",
"display_name": "GitHub",
"tool_type": "builtin",
"api_host": "https://api.github.com",
"operations": [
{ "name": "clone", "description": "Clone a repository", "risk": "read" },
{ "name": "read_prs", "description": "Read pull requests", "risk": "read" },
{ "name": "create_pr_draft", "description": "Create a draft pull request", "risk": "write" }
],
"created_at": "2026-03-20T10:00:00Z"
}
],
"count": 1
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Tools listed |
| 405 | Method not allowed (only GET is supported) |
curl example:
curl http://localhost:8080/api/v1/tools \
-H "Authorization: Bearer $TOKEN"Get a single tool by name.
Response (200): same shape as a single item in the list response.
Status codes:
| Code | Meaning |
|---|---|
| 200 | Tool found |
| 404 | Tool not found |
| 405 | Method not allowed (only GET is supported) |
curl example:
curl http://localhost:8080/api/v1/tools/github \
-H "Authorization: Bearer $TOKEN"Security profiles define per-tool access rules for sessions. They are managed via YAML definitions in agent repos (.alcove/security-profiles/*.yml). The API provides read-only access to synced profiles. To create, update, or delete profiles, edit the YAML files in your agent repos and trigger a sync.
List all security profiles.
Response (200):
{
"profiles": [
{
"id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
"name": "read-only-github",
"display_name": "Read-Only GitHub",
"description": "Clone and read GitHub repos, no write access",
"source": "user",
"tools": {
"github": {
"rules": [
{ "repos": ["*"], "operations": ["clone", "read_prs", "read_issues", "read_contents"] }
]
}
},
"created_at": "2026-03-20T10:00:00Z",
"updated_at": "2026-03-20T10:00:00Z"
},
{
"id": "c2d3e4f5-a6b7-8901-bcde-f12345678901",
"name": "repo-reader",
"display_name": "Repo Reader",
"description": "Read-only access to a specific repo",
"source": "yaml",
"source_repo": "https://github.com/org/task-definitions.git",
"source_key": ".alcove/security-profiles/repo-reader.yml",
"tools": {
"github": {
"rules": [
{ "repos": ["org/myproject"], "operations": ["clone", "read_prs", "read_contents"] }
]
}
},
"created_at": "2026-03-20T10:00:00Z",
"updated_at": "2026-03-20T10:00:00Z"
}
],
"count": 2
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Profiles listed |
| 405 | Method not allowed (only GET is supported) |
curl example:
curl http://localhost:8080/api/v1/security-profiles \
-H "Authorization: Bearer $TOKEN"Get a single profile by name.
Response (200): same shape as a single item in the list response.
Status codes:
| Code | Meaning |
|---|---|
| 200 | Profile found |
| 404 | Profile not found |
| 405 | Method not allowed (only GET is supported) |
Configure git repositories containing YAML agent definitions (.alcove/agents/*.yml). Agent repos are synced automatically every 15 minutes. When a team context is active (via the X-Alcove-Team header), agent repos are stored as team settings. Without a team context, they fall back to per-user settings.
Get agent repos for the active team (or the current user if no team context).
Response (200):
{
"repos": [
{
"url": "https://github.com/org/task-definitions.git",
"ref": "main",
"name": "Org Agents",
"enabled": true
}
]
}curl example:
curl http://localhost:8080/api/v1/user/settings/agent-repos \
-H "Authorization: Bearer $TOKEN"Set agent repos for the active team (or the current user if no team context). Replaces the entire list and triggers an immediate sync.
Request body:
{
"repos": [
{
"url": "https://github.com/org/task-definitions.git",
"ref": "main",
"name": "Org Agents",
"enabled": true
}
]
}Response (200): the saved repos array.
Status codes:
| Code | Meaning |
|---|---|
| 200 | Repos saved |
| 400 | Invalid request body |
| 401 | Authentication required |
| 500 | Storage error |
curl example:
curl -X PUT http://localhost:8080/api/v1/user/settings/agent-repos \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"repos": [
{
"url": "https://github.com/org/task-definitions.git",
"ref": "main",
"name": "Org Agents"
}
]
}'Agent definitions are YAML files discovered from registered agent repos. They define reusable, parameterized agents.
List all agent definitions from synced agent repos.
Response (200):
{
"agent_definitions": [
{
"name": "run-tests",
"prompt": "Run the full test suite and fix any failures",
"repo": "https://github.com/org/myproject.git",
"provider": "anthropic",
"model": "claude-sonnet-4-20250514",
"timeout": 1800,
"budget_usd": 5.0,
"profiles": ["read-only-github"],
"tools": ["github"],
"schedule": "0 2 * * *",
"source_repo": "https://github.com/org/task-definitions.git",
"source_file": ".alcove/agents/run-tests.yml"
}
]
}Get a single agent definition by name.
Run an agent definition immediately as a new session. Returns the created session.
Response (201): same shape as POST /api/v1/sessions (POST).
Trigger an immediate sync of all agent repos (normally happens every 15 minutes).
Response (200):
{
"synced": true
}Agent definitions with event triggers (e.g., GitHub issues.opened) support two delivery modes via the delivery_mode field in the trigger configuration:
polling(default) — Alcove polls the GitHub Events API every 60 seconds. No webhook setup required. Suitable for local development and environments without a public URL.webhook— GitHub pushes events toPOST /api/v1/webhooks/github. Requires a publicly accessible Bridge URL and a configured webhook secret.
The trigger configuration supports an optional labels field (string array). When specified, the event is only dispatched if at least one of the listed labels is present on the issue or pull request. This acts as a safety gate to prevent unauthorized issues from triggering automated tasks.
trigger:
github:
events: [issues]
actions: [opened, labeled]
repos: [org/myproject]
labels: [ready-for-dev]If labels is omitted or empty, all matching events are dispatched.
See Configuration Reference for full details.
The trigger configuration supports an optional users field (string array). When specified, the event is only dispatched if the user who authored the comment or issue matches at least one of the listed GitHub usernames (case-insensitive). This prevents automated agents' own comments from re-triggering sessions and limits dispatch to trusted users.
trigger:
github:
events: [issues, issue_comment]
actions: [opened, created]
repos: [org/myproject]
labels: [ready-for-dev]
users: [bmbouter]If users is omitted or empty, all matching events are dispatched regardless of the event author.
See Configuration Reference for full details.
Starter templates for creating agent definitions.
List available starter templates.
Response (200):
{
"templates": [
{
"name": "basic-task",
"description": "A simple task with a prompt and repo",
"raw_yaml": "name: my-task\nprompt: |\n Your prompt here\nrepo: https://github.com/org/repo.git\ntimeout: 1800\n"
}
]
}Admin-only endpoints for system configuration. Requires the X-Alcove-Admin: true header (set by auth middleware for admin users).
Get the effective system LLM configuration (read-only). Returns the resolved configuration with source tracking for each field (env, config, or default). The system LLM is configured exclusively in alcove.yaml or via environment variables.
Response (200):
{
"provider": "anthropic",
"provider_source": "env",
"model": "claude-sonnet-4-20250514",
"model_source": "config",
"region": "",
"region_source": "default",
"project_id": "",
"project_id_source": "default",
"configured": true
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Settings returned |
| 403 | Admin access required |
curl example:
curl http://localhost:8080/api/v1/admin/settings/llm \
-H "Authorization: Bearer $TOKEN"This endpoint returns 405 Method Not Allowed. The system LLM configuration is read-only via the API. To change it, edit alcove.yaml or set BRIDGE_LLM_* environment variables and restart Bridge.
Status codes:
| Code | Meaning |
|---|---|
| 405 | Method not allowed (system LLM is config-file-only) |
Teams are the ownership unit in Alcove. Every resource belongs to a team, and every user belongs to one or more teams. A personal team is auto-created for each user at signup. Shared teams can be created for collaboration.
The X-Alcove-Team header scopes all API requests to a specific team (see Team Scoping above).
List all teams the authenticated user is a member of.
Response (200):
{
"teams": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "admin's workspace",
"is_personal": true,
"created_at": "2026-03-20T10:00:00Z"
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Platform Team",
"is_personal": false,
"created_at": "2026-04-01T10:00:00Z"
}
],
"count": 2
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Teams listed |
| 401 | Authentication required |
| 500 | Database error |
curl example:
curl http://localhost:8080/api/v1/teams \
-H "Authorization: Bearer $TOKEN"Create a new shared team. The authenticated user is added as the first member.
Request body:
{
"name": "Platform Team"
}| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Team display name |
Response (201):
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Platform Team",
"is_personal": false,
"created_at": "2026-04-01T10:00:00Z",
"members": ["admin"]
}Status codes:
| Code | Meaning |
|---|---|
| 201 | Team created |
| 400 | Missing name |
| 401 | Authentication required |
| 500 | Database error |
curl example:
curl -X POST http://localhost:8080/api/v1/teams \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Platform Team"}'Get a team's details including its member list. Requires team membership or admin access.
Response (200):
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Platform Team",
"is_personal": false,
"created_at": "2026-04-01T10:00:00Z",
"members": ["admin", "developer"]
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Team found |
| 401 | Authentication required |
| 403 | Access denied (not a member and not admin) |
| 404 | Team not found |
Rename a team. Personal teams cannot be renamed (returns 400).
Request body:
{
"name": "New Team Name"
}Response (200):
{
"updated": true
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Team renamed |
| 400 | Missing name, team not found, or personal team |
| 401 | Authentication required |
| 403 | Access denied |
Delete a team. Personal teams cannot be deleted (returns 400). Any running sessions for the team are cancelled before deletion.
Response (200):
{
"deleted": true
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Team deleted |
| 400 | Team not found or personal team |
| 401 | Authentication required |
| 403 | Access denied |
curl example:
curl -X DELETE http://localhost:8080/api/v1/teams/660e8400-e29b-41d4-a716-446655440001 \
-H "Authorization: Bearer $TOKEN"Add a user to a team. The user must exist. Cannot add members to personal teams.
Request body:
{
"username": "developer"
}Response (201):
{
"added": true
}Status codes:
| Code | Meaning |
|---|---|
| 201 | Member added |
| 400 | Missing username, user does not exist, or personal team |
| 401 | Authentication required |
| 403 | Access denied |
curl example:
curl -X POST http://localhost:8080/api/v1/teams/$TEAM_ID/members \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"username": "developer"}'Remove a user from a team. Cannot remove members from personal teams.
Response (200):
{
"removed": true
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Member removed |
| 400 | Member not found or personal team |
| 401 | Authentication required |
| 403 | Access denied |
curl example:
curl -X DELETE http://localhost:8080/api/v1/teams/$TEAM_ID/members/developer \
-H "Authorization: Bearer $TOKEN"List catalog sources with item counts for the team.
Response (200):
{
"sources": [
{
"source_id": "alcove-agents",
"name": "Alcove Agents",
"description": "Built-in agent collection",
"category": "agents",
"total_items": 12,
"enabled_items": 5
}
]
}curl example:
curl http://localhost:8080/api/v1/teams/$TEAM_ID/catalog \
-H "Authorization: Bearer $TOKEN"List all items within a catalog source, with per-team enabled state.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
search |
string | Filter items by name or description (case-insensitive substring match) |
Response (200):
{
"source_id": "alcove-agents",
"items": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"source_id": "alcove-agents",
"slug": "code-reviewer",
"name": "Code Reviewer",
"description": "Reviews pull requests for code quality",
"item_type": "agent",
"source_file": ".alcove/agents/code-reviewer.yml",
"synced_at": "2026-04-15T10:00:00Z",
"enabled": true
}
]
}Bulk toggle items within a catalog source for the team.
Request body:
{
"items": [
{ "slug": "code-reviewer", "enabled": true },
{ "slug": "test-runner", "enabled": false }
]
}Response (200):
{
"updated": true,
"source_id": "alcove-agents",
"count": 2
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Items updated |
| 400 | Missing or empty items array |
| 404 | Catalog source not found |
| 500 | Database error |
Toggle an individual catalog item for the team.
Request body:
{
"enabled": true
}Response (200):
{
"updated": true,
"source_id": "alcove-agents",
"item_slug": "code-reviewer",
"enabled": true
}Add a custom plugin repository to the team.
Request body:
{
"url": "https://github.com/org/custom-agents.git",
"ref": "main",
"name": "Custom Agents"
}Response (201):
{
"added": true,
"custom_plugins": [
{
"url": "https://github.com/org/custom-agents.git",
"ref": "main",
"name": "Custom Agents"
}
]
}Remove a custom plugin repository by index.
Response (200):
{
"removed": true,
"custom_plugins": []
}List all enabled agents (catalog items with item_type="agent") for the team. Useful for workflow authoring.
Response (200):
{
"agents": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"source_id": "alcove-agents",
"slug": "code-reviewer",
"name": "Code Reviewer",
"description": "Reviews pull requests for code quality",
"item_type": "agent",
"source_file": ".alcove/agents/code-reviewer.yml",
"synced_at": "2026-04-15T10:00:00Z",
"enabled": true
}
]
}curl example:
curl http://localhost:8080/api/v1/teams/$TEAM_ID/agents \
-H "Authorization: Bearer $TOKEN"Workflows define multi-step execution graphs with agent steps (Skiff pods) and bridge steps (deterministic actions like create-pr, await-ci, merge-pr). Workflows are defined in YAML agent definition files and synced from agent repos.
List all workflow definitions for the active team.
Response (200):
{
"workflows": [
{
"id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
"name": "review-and-merge",
"source_repo": "https://github.com/org/task-definitions.git",
"source_file": ".alcove/agents/review-and-merge.yml",
"team_id": "550e8400-e29b-41d4-a716-446655440000",
"source_key": "https://github.com/org/task-definitions.git::.alcove/agents/review-and-merge.yml",
"raw_yaml": "name: review-and-merge\nworkflow:\n ...",
"last_synced": "2026-04-15T10:00:00Z",
"workflow": [
{
"id": "code",
"agent": "alcove-agents/coder",
"repo": "https://github.com/org/myproject.git",
"outputs": ["branch"]
},
{
"id": "create-pr",
"type": "bridge",
"action": "create-pr",
"depends": "code",
"inputs": {
"repo": "org/myproject",
"branch": "{{steps.code.outputs.branch}}",
"base": "main",
"title": "Automated changes"
}
}
]
}
],
"count": 1
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Workflows listed |
| 500 | Database error |
curl example:
curl http://localhost:8080/api/v1/workflows \
-H "Authorization: Bearer $TOKEN" \
-H "X-Alcove-Team: $TEAM_ID"List workflow run executions for the active team.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status: pending, running, completed, failed, cancelled, awaiting_approval |
Response (200):
{
"workflow_runs": [
{
"id": "c2d3e4f5-a6b7-8901-bcde-f12345678901",
"workflow_id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
"status": "running",
"trigger_type": "manual",
"trigger_ref": "",
"current_step": "code",
"step_outputs": {},
"started_at": "2026-04-15T14:00:00Z",
"team_id": "550e8400-e29b-41d4-a716-446655440000",
"created_at": "2026-04-15T14:00:00Z"
}
],
"count": 1
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Runs listed |
| 500 | Database error |
curl example:
# List all running workflow runs
curl "http://localhost:8080/api/v1/workflow-runs?status=running" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Alcove-Team: $TEAM_ID"Trigger a new workflow run manually.
Request body:
{
"workflow_id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
"trigger_ref": ""
}| Field | Type | Required | Description |
|---|---|---|---|
workflow_id |
string | yes | The workflow definition ID to run |
trigger_ref |
string | no | Optional trigger reference (e.g., branch name, PR number) |
Response (201):
{
"id": "c2d3e4f5-a6b7-8901-bcde-f12345678901",
"workflow_id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
"status": "running",
"trigger_type": "manual",
"trigger_ref": "",
"step_outputs": {},
"started_at": "2026-04-15T14:00:00Z",
"team_id": "550e8400-e29b-41d4-a716-446655440000",
"created_at": "2026-04-15T14:00:00Z"
}Status codes:
| Code | Meaning |
|---|---|
| 201 | Workflow run created and started |
| 400 | Invalid body or missing workflow_id |
| 500 | Failed to start workflow run |
curl example:
curl -X POST http://localhost:8080/api/v1/workflow-runs \
-H "Authorization: Bearer $TOKEN" \
-H "X-Alcove-Team: $TEAM_ID" \
-H "Content-Type: application/json" \
-d '{"workflow_id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890"}'Get detailed information about a workflow run, including all step executions.
Response (200):
{
"workflow_run": {
"id": "c2d3e4f5-a6b7-8901-bcde-f12345678901",
"workflow_id": "b1c2d3e4-f5a6-7890-abcd-ef1234567890",
"status": "running",
"trigger_type": "manual",
"trigger_ref": "",
"current_step": "review",
"step_outputs": {
"code": {
"branch": "auto/fix-tests"
}
},
"started_at": "2026-04-15T14:00:00Z",
"team_id": "550e8400-e29b-41d4-a716-446655440000",
"created_at": "2026-04-15T14:00:00Z"
},
"steps": [
{
"id": "d3e4f5a6-b789-0123-cdef-456789012345",
"run_id": "c2d3e4f5-a6b7-8901-bcde-f12345678901",
"step_id": "code",
"session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "completed",
"outputs": { "branch": "auto/fix-tests" },
"iteration": 1,
"started_at": "2026-04-15T14:00:05Z",
"finished_at": "2026-04-15T14:15:30Z",
"type": "agent"
},
{
"id": "e4f5a6b7-8901-2345-def0-567890123456",
"run_id": "c2d3e4f5-a6b7-8901-bcde-f12345678901",
"step_id": "review",
"status": "running",
"iteration": 1,
"started_at": "2026-04-15T14:15:35Z",
"type": "agent",
"depends": "code"
}
]
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Run found |
| 400 | Missing run ID |
| 404 | Run not found |
curl example:
curl http://localhost:8080/api/v1/workflow-runs/$RUN_ID \
-H "Authorization: Bearer $TOKEN"Approve a workflow step that is awaiting approval. Steps with approval: required pause execution until explicitly approved.
Response (200):
{
"status": "approved",
"run_id": "c2d3e4f5-a6b7-8901-bcde-f12345678901",
"step_id": "deploy"
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Step approved |
| 400 | Step not in awaiting_approval state or other validation error |
Reject a workflow step that is awaiting approval. The step is marked as failed and the workflow continues based on its dependency graph.
Response (200):
{
"status": "rejected",
"run_id": "c2d3e4f5-a6b7-8901-bcde-f12345678901",
"step_id": "deploy"
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Step rejected |
| 400 | Step not in awaiting_approval state or other validation error |
curl examples:
# Approve a step
curl -X POST http://localhost:8080/api/v1/workflow-runs/$RUN_ID/approve/deploy \
-H "Authorization: Bearer $TOKEN"
# Reject a step
curl -X POST http://localhost:8080/api/v1/workflow-runs/$RUN_ID/reject/deploy \
-H "Authorization: Bearer $TOKEN"Cancel a workflow run and all its pending/running steps. The run and any associated sessions will be marked as cancelled. Only workflow runs in pending, running, or awaiting_approval status can be cancelled.
Response (200):
{
"status": "cancelled",
"run_id": "c2d3e4f5-a6b7-8901-bcde-f12345678901"
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Workflow run cancelled successfully |
| 400 | Workflow run is already in final state or other validation error |
| 404 | Workflow run not found |
Alternative endpoint to cancel a workflow run. Same functionality as DELETE /api/v1/workflow-runs/{id}.
Response (200):
{
"status": "cancelled",
"run_id": "c2d3e4f5-a6b7-8901-bcde-f12345678901"
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Workflow run cancelled successfully |
| 400 | Workflow run is already in final state or other validation error |
| 404 | Workflow run not found |
curl examples:
# Cancel using DELETE
curl -X DELETE http://localhost:8080/api/v1/workflow-runs/$RUN_ID \
-H "Authorization: Bearer $TOKEN"
# Cancel using POST
curl -X POST http://localhost:8080/api/v1/workflow-runs/$RUN_ID/cancel \
-H "Authorization: Bearer $TOKEN"Bridge actions are deterministic actions executed by Bridge itself (not by Skiff agents). They are used as steps in workflows with type: bridge. This endpoint lists the available bridge actions and their input/output schemas.
List all available bridge action schemas.
Response (200):
{
"actions": [
{
"name": "create-pr",
"description": "Create a pull request on GitHub",
"inputs": {
"repo": "string (required) - Repository in owner/repo format",
"branch": "string (required) - Source branch name",
"base": "string (required) - Target branch name",
"title": "string (required) - PR title",
"body": "string (optional) - PR body/description",
"draft": "bool (optional) - Create as draft PR"
},
"outputs": {
"pr_number": "int - Pull request number",
"pr_url": "string - Pull request URL"
}
},
{
"name": "await-ci",
"description": "Wait for CI checks to complete on a pull request",
"inputs": {
"repo": "string (required) - Repository in owner/repo format",
"pr": "int (required) - Pull request number",
"timeout": "int (optional) - Timeout in seconds (default 900)"
},
"outputs": {
"status": "string - CI result: 'passed' or 'failed'",
"failure_logs": "string - Concatenated failure logs (if failed)",
"failed_checks": "[]string - Names of failed checks"
}
},
{
"name": "merge-pr",
"description": "Merge a pull request on GitHub",
"inputs": {
"repo": "string (required) - Repository in owner/repo format",
"pr": "int (required) - Pull request number",
"method": "string (optional) - Merge method: merge, squash, rebase (default merge)",
"delete_branch": "bool (optional) - Delete source branch after merge (default true)"
},
"outputs": {
"merge_sha": "string - The SHA of the merge commit"
}
}
],
"count": 3
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Actions listed |
curl example:
curl http://localhost:8080/api/v1/bridge-actions \
-H "Authorization: Bearer $TOKEN"The catalog provides a registry of available sources (git repositories containing agents, plugins, LSPs, MCPs) and their items. Catalog entries are seeded from embedded data at compile time. Teams toggle individual items via the Teams catalog endpoints.
List all catalog sources with category breakdown.
Response (200):
{
"entries": [
{
"id": "alcove-agents",
"name": "Alcove Agents",
"description": "Built-in agent collection for common development tasks",
"category": "agents",
"source_type": "git",
"source_url": "https://github.com/bmbouter/alcove-catalog.git",
"source_path": "agents",
"ref": "main",
"docs_url": "https://github.com/bmbouter/alcove-catalog",
"tags": ["official", "agents"]
}
],
"count": 1,
"categories": [
{ "id": "agents", "count": 1 }
]
}Each catalog entry represents a source (a git repository or sub-path within one). Items within each source are discovered during sync and managed per-team via the /api/v1/teams/{id}/catalog endpoints.
Status codes:
| Code | Meaning |
|---|---|
| 200 | Catalog listed |
curl example:
curl http://localhost:8080/api/v1/catalog \
-H "Authorization: Bearer $TOKEN"All error responses use the same JSON shape:
{
"error": "human-readable error message"
}The error field is always a string. HTTP status codes follow standard conventions:
| Code | Meaning |
|---|---|
| 400 | Bad request (invalid JSON, missing required fields) |
| 401 | Unauthorized (missing or invalid token) |
| 404 | Resource not found |
| 405 | Method not allowed |
| 409 | Conflict (duplicate resource) |
| 500 | Internal server error |
| 503 | Service unavailable (degraded health) |