AI Agents

API Reference

The API server (src/index.ts) listens on PORT (default 3001).

Authentication

MethodHeader / CookieUsed For
API keyAuthorization: Bearer {key}Job submission, event ingest, workspace uploads
HMACX-Hub-Signature-256GitHub webhook receiver
JWTauth_token cookie (HttpOnly)Dashboard API after OIDC login

API keys are validated against the SUBMIT_API_KEYS env var (fast path) and against Secrets labeled labrats.work/type=ai-api-key (CRD-managed via ApiKeyWatcher).

Public endpoints (no auth required): /health, /ready, /metrics, /api/auth/*.


Health and Metrics

EndpointPurpose
GET /healthLiveness — returns {"status":"ok"}.
GET /readyReadiness — returns {"status":"ok"}. The engine has no external dependencies that require checking.
GET /metricsPrometheus exposition format.

Jobs

Jobs map 1:1 to InferenceRequest CRDs. The frontend uses lowercase status strings derived from CRD phases:

PhaseAPI status
Pendingwaiting
Runningactive
Succeededcompleted
Failedfailed
Cancelledcancelled

Submit Job

POST /api/jobs/submit
Authorization: Bearer {api-key}
Content-Type: application/json
FieldTypeRequiredDescription
sourcestringyesOrigin identifier (github, manual, dashboard, github-actions, …).
typestringyesJob type label (implement-issue, code-review, document-extraction, error-reporting, …).
promptstringno*Stored in the per-job prompt ConfigMap. *Required unless type === "error-reporting".
errorsErrorEntry[]noUsed when type === "error-reporting".
prioritynumbernoDefault 2; lower runs first.
agentRolestringnoMatch against AiAgent trigger name.
workspaceSetup.gitRepostringnoClone URL (may include token).
workspaceSetup.gitRefstringnoBranch / tag / commit.
workspaceSetup.gitDepthnumbernoShallow clone depth.
workspaceFiles[]arrayno[{name, data(base64)}] written into the workspace.
workspaceUploads[]arrayno[{id, name}] referencing files in the uploads PVC.
config.modelstringnoOverride model.
config.effortstringnolow / medium / high.
config.providerstringnoclaude / codex / vllm / gemma / qwen / mock.
config.fastbooleannoEnable fast mode (Claude only).
config.timeoutMsnumbernoPer-job timeout (ms). Default 3,300,000 (55 min).
config.maxTurnsnumbernoMaximum conversation turns. Default 25.
config.executorImagestringnoOverride executor container image.
config.reactEnabledbooleannoEnable ReAct tool-calling loop (local inference only).
callbackUrlstringnoPOSTed at lifecycle events. Must pass validateCallbackUrl.
pipeline.typestringnoCurrently only pdf-sections.
metadataobjectnoFree-form key-value (echoed in callbacks and the dashboard).

Response (201):

{ "jobId": "ir-3ab1c2d4", "source": "github", "type": "implement-issue" }

jobId is the InferenceRequest CR name.

List Jobs

GET /api/jobs?page=1&limit=20&chainId={uuid}

limit is clamped to 1–100. Items expose CRD-derived fields: id, name (= type), source, agentRole, repo (from metadata), status, attempts, createdAt, processedAt, finishedAt, failedReason, chainId, chainDepth, parentJobId, chainPath, result.

Get Job Detail

GET /api/jobs/:id

Adds phase (raw CRD phase), accountName, k8sJobName, executorPodName, returnvalue (alias for status.result), logs[], the redacted workspace setup, and the promptRef.

Stream Job Logs (SSE)

GET /api/jobs/:id/logs
Accept: text/event-stream

Emits data: {"log":"..."} lines. Terminates with data: {"done":true,"status":"completed|failed|cancelled"}.

Source order: live executor pod logs (when an executorPodName is recorded) → persisted RWX log file (used by pipeline jobs) → fallback to status.logs[].

Retry Job

POST /api/jobs/:id/retry

Resets a Failed IR to Pending. Rejects (400) if the IR is not Failed, or if it carries an embedded git token and is older than 10 minutes (tokens have likely expired).

Cancel Job

POST /api/jobs/:id/cancel

Pending → set phase Cancelled. Running → delete the executor Job, set Cancelled, release the account. Other phases return 400.


Accounts

Removed. The AiAccount CRD and its /api/accounts endpoints were removed in spec 0003. Concurrency tracking moved to AiModel (see Models); credentials flow via the IR apiKeyRef (caller identity) and the optional AiModel.credentialsRef (backend token, claude only).


Agents

AiAgent CRDs.

EndpointDescription
GET /api/agentsList.
POST /api/agentsCreate. Fields: name, triggerName, defaultModel, defaultEffort, defaultProvider, eventTriggers[], instructions[].
GET /api/agents/:idDetail.
PATCH /api/agents/:idUpdate any subset, including enabled, instructions[], eventTriggers[].
DELETE /api/agents/:idRemove.
GET /api/agents/by-trigger/:triggerNameLookup by trigger. 404 if missing.
GET /api/agents/triggersOptional ?source=…&event=…. Returns agents whose eventTriggers match.
GET /api/agents/:id/instructionsResolved instruction list (globals sorted by priority, then assigned locals).
POST /api/agents/seedSeed default agents. Returns { "seeded": n }.

Event Triggers and Chains

Each entry in eventTriggers[]:

{
  "source": "github",
  "events": ["issues.labeled"],
  "instruction": "implement",
  "config": { "model": "opus", "effort": "high" },
  "filters": {},
  "enabled": true,
  "next": {
    "agentTriggerName": "ai-developer",
    "condition": "on-success",
    "failurePolicy": "stop"
  }
}

See Agent Chains for chain semantics.


Instructions

AiInstruction CRDs.

EndpointDescription
GET /api/instructionsList. Supports ?scope=global or ?scope=local.
POST /api/instructionsCreate. Fields: name, scope, displayName, description, priority, content.
GET /api/instructions/:idDetail.
PATCH /api/instructions/:idUpdate any subset of displayName, description, scope, priority, content.
DELETE /api/instructions/:idRemove.

API Keys

API keys are stored as labeled Secrets; the watcher updates the in-memory index in seconds.

EndpointDescription
GET /api/api-keysList. Only the prefix is returned.
POST /api/api-keysBody: { "name": "..." }. Response includes the full key once — store it.
DELETE /api/api-keys/:idRevoke.

Webhook Sources

WebhookSource CRDs. Each WebhookSource is reconciled by the API server, which auto-provisions a Deployment + Service + Ingress for the webhook receiver.

EndpointDescription
GET /api/webhook-sourcesList.
POST /api/webhook-sourcesCreate.
GET /api/webhook-sources/:idDetail.
PATCH /api/webhook-sources/:idUpdate.
DELETE /api/webhook-sources/:idRemove (also tears down the provisioned Deployment/Service/Ingress).

Configuration

Global Defaults (singleton AiConfig)

GET /api/config/defaults
PUT /api/config/defaults

Body / response shape:

{
  "model": "sonnet",
  "effort": "medium",
  "executorImage": "ghcr.io/labrats-work/apps.ai-agents/executor:latest",
  "executorResources": {
    "requests": { "cpu": "500m", "memory": "1Gi" },
    "limits":   { "cpu": "2",    "memory": "4Gi" }
  },
  "providers": {
    "claude": { "model": "opus", "effort": "high" },
    "codex":  { "model": "o3" }
  }
}

All fields are optional; PUT merges with the existing CR.

Source Config (Stubs)

Source-specific config moved to WebhookSource CRDs (repoOverrides, defaults). The legacy endpoints remain as stubs to avoid frontend errors:

GET    /api/config/sources          → { "sources": [] }
GET    /api/config/sources/:source  → { "source": "{name}", "model": "", "effort": "" }
PUT    /api/config/sources/:source  → echoes the body
DELETE /api/config/sources/:source  → { "removed": "{name}" }

Stats

EndpointDescription
GET /api/statsAggregated counts by type, model, repo, plus totals. Computed from in-memory IR cache.
GET /api/stats/timeseriesProxies queries to PROMETHEUS_URL.

Uploads

PDF / file uploads stored under WORKSPACE_DIR/uploads. Used by the dashboard for pipeline runs.

EndpointDescription
GET /api/uploadsList.
POST /api/uploadsmultipart/form-data with field file (PDF, max 100 MB).
DELETE /api/uploads/:idRemove.
POST /api/uploads/:id/extractSubmit a pdf-sections pipeline IR. Body: prompt?, model?, effort?. Returns { "jobId": "ir-…" }.

Workspace Uploads (RWX PVC)

Files made available to executor Jobs via the shared uploads PVC.

EndpointAuthDescription
POST /api/workspace-uploadsAPI keyUpload a file into UPLOADS_DIR/{id}/{name} (referenced by workspaceUploads in IR specs).
GET /api/workspace-uploads/:id/:name/rawAPI keyDownload a workspace upload file.
GET /api/workspace-uploadsJWTDashboard listing of files in the PVC.
DELETE /api/workspace-uploads/:idJWTDelete a workspace upload (dashboard).

Models

Manage local inference model files on the models-cache PVC.

EndpointDescription
GET /api/modelsList configured models (from AiConfig provider settings) and the PVC name.
POST /api/models/scanTrigger a k8s Job to scan the models PVC for downloaded files. 30-second cache.
POST /api/models/downloadDownload a model file to the PVC. Body: { "provider", "model", "url" }. URL must match a configured model.
GET /api/models/jobsList model operation jobs (download, delete — excludes scan jobs).
GET /api/models/jobs/:name/logsRead logs from a completed model operation job.
DELETE /api/models/:provider/:filenameDelete a model file from the PVC (creates a k8s Job).

Auth

EndpointDescription
GET /api/auth/oidcStart Authelia OIDC login (sets state cookie, redirects).
GET /api/auth/oidc/callbackExchange code → set auth_token cookie → redirect.
GET /api/auth/meReturns user object or null, plus app version string.
POST /api/auth/logoutClear auth_token.

Event Ingest

POST /api/events/ingest
Authorization: Bearer {api-key}
Content-Type: application/json

Body: { "source": "github", "event": "pull_request.opened", "payload": {...} }. Each agent with a matching enabled eventTriggers entry yields one IR.

Response: { "matched": n, "jobs": [{ "jobId", "agent" }, ...] }.


Webhooks

POST /api/webhooks/github
X-Hub-Signature-256: sha256=…
X-GitHub-Event: {event}

HMAC-verified GitHub webhook receiver. Resolves the WebhookSource CR (type github), reads the secret, normalizes the event, and creates IRs for matched agents. See GitHub Integration.


Callback Webhooks

When an IR has a callbackUrl, the engine POSTs at lifecycle points. Payloads are intentionally minimal — fetch full state via GET /api/jobs/:id.

{ "jobId": "ir-…", "phase": "in_progress", "metadata": {...} }
{ "jobId": "ir-…", "phase": "completed",   "metadata": {...} }
{ "jobId": "ir-…", "phase": "failed",      "details": "...", "metadata": {...} }

details only present on failed. Callbacks have a 10-second timeout and never affect IR status.