Skip to content

Colony Monitor REST API

The monitor process exposes an HTTP API for pipeline observability, issue lifecycle management, and Prometheus metrics scraping.

When agents.monitor.auth is configured, all endpoints except /health and /prometheus require HTTP Basic authentication.

colony.config.yaml
agents:
monitor:
auth:
username: colony
password_env: COLONY_MONITOR_PASSWORD # env var holding the password

Credentials are compared using timing-safe equality. On failure the server returns:

  • Status: 401 Unauthorized
  • Header: WWW-Authenticate: Basic realm="Colony"
  • Body: JSON ApiError{"error": "...", "code": "AUTH_REQUIRED" | "AUTH_FAILED", "status": 401}

If no auth block is configured, all endpoints are open.

Returns server liveness. No auth required.

ResponseHealthResponse

{ "status": "healthy", "uptime": 3600 }
FieldTypeDescription
statusstringAlways "healthy"
uptimenumberSeconds since the process started

Returns the full pipeline dashboard snapshot. Auth required.

ResponseDashboardResponse

{
"status": "healthy",
"uptime": 3600,
"agents": {
"sprint-master": {
"agentName": "sprint-master",
"reachable": true,
"timestamp": 1711929600000,
"responseTimeMs": 42,
"health": { "status": "healthy" },
"costUsd": 1.23,
"inFlightIssues": ["owner/repo#10"],
"tenantSpend": { "default": 1.23 }
}
},
"alerts": [],
"costTotalUsd": 12.50,
"pipelineSummary": { "analyzing": 1, "in-development": 3 },
"workerPool": []
}
FieldTypeDescription
status"healthy" | "degraded" | "unhealthy"Overall pipeline health
uptimenumberSeconds since process start
agentsRecord<string, AgentHealthSnapshot>Per-agent health snapshots
alertsAlert[]Active alerts from failure detectors
costTotalUsdnumberTotal cost across all agents
costByWindow?CostByWindowCost broken down by time window
pipelineSummaryRecord<string, number>Issue counts by pipeline state
issueTimelines?Record<number, IssueTimeline>Per-issue timelines
tenants?TenantBudgetDashboard[]Per-tenant budget info
metrics?Record<string, PipelineMetrics>Per-repo pipeline metrics
workerPool?WorkerPoolSnapshot[]Per-repo worker pool status

Returns the timeline for a single issue. Auth required.

Path parameters:

ParamTypeDescription
ownerstringRepository owner
repostringRepository name
issuenumberIssue number

ResponseTimelineResponse

TimelineResponse extends IssueTimeline with two additional fields:

{
"issueNumber": 42,
"entries": [],
"totalCostUsd": 0.85,
"totalDurationMs": 120000,
"currentState": "in-development",
"stateTransitions": [],
"isPaused": false,
"isBlocked": false
}
FieldTypeDescription
issueNumbernumberThe issue number
entriesTimelineEntry[]Chronological timeline entries
totalCostUsdnumberTotal cost for this issue
totalDurationMsnumberTotal wall-clock duration
currentStatestringCurrent pipeline state
staleSinceMs?numberHow long the issue has been stale
stateTransitionsStateTransition[]State change history
isPausedbooleanWhether the issue is paused
isBlockedbooleanWhether the issue is blocked

Errors:

StatusCodeWhen
400Expected /api/timeline/:owner/:repo/:issueMalformed path
400Invalid issue numberNon-numeric issue param
503No repo context available for owner/repoRepo not configured
500Failed to build timelineInternal error

Lists all tracks for a repository. Auth required.

The repo query parameter is required. Requests without a ? query string do not match this route and return a 404.

Query parameters:

ParamTypeRequiredDescription
repostringYesRepository as owner/repo

ResponseTrackListResponse

{
"tracks": [
{
"name": "bugs",
"label": "bug",
"cooldown_minutes": 60,
"enabled": true,
"active_version": 1
}
]
}

Errors:

StatusCodeWhen
400Missing or invalid repo query parameterMissing or malformed repo

Creates or updates a track. Auth required.

Request bodyTrackCreateRequest

{
"repo": "owner/repo",
"name": "bugs",
"label": "bug",
"cooldown_minutes": 30,
"enabled": true
}
FieldTypeRequiredDefaultDescription
repostringYesRepository as owner/repo
namestringYesTrack name
labelstringNo""GitHub label filter
cooldown_minutesnumberNo60Cooldown between runs
enabledbooleanNotrueWhether the track is active

