Rensei docs
Worker Protocol

Poll & Heartbeat

poll/heartbeat, batchWork, gitCredentials.

Once registered, a worker runs a continuous loop: it sends a heartbeat to report its health and polls for new work. This page describes both endpoints and the full structure of the poll response, including batch work items and git credentials.

Heartbeat

Send a heartbeat on the interval provided by the registration response (heartbeatIntervalSeconds). A missed heartbeat causes the platform to mark the worker as unhealthy and eventually stop dispatching new sessions to it.

Daemon-native heartbeat

POST /v1/daemon/heartbeat
Authorization: Bearer <runtimeJwt>
Content-Type: application/json

Request body

{
  "workerId": "wkr_01abc...",
  "hostname": "build-host-01",
  "status": "idle",
  "activeSessions": 0,
  "maxSessions": 4,
  "region": "us-east-1",
  "capabilities": ["code-execution"],
  "version": "0.11.0"
}
FieldTypeRequiredDescription
workerIdstringYesWorker ID from registration
hostnamestringYesHuman-readable host identifier
statusstringYesOne of: idle, busy, draining
activeSessionsnumberYesCurrent number of active sessions
maxSessionsnumberYesMaximum concurrent session capacity
regionstringNoGeographic region
capabilitiesstring[]NoDeclared capability tokens
versionstringNoDaemon version

Success response (200)

{
  "ok": true,
  "serverTimeMs": 1748880000000
}

AF-compatible heartbeat

POST /api/workers/{workerId}/heartbeat
Authorization: Bearer <runtimeJwt>
Content-Type: application/json

Request body

{
  "status": "idle",
  "activeSessions": 0,
  "maxSessions": 4
}

Poll for work

Poll returns any sessions queued for this worker, plus inbox messages and optional batch work items.

GET /api/workers/{workerId}/poll
Authorization: Bearer <runtimeJwt>

The platform enforces that the JWT sub claim matches the {workerId} URL parameter. A mismatched token returns 403 Forbidden.

Poll response

{
  "work": [
    {
      "sessionId": "sess_01abc...",
      "issueId": "linear:abc123",
      "projectId": "proj_01abc...",
      "workType": "feature",
      "agentCard": { "... agent card object ..." },
      "systemPromptOverride": null,
      "gitCredentials": {
        "token": "ghp_...",
        "host": "github.com",
        "expiresAt": "2026-06-02T13:00:00Z"
      }
    }
  ],
  "inboxMessages": [],
  "hasInboxMessages": false,
  "preClaimed": true,
  "claimedSessionIds": ["sess_01abc..."],
  "batchWork": []
}

Work item fields

FieldTypeDescription
sessionIdstringUnique session ID. Use in all session lifecycle calls.
issueIdstringProvider-namespaced issue identifier (e.g. linear:ABC-123)
projectIdstringPlatform project ID
workTypestringSDLC work type: feature, bug_fix, refactor, research, etc.
agentCardobjectResolved agent card for this session (includes system prompt, capabilities, tool config)
systemPromptOverridestring | nullOverride system prompt, if set on the session (takes precedence over agent card)
gitCredentialsobject | nullShort-lived git credentials for repo access
authModestringAuth mode for this session: byok, metered, shared, host-session, local

gitCredentials

When the session requires repository access, gitCredentials provides a short-lived token:

{
  "token": "ghs_...",
  "host": "github.com",
  "username": "x-access-token",
  "expiresAt": "2026-06-02T13:00:00Z"
}

Configure git to use it:

git config --global credential.helper store
echo "https://x-access-token:${GIT_TOKEN}@github.com" > ~/.git-credentials

Batch work items

Workers that advertise the code-survival-scan capability receive batchWork[] items in addition to session-based work. These are code survival analysis tasks dispatched in bulk.

{
  "batchWork": [
    {
      "batchItemId": "batch_01abc...",
      "type": "code-survival-scan",
      "payload": {
        "repository": "github.com/my-org/my-repo",
        "pool": "RW3",
        "commitRange": "abc123..def456"
      }
    }
  ]
}

Declare the capability at registration to receive these items:

{
  "registrationToken": "rsk_live_...",
  "capabilities": ["code-execution", "code-survival-scan"]
}

Inbox messages

The inboxMessages array carries out-of-band signals for the worker - for example, a user's nudge prompt sent via the Public Sessions API or a stop signal.

{
  "inboxMessages": [
    {
      "messageId": "msg_01abc...",
      "type": "prompt",
      "payload": { "text": "Focus on the error handling in the login flow." }
    }
  ],
  "hasInboxMessages": true
}

ACK inbox messages after processing them:

curl -X POST "https://app.rensei.ai/api/sessions/sess_01abc.../inbox/ack" \
  -H "Authorization: Bearer <runtimeJwt>" \
  -H "Content-Type: application/json" \
  -d '{"messageId": "msg_01abc..."}'

Pre-claim semantics

When preClaimed is true, the platform has atomically reserved the returned sessions for this worker. The worker must either begin execution or explicitly return the session. There is no separate "claim" step - sessions returned in a poll response are already owned by the calling worker.

Worker loop example (TypeScript)

async function workerLoop(workerId: string, jwt: string) {
  while (true) {
    // Heartbeat
    await fetch(`https://app.rensei.ai/v1/daemon/heartbeat`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${jwt}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ workerId, status: 'idle', activeSessions: 0, maxSessions: 4 }),
    });

    // Poll
    const pollRes = await fetch(
      `https://app.rensei.ai/api/workers/${workerId}/poll`,
      { headers: { Authorization: `Bearer ${jwt}` } }
    );
    const { work, inboxMessages } = await pollRes.json();

    for (const session of work) {
      // dispatch session to agent subprocess
    }

    await sleep(5000); // use pollIntervalSeconds from registration
  }
}

On this page