REST API Reference

July 26, 2026 ยท View on GitHub

Bernstein exposes a task-server HTTP API on http://127.0.0.1:8052 by default. The full OpenAPI 3.1 specification is available at /openapi.json when the server is running.

This page is a hand-maintained tour of the FastAPI route modules under src/bernstein/core/routes/, plus 13 MCP tools. Endpoints requiring authentication are marked with Y in the Auth column. docs/reference/openapi.json is the complete machine-readable list; where the two disagree, the JSON wins.

Generating the spec

Use the included script to regenerate docs/reference/openapi.json from the FastAPI app definition without starting the server:

uv run python scripts/generate_openapi.py
# Written docs/reference/openapi.json  (459 paths, 121 schemas)

Run this after adding or modifying any API route, Pydantic model, or response schema, then commit the updated JSON. The hosted Redoc page reads the spec at load time, so the rendered reference updates automatically once the JSON is committed.

Forgetting the step is a CI failure, not a silent rot: tests/unit/test_openapi_snapshot_drift.py rebuilds the app, diffs its paths and component schemas against the committed snapshot, and names whatever moved.

Alternative -- inspect the spec from a running server:

curl -s http://127.0.0.1:8052/openapi.json | python -m json.tool

Read-only. Redirecting curl into the snapshot writes minified JSON and rewrites every line of the committed file, so refresh it with the script above instead.

The OpenAPI JSON declares each route at both its bare path (e.g. /tasks) and an /api/v1/-prefixed alias (e.g. /api/v1/tasks). Both are live; pick one prefix per client.

Authentication

When auth is enabled (BERNSTEIN_AUTH_ENABLED=true), endpoints marked Auth: Y require a Bearer token:

curl -H "Authorization: Bearer <token>" http://127.0.0.1:8052/tasks

Public endpoints (no auth required): /health, /health/ready, /health/live, /.well-known/agent.json, /.well-known/acp.json, /docs, /openapi.json, plus loopback connections from 127.0.0.1 (for local CLI use).

Bearer tokens are issued via the CLI device flow (/auth/cli/device, /auth/cli/authorize, /auth/cli/token).


Health and lifecycle

Source: core/routes/status_lifecycle.py.

MethodPathHandlerAuthPurpose
GET/healthhealthNServer liveness probe; returns 200 when up
GET/health/readyreadinessNReadiness probe; checks dependencies
GET/readyreadinessNAlias for /health/ready
GET/health/livelivenessNLiveness probe
GET/alivelivenessNAlias for /health/live
GET/health/depsdependency_healthNPer-dependency health (DB, Redis, providers)
POST/configupdate_configYHot-reload server configuration
POST/shutdownshutdownYGraceful server shutdown
GET/cache-statscache_statsNPrompt-cache hit/miss stats
GET/metricsprometheus_metricsNPrometheus scrape endpoint

Status and dashboard

Source: core/routes/status_dashboard.py, core/routes/status_events.py.

MethodPathHandlerAuthPurpose
GET/statusstatus_summaryNDashboard snapshot (agents, tasks, metrics)
GET/status/duration-predictionsduration_predictionsNPredicted completion time per task
GET/routing/banditbandit_stateNCascade-router bandit state inspection
GET/dashboarddashboard_htmlNWeb dashboard HTML page
GET/dashboard/datadashboard_dataNJSON payload for the dashboard
GET/eventsevents_streamNServer-Sent Events stream for live updates
GET/badge.jsonbadge_jsonNShields.io-compatible status badge
GET/memory/auditmemory_auditYInspect memory store for audit
POST/broadcastbroadcast_messageYPush a message to all connected clients

Tasks

Source: core/routes/task_crud.py, core/routes/paginated_tasks.py, core/routes/batch_ops.py, core/routes/task_detail.py.

MethodPathHandlerAuthPurpose
POST/taskscreate_taskNCreate a new task
POST/tasks/batchcreate_tasks_batchNCreate many tasks in one call
POST/tasks/importimport_tasksNImport tasks from a YAML/JSON file
GET/taskslist_tasksNList tasks (filter by status, role, etc.)
GET/tasks/countstask_countsNCounts per status (open/claimed/done/failed)
GET/tasks/archivearchived_tasksNList archived tasks
GET/tasks/graphtask_graphNDependency graph between tasks
GET/tasks/searchsearch_tasksNFull-text search over task corpus
GET/tasks/{task_id}get_taskNFetch a single task by ID
GET/tasks/{task_id}/logstask_logsNStatic log dump for a task
GET/tasks/{task_id}/snapshotstask_snapshotsNPersistence snapshots taken during the run
GET/tasks/{task_id}/partial-mergepartial_mergeNPartial-merge diff for a long-running task
PATCH/tasks/{task_id}update_taskNUpdate task fields (priority, scope, etc.)