ResponseTrackCreateResponse

{ "ok": true }

Errors:

StatusCodeWhen
400Invalid JSON bodyUnparseable request body
400Missing required fields: repo, nameMissing repo or name

Deletes a track. Auth required.

Path parameters:

ParamTypeDescription
ownerstringRepository owner
repostringRepository name
namestringTrack name

ResponseTrackDeleteResponse

{ "ok": true }

POST /api/tracks/:owner/:repo/:name/enable

Section titled “POST /api/tracks/:owner/:repo/:name/enable”

Enables a track. Auth required.

ResponseTrackToggleResponse

{ "ok": true }

Errors:

StatusCodeWhen
404Track "name" not foundTrack does not exist

POST /api/tracks/:owner/:repo/:name/disable

Section titled “POST /api/tracks/:owner/:repo/:name/disable”

Disables a track. Auth required.

ResponseTrackToggleResponse

{ "ok": true }

Errors:

StatusCodeWhen
404Track "name" not foundTrack does not exist

GET /api/tracks/:owner/:repo/:name/prompts

Section titled “GET /api/tracks/:owner/:repo/:name/prompts”

Lists all prompt versions for a track. Auth required.

ResponseTrackPromptListResponse

{
"versions": [
{ "version": 1, "created_at": "2026-01-15T10:00:00Z", "notes": "initial" }
]
}

POST /api/tracks/:owner/:repo/:name/prompts

Section titled “POST /api/tracks/:owner/:repo/:name/prompts”

Creates a new prompt version for a track. Auth required.

Request bodyTrackPromptCreateRequest

{
"seed_title": "Fix {{label}} issues",
"seed_body": "Investigate and fix the problem.",
"instructions": "Follow repo conventions.",
"notes": "v2 with better instructions"
}
FieldTypeRequiredDefaultDescription
seed_titlestringNo""Issue title template
seed_bodystringNo""Issue body template
instructionsstringNo""Agent instructions
notesstringNo""Human-readable version notes

ResponseTrackPromptCreateResponse

{ "version": 2 }

Errors:

StatusCodeWhen
400Invalid JSON bodyUnparseable request body
404variesTrack not found

GET /api/tracks/:owner/:repo/:name/prompts/:version

Section titled “GET /api/tracks/:owner/:repo/:name/prompts/:version”

Returns a single prompt version. Auth required.

Path parameters:

ParamTypeDescription
versionnumberPrompt version number

ResponseTrackPromptGetResponse

{
"prompt": {
"version": 1,
"seed_title": "Fix {{label}} issues",
"seed_body": "Investigate and fix the problem.",
"instructions": "Follow repo conventions."
}
}

Errors:

StatusCodeWhen
404Version N not foundVersion does not exist

POST /api/tracks/:owner/:repo/:name/prompts/:version/activate

Section titled “POST /api/tracks/:owner/:repo/:name/prompts/:version/activate”

Sets a prompt version as the active version for a track. Auth required.

ResponseTrackPromptActivateResponse

{ "ok": true }

Errors:

StatusCodeWhen
404variesTrack or version not found

All issue action endpoints follow the pattern POST /api/issues/:owner/:repo/:issue/:action. Auth required.

Path parameters:

ParamTypeDescription
ownerstringRepository owner
repostringRepository name
issuenumberIssue number

ResponseIssueActionResponse

resume, unblock, and retry include a state field with the issue’s current pipeline state. pause and cancel do not.


POST /api/issues/:owner/:repo/:issue/pause

Section titled “POST /api/issues/:owner/:repo/:issue/pause”

Pauses an issue. Adds the colony:paused label.

{ "ok": true }

POST /api/issues/:owner/:repo/:issue/resume

Section titled “POST /api/issues/:owner/:repo/:issue/resume”

Resumes a paused issue. Removes colony:paused and re-enqueues the work task.

{ "ok": true, "state": "in-development" }

POST /api/issues/:owner/:repo/:issue/unblock

Section titled “POST /api/issues/:owner/:repo/:issue/unblock”

Unblocks an issue. Removes colony:blocked and re-enqueues the work task.

{ "ok": true, "state": "analyzing" }

POST /api/issues/:owner/:repo/:issue/retry