Lifecycle operations

MethodPathHandlerAuthPurpose
POST/tasks/{task_id}/approveapprove_taskNMark a task as approved for execution
POST/tasks/{task_id}/rejectreject_taskNReject a task; halts execution
POST/tasks/{task_id}/progressreport_progressNHeartbeat with files/tests/errors
POST/tasks/{task_id}/claimclaim_taskNClaim a task for an agent session
POST/tasks/{task_id}/completecomplete_taskNMark task completed (success)
POST/tasks/{task_id}/failfail_taskNMark task failed
POST/tasks/{task_id}/cancelcancel_taskNCancel a queued or in-flight task
POST/tasks/{task_id}/requeuerequeue_taskNRe-queue a failed task
POST/tasks/{task_id}/archivearchive_taskNArchive a closed task
POST/tasks/{task_id}/splitsplit_taskNSplit into subtasks
POST/tasks/{task_id}/retryretry_taskNRetry a failed task

Batch operations

MethodPathHandlerAuthPurpose
POST/tasks/claim-batchclaim_batchNClaim multiple tasks atomically
POST/tasks/batch-opsbatch_opsNMixed lifecycle ops in one request

Streaming and dashboard views

MethodPathHandlerAuthPurpose
GET/dashboard/tasks/{task_id}dashboard_task_detailNDashboard task detail JSON
GET/dashboard/tasks/{task_id}/logs/streamtask_log_streamNSSE log stream for a task
GET/dashboard/file_locksfile_locks_viewNCross-task file-lock state for the dashboard

Agents and team

Source: core/routes/agents.py, core/routes/team.py, core/routes/agent_comparison.py.

MethodPathHandlerAuthPurpose
GET/agentslist_agentsNList active agent sessions
POST/agents/{session_id}/killkill_agentYForce-terminate an agent process
GET/agents/{session_id}/streamagent_streamNSSE stream of agent stdout/stderr
GET/agents/{session_id}/logsagent_logsNStatic log dump for an agent
POST/agents/{agent_id}/heartbeatagent_heartbeatNLiveness ping from the agent process
GET/agents/comparisonagent_comparisonNA/B-test comparison view
GET/teamteam_overviewNLogical "team" of agents working on a goal
GET/team/activeteam_activeNCurrently-active team sessions
GET/team/{team_id}team_by_idNSingle team detail
GET/team/dashboardteam_dashboardNDashboard JSON for team view

WebSocket

MethodPathHandlerAuthPurpose
WS/wswebsocket_endpointNPrimary streaming surface for agent + task events

The /ws endpoint is the recommended subscription channel for live UI; use SSE endpoints (/events, /agents/{id}/stream) for unidirectional consumers.


Plans and graph

Source: core/routes/plans.py, core/routes/graph.py.

MethodPathHandlerAuthPurpose
GET/planslist_plansNList known plan files
GET/plans/activeactive_planNThe currently-executing plan
POST/planscreate_planNCreate a new plan from goal + scope
POST/plans/validatevalidate_planNValidate plan YAML against schema
GET/graph/impactimpact_graphNDependency-impact analysis for a change

Quality

Source: core/routes/quality.py, core/routes/file_health.py.

MethodPathHandlerAuthPurpose
GET/qualityquality_overviewNTop-level quality metrics
GET/quality/budget-forecastquality_budget_forecastNPredicted quality-budget burn
GET/quality/trendquality_trendNTrend over time
GET/quality/modelsquality_per_modelNQuality breakdown per model
GET/quality/file-healthfile_health_overviewNPer-file health snapshot
GET/quality/file-health/flaggedflagged_filesNFiles flagged for review
GET/quality/file-health/{path}file_health_detailNDrill-down for one file

Observability and costs

Source: core/routes/observability.py, core/routes/costs.py, core/routes/provider_latency.py, core/routes/predictive.py, core/routes/custom_metrics.py, core/routes/grafana.py, core/routes/slo.py.

Observability

MethodPathHandlerAuthPurpose
GET/observability/agentsobs_agentsNPer-agent metrics
GET/observability/effectivenessobs_effectivenessNEffectiveness scoring
GET/observability/recommendationsobs_recommendationsNTuning recommendations from telemetry
GET/observability/budgetobs_budgetNBudget burn-down view
GET/observability/depsobs_depsNExternal dependency health timeline
GET/observability/token-histogramobs_token_histogramNToken-usage histogram
GET/observability/queue-depthobs_queue_depthNTask-queue depth over time
GET/observability/timelineobs_timelineNCombined event timeline
GET/observability/incidentsobs_incidentsNList incidents detected by anomaly detector
GET/observability/token-breakdownobs_token_breakdownNTokens broken down by role/agent/task
GET/observability/incident-timeline/{incident_id}obs_incident_timelineNPer-incident timeline
GET/recapdaily_recapNDaily/weekly recap
GET/changelogauto_changelogNAuto-generated changelog from runs
GET/events/costcost_events_streamNSSE stream of cost events

Costs

MethodPathHandlerAuthPurpose
GET/costscosts_overviewNAggregate cost view
GET/costs/livecosts_liveNLive cost gauge
GET/costs/currentcosts_currentNCurrent run costs
GET/costs/alertscosts_alertsNActive cost alerts
GET/costs/historycosts_historyNHistorical cost series
GET/costs/{run_id}costs_for_runNCost detail for a run
GET/costs/exportcosts_exportNCSV export for external billing
GET/costs/forecastcosts_forecastNBudget-forecast predictions
GET/costs/comparecosts_compareNCompare two runs
GET/costs/cache-statscosts_cache_statsNPrompt-cache hit value (USD)
GET/costs/model-comparisoncosts_model_comparisonNCross-model cost comparison
GET/costs/token-efficiencycosts_token_efficiencyNTokens per accepted change

Provider latency and predictions

MethodPathHandlerAuthPurpose
GET/metrics/provider-latencyprovider_latencyNLatency per provider
GET/metrics/provider-latency/historyprovider_latency_historyNTime series
GET/metrics/predictionsmetric_predictionsNPredictive metric output
GET/metrics/customcustom_metricsNUser-defined metrics
GET/metrics/custom/schemacustom_metrics_schemaNCustom-metric schema introspection

Grafana and SLO

MethodPathHandlerAuthPurpose
GET/grafana/dashboardgrafana_dashboardNGrafana JSON model for the Bernstein dashboard
GET/sloslo_overviewNSLO status
GET/slo/budgetslo_budgetNError-budget remaining
GET/slo/burndownslo_burndownNBurndown chart data
POST/slo/resetslo_resetYReset SLO budgets after an incident

Webhooks and chat

Source: core/routes/webhooks.py, core/routes/notifications.py.

MethodPathHandlerAuthPurpose
POST/webhookgeneric_webhookNGeneric inbound webhook receiver
POST/webhooks/githubgithub_webhookNGitHub events (signature-verified)
POST/webhooks/gitlabgitlab_webhookNGitLab events
POST/webhooks/slack/commandsslack_commandNSlack slash-command receiver
POST/webhooks/slack/eventsslack_eventNSlack Events API receiver
POST/webhooks/discord/interactionsdiscord_interactionNDiscord interaction receiver
GET/alertslist_alertsNActive alerts emitted to chat sinks

Workspace, GraphQL, hooks, identities

Source: core/routes/workspace.py, core/routes/graphql.py, core/routes/hooks.py, core/routes/identities.py.

MethodPathHandlerAuthPurpose
GET/workspaceget_workspaceNRead workspace state
POST/workspaceupdate_workspaceNUpdate workspace state
POST/graphqlgraphql_endpointNGraphQL query interface
POST/hooks/{session_id}session_hookNPer-session hook receiver
GET/identitieslist_identitiesYList configured identities
GET/identities/{id}get_identityYFetch identity by ID
POST/identities/{id}/revokerevoke_identityYRevoke an identity
GET/identities/{id}/auditidentity_auditYAudit trail for an identity

ACP and A2A protocols

Source: core/routes/acp.py, core/routes/a2a.py.

ACP (Agent Client Protocol)

MethodPathHandlerAuthPurpose
GET/.well-known/acp.jsonacp_well_knownNACP service discovery
GET/acp/v0/agentsacp_list_agentsNList ACP agents
GET/acp/v0/agents/{id}acp_get_agentNACP agent detail
POST/acp/v0/runsacp_create_runNStart an ACP run
GET/acp/v0/runs/{id}acp_get_runNGet ACP run status
DELETE/acp/v0/runs/{id}acp_cancel_runNCancel ACP run