Section titled “POST /api/issues/:owner/:repo/:issue/retry”

Re-enqueues the work task for an issue in its current state.

{ "ok": true, "state": "in-review" }

Errors:

StatusCodeWhen
404Issue not found: owner/repo#NIssue not in pipeline store

POST /api/issues/:owner/:repo/:issue/cancel

Section titled “POST /api/issues/:owner/:repo/:issue/cancel”

Cancels an issue by transitioning it to done.

{ "ok": true }

Common issue action errors:

StatusCodeWhen
404Not foundMalformed URL path
404Repo not found: owner/repoRepo not configured
404variesError message containing “not found”
500Internal server errorUnexpected failure
503Pipeline store not availableNo database connection

Lists GitHub projections (queued label/state sync operations). Auth required.

Query parameters:

ParamTypeRequiredDefaultDescription
statusstringNopending + failedFilter by projection status (pending, failed, complete, discarded)

When status is omitted, results are filtered to only pending and failed projections.

ResponseProjectionListResponse

{
"projections": [
{
"id": 1,
"repoOwner": "acme",
"repoName": "app",
"issueNumber": 42,
"action": { "type": "addLabels", "labels": ["colony:analyzing"] },
"status": "pending",
"attempts": 0,
"maxAttempts": 3,
"clientType": "ops",
"retryAfter": null,
"error": null,
"createdAt": "2026-01-15T10:00:00Z",
"updatedAt": "2026-01-15T10:00:00Z"
}
]
}

The action field is a discriminated union keyed by type. See the ProjectionAction type in the SDK for all variants (e.g. addLabels, removeLabels, swapLabels, closeIssue, postComment, mergePR, etc.).

Errors:

StatusCodeWhen
500Internal server errorUnexpected failure
503Pipeline store not availableNo database connection

Resets a projection to pending for re-execution. Auth required.

Path parameters:

ParamTypeDescription
idnumberProjection ID

ResponseProjectionActionResponse

{ "ok": true }

Errors:

StatusCodeWhen
400Invalid requestMalformed URL
500Internal server errorUnexpected failure
503Pipeline store not availableNo database connection

Marks a projection as discarded, preventing further retries. Auth required.

Path parameters:

ParamTypeDescription
idnumberProjection ID

ResponseProjectionActionResponse

{ "ok": true }

Errors: Same as POST /api/projections/:id/retry.


Toggles drain mode for a worker. A draining worker finishes its current task but does not claim new work. Auth required.

Path parameters:

ParamTypeDescription
idstringWorker ID (URL-encoded if necessary)

Request bodyWorkerDrainRequest

{ "drain": true }
FieldTypeRequiredDescription
drainbooleanYestrue to drain, false to resume

ResponseWorkerDrainResponse

{ "ok": true, "draining": true }

Errors:

StatusCodeWhen
400Invalid JSON bodyUnparseable request body
400Missing required boolean field: draindrain is not a boolean
500Failed to set worker drain statusDatabase error
503Pipeline store not availableNo database connection

Returns Prometheus-format metrics. No auth required.

Response: text/plain; version=0.0.4; charset=utf-8

Metrics include agent health, alert counts, pipeline state gauges, tenant spend, per-repo pipeline metrics, and worker pool statistics.


Most error responses follow the ApiError shape:

interface ApiError {
error: string; // human-readable message
code: string; // machine-readable error code
status: number; // HTTP status code
}

All API error responses return the full ApiError shape — all three fields are always present, except for the empty-body paths listed under Unmatched routes below.

StatusMeaningWhen
200OKSuccessful request
400Bad RequestInvalid input, malformed JSON, missing required fields
401UnauthorizedMissing or invalid Basic auth credentials
404Not FoundResource not found or unmatched route
500Internal Server ErrorUnexpected server-side failure
503Service UnavailablePipeline store (Postgres) not connected

Unmatched API routes return 404 with a structured JSON body: { "error": "No matching route", "code": "NOT_FOUND", "status": 404 }.

Only two response paths intentionally return empty bodies (no JSON):

  • /assets/* 404s — directory traversal violations and missing static files.
  • /api/events 503 — returned when the SSE manager is not running; this path bypasses sendError.

Serves the dashboard SPA (index.html). If the dashboard has not been built, returns a placeholder HTML page. Auth required.

Serves static files from the dashboard build output directory. Includes directory traversal protection. Auth required.