A2A (Agent-to-Agent)

MethodPathHandlerAuthPurpose
GET/.well-known/agent.jsona2a_well_knownNA2A service discovery
GET/a2a/agentsa2a_list_agentsNList A2A agents
POST/a2a/agents/{id}/tasksa2a_post_taskNSubmit a task to an A2A agent
POST/a2a/tasks/senda2a_send_taskNTop-level task-send entry
GET/a2a/tasks/{id}a2a_get_taskNFetch A2A task status
POST/a2a/tasks/{id}/subscribea2a_subscribeNSubscribe to A2A task updates

Auth

Source: core/routes/auth.py.

MethodPathHandlerAuthPurpose
GET/auth/providerslist_providersNList configured auth providers
GET/auth/oidc/callbackoidc_callbackNOIDC redirect callback
POST/auth/saml/acssaml_acsNSAML Assertion Consumer Service
GET/auth/saml/metadatasaml_metadataNSAML SP metadata
POST/auth/cli/devicecli_device_initNInitiate CLI device-flow login
POST/auth/cli/tokencli_device_tokenNExchange device code for token
POST/auth/cli/authorizecli_authorizeNAuthorize a pending device
GET/auth/loginloginNInteractive login
GET/auth/mecurrent_userYAuthenticated-user profile
POST/auth/logoutlogoutYRevoke current session
GET/auth/group-mappingsgroup_mappingsYOIDC/SAML group -> role mappings
GET/auth/userslist_usersYList users (admin)

Approvals

Source: core/routes/approvals.py.

MethodPathHandlerAuthPurpose
GET/approvalslist_approvalsYList pending approvals
POST/approvals/{id}/approveapproveYApprove a pending request
POST/approvals/{id}/rejectrejectYReject a pending request
GET/approvals/queueapprovals_queueYApprovals queue view
POST/approvals/queue/{id}/resolveresolve_queue_itemYResolve a queued approval
GET/approvals/live-fragmentlive_fragmentNHTMX live-fragment for the dashboard

Audit, drain, export, SBOM

Source: core/routes/audit_log.py, core/routes/drain.py, core/routes/export.py, core/routes/sbom.py.

MethodPathHandlerAuthPurpose
GET/auditaudit_logYHMAC-chained audit log
POST/drainstart_drainYBegin a graceful drain
GET/draindrain_statusYDrain status
POST/drain/cancelcancel_drainYCancel an in-progress drain
GET/export/tasksexport_tasksYExport task history
GET/export/agentsexport_agentsYExport agent history
POST/sbomgenerate_sbomYGenerate Software Bill of Materials
GET/sbomget_sbomYRetrieve last-generated SBOM

Sandbox and cluster

Source: core/routes/sandbox.py, core/routes/task_cluster.py.

Sandbox sessions

MethodPathHandlerAuthPurpose
GET/packslist_packsNList installed sandbox packs
POST/packs/{id}/sessionscreate_sessionNSpawn a session from a pack
GET/sessionslist_sessionsNList active sandbox sessions
GET/sessions/{id}get_sessionNSession detail
POST/sessions/{id}/execexec_in_sessionNRun a command in a session
GET/sessions/{id}/outputsession_outputNStream session output

Cluster

MethodPathHandlerAuthPurpose
POST/cluster/nodesregister_nodeYRegister a worker node (replaces legacy /cluster/register)
GET/cluster/nodeslist_nodesYList registered nodes
POST/cluster/nodes/{node_id}/heartbeatnode_heartbeatYPer-node heartbeat (replaces legacy /cluster/heartbeat)
POST/cluster/nodes/{node_id}/cordoncordon_nodeYMark node unschedulable
POST/cluster/nodes/{node_id}/uncordonuncordon_nodeYMark node schedulable
POST/cluster/nodes/{node_id}/draindrain_nodeYDrain in-flight work off a node
DELETE/cluster/nodes/{node_id}deregister_nodeYRemove a node from the cluster
GET/cluster/statuscluster_statusYCluster-wide status (replaces legacy /cluster/topology)
POST/cluster/stealsteal_tasksYRe-balance by stealing tasks from another node

Note on legacy paths. Earlier versions of this reference listed POST /cluster/register, POST /cluster/heartbeat, and GET /cluster/topology. None of those exist in the current codebase. Use the paths above.


Bulletin and channel

Source: core/routes/bulletin.py, core/routes/channel.py.

MethodPathHandlerAuthPurpose
POST/bulletinpost_bulletinNPost a cross-agent finding or blocker
GET/bulletinread_bulletinNRead bulletins (filter by since)
POST/channel/querychannel_queryNOne-shot query on a channel
POST/channel/subscribechannel_subscribeNSubscribe to a channel
GET/channel/querieslist_channel_queriesNList recent queries
GET/channel/query/{id}get_channel_queryNFetch a specific query result

MCP tools

The MCP tools below are exposed via Bernstein's MCP server (mcp/server.py), not over HTTP. They are callable from any MCP-aware client (Claude Desktop, Cursor, etc.) once the MCP server is registered.

Tool namePurpose
bernstein_runStart an orchestration run from a goal
bernstein_statusFetch current task/agent status
bernstein_tasksList tasks with filtering
bernstein_costCost summary for the current run
bernstein_stopStop the running orchestrator
bernstein_approveSign off a finished result that is waiting on a decision
bernstein_completeReport the result of work the caller is executing
bernstein_create_subtaskCreate a subtask under an existing task
bernstein_healthHealth check
bernstein_scenariosList available scenarios
bernstein_scenarioRun a scenario
bernstein_scenario_statusFetch scenario run status
verify_chainVerify an artefact's lineage chain
load_skillLoad a skill pack at runtime

These are MCP tools, not HTTP endpoints. They consume tool-call payloads matching each tool's MCP schema (see mcp/server.py for inputSchema definitions).


Request/response examples

Create a task

curl -X POST http://127.0.0.1:8052/tasks \
  -H "Content-Type: application/json" \
  -d '{
    "goal": "Implement user authentication",
    "role": "backend",
    "priority": 2,
    "scope": ["src/auth/"],
    "complexity": "medium"
  }'

Response:

{
  "id": "task-a1b2c3d4",
  "goal": "Implement user authentication",
  "role": "backend",
  "status": "open",
  "priority": 2,
  "created_at": 1712345678.0
}

List open tasks

curl 'http://127.0.0.1:8052/tasks?status=open'

Complete a task

curl -X POST http://127.0.0.1:8052/tasks/task-a1b2c3d4/complete \
  -H "Content-Type: application/json" \
  -d '{
    "summary": "Added JWT auth with refresh tokens",
    "files_changed": ["src/auth/jwt.py", "tests/test_jwt.py"]
  }'

Report progress

curl -X POST http://127.0.0.1:8052/tasks/task-a1b2c3d4/progress \
  -H "Content-Type: application/json" \
  -d '{
    "files_changed": 3,
    "tests_passing": true,
    "errors": []
  }'

Register a worker node (cluster)

curl -X POST http://127.0.0.1:8052/cluster/nodes \
  -H "Authorization: Bearer ${BERNSTEIN_AUTH_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "node_id": "worker-eu-1",
    "address": "10.0.0.4:8052",
    "labels": {"region": "eu", "tier": "spot"}
  }'

Error responses

All errors return JSON with a detail field:

{ "detail": "Task not found: task-xyz" }
StatusMeaning
400Bad request (validation error)
401Unauthorized (missing/invalid token)
403Forbidden (IP not in allowlist; insufficient role)
404Resource not found
409Conflict (e.g., claim race)
422Pydantic validation error
429Rate limited (Retry-After header set)
500Internal server error
503Drain in progress; not accepting new work

Rendering full HTML docs

Use any OpenAPI renderer:

# Redoc
npx @redocly/cli build-docs docs/reference/openapi.json -o docs/api.html

# Swagger UI (Docker)
docker run -p 8080:8080 -e SWAGGER_JSON=/spec/openapi.json \
  -v "$(pwd)/docs/reference":/spec swaggerapi/swagger-ui

Webhooks (outbound)

Bernstein can send webhook notifications for task lifecycle events. Configure in bernstein.yaml:

webhooks:
  url: "https://your-app.example.com/bernstein-events"
  events:
    - task.created
    - task.completed
    - task.failed
    - agent.spawned
    - agent.completed
  secret: "your-hmac-secret"

Webhook payloads include an X-Bernstein-Signature header containing an HMAC-SHA256 signature of the request body, computed with the configured secret.