Rensei docs

Worker Fleet Migration

Worker fleet upgrade for on-prem deployments.

Upgrade your on-premises worker fleet from the legacy shared-key passthrough model to the platform-owned execution-capacity model with project-scoped authentication, short-lived runtime JWTs, and structured sandbox orchestration.

Architecture overview

The current execution-capacity model replaces the legacy projects.sandbox_* columns and global WORKER_API_KEY with a structured hierarchy:

Org
└── Execution Provider Pool  (local | docker | kubernetes | e2b | daytona | modal | vercel)
    └── Worker Host           (durable capacity, heartbeats)
        └── Worker            (per-session or host-spawned process)

Project
└── Execution Route           (allowed / preferred / forbidden / fallback pools)

The diagram below shows how a worker authenticates and claims work under the new model:

sequenceDiagram
    participant W as Worker daemon
    participant P as Platform API
    participant R as Redis queue

    W->>P: POST /api/workers/register<br/>Authorization: Bearer rsp_live_...
    P-->>W: { workerId, runtimeJwt, expiresAt }

    loop Every 30 s
        W->>P: POST /api/workers/{id}/heartbeat<br/>Bearer runtimeJwt
    end

    loop Poll for work
        W->>P: GET /api/workers/{id}/poll<br/>Bearer runtimeJwt
        P->>R: ZPOPMIN (atomic claim)
        R-->>P: QueuedWork item
        P-->>W: { sessionId, resolvedProfile, ... }
        W->>P: POST /api/sessions/{id}/claim
    end

Legacy projects.sandbox_* columns remain readable and writable during the transition. The compatibility layer translates them into an org execution pool and project route automatically - no immediate action required for existing projects. New code should use /api/execution/* and /api/projects/:projectId/execution-route.

Migration phases

Phases 1a through 2a are already landed in production. Phase 2b and beyond are in progress. The upgrade steps below reflect the current state.

Phase summary

PhaseStatusDescription
1a - backend foundationCompleteSchema, registration tokens, runtime JWTs, worker/session route port
1b - platform-owned worker routesCompleteAll worker + session HTTP endpoints owned by platform
1c - project settings UICompleteExecution settings at /[org]/[project]/settings/execution/
2a - Linear client in platformCompleteAll deferred session handlers ported; Linear OAuth in platform
2b - drop @renseiai/agentfactory-nextjsIn progressPort remaining webhook/OAuth passthroughs
2c - multi-tracker + multi-SCMPlannedIssueTrackerProvider / GitCredentialProvider interfaces
3 - sandbox provider interfacePlannedSandboxProvider.provision(spec) for on-demand workers
4 - cloud sandbox providersPlannedDaytona, E2B, Modal on-demand provisioning
6 - on-prem portabilityPlannedDocker image, Helm chart, swap-WorkOS-for-Keycloak

Upgrade your workers to runtime JWT auth

Legacy workers authenticate with a global WORKER_API_KEY. Platform-managed workers use short-lived runtime JWTs issued by the platform's /api/workers/register endpoint. The runtime JWT carries proj, org, sub, reg, and scope claims.

Create a registration token

In the platform UI, navigate to your project's Settings → Execution tab, or use the CLI:

rensei project tokens create \
  --project <project-slug> \
  --type registration \
  --name "my-worker-host"

The token is a rsp_live_… prefixed string. It is accepted only by /api/workers/register and cannot be used for any other endpoint.

Register the worker

Your worker daemon calls POST /api/workers/register with the registration token in the Authorization header:

curl -X POST https://app.rensei.ai/api/workers/register \
  -H "Authorization: Bearer rsp_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "version": "0.5.0",
    "capabilities": ["local"],
    "maxConcurrency": 4
  }'

The response includes a short-lived runtimeJwt and a workerId:

{
  "workerId": "wkr_abc123",
  "runtimeJwt": "eyJ...",
  "expiresAt": "2026-06-02T02:00:00Z"
}

Poll and heartbeat

Use the runtimeJwt as the bearer token for all subsequent worker calls:

# Poll for work
GET /api/workers/{workerId}/poll
Authorization: Bearer eyJ...

# Heartbeat (every 30s)
POST /api/workers/{workerId}/heartbeat
Authorization: Bearer eyJ...

The runtime JWT is short-lived. The worker SDK handles refresh automatically via /api/workers/{workerId}/lock-refresh.

Verify project routing

After the worker registers, confirm it appears under the correct project in the Admin UI at Workers or via:

rensei fleet status --project <project-slug>

The worker should appear with runtime: go or runtime: ts and a recent heartbeat.

Configure execution provider pools

Provider pools are org-scoped. Configure them at Settings → Execution at the org level (not per-project). Each pool has a providerId, mode, credential binding, and capacity policy.

Supported providers

ProviderModeNotes
localhost-session / localDaemon workers on the operator's own hardware
dockerOn-demanddockerode-based container provisioning
kubernetesOn-demandJob-based pod scheduling
e2bOn-demandPause/resume support
daytonaOn-demandREST-based workspace
modalOn-demandGPU workloads, 24h session ceiling
vercelOn-demandFirecracker microVM, no execCommand

Project execution routes

Each project declares which org pools it uses via a route policy. Set this at Settings → Execution → Route or via the API:

PUT /api/projects/{projectId}/execution-route
Content-Type: application/json
Authorization: Bearer rsk_live_...

{
  "allowed": ["pool_local_01"],
  "preferred": ["pool_local_01"],
  "forbidden": [],
  "fallback": null
}

preferred pools are tried first; fallback is used if all preferred and allowed pools are at capacity. The platform resolves the final pool on each dispatch and stamps it onto the queued session.

Auth modes and pool pinning

Two auth modes are pinned to local-capacity pools and cannot use cloud sandboxes:

  • host-session - requires executionProviderPools.providerId = 'local'
  • local - same constraint

Attempting to dispatch with these auth modes against a cloud pool (e2b, modal, etc.) will fail at pre-flight validation. See Auth modes for the full capability matrix.

Legacy compatibility layer

During the migration window, the legacy projects.sandbox_* columns continue to work. The compatibility layer translates them:

Legacy fieldNew model
projects.sandbox_providerorg pool with matching providerId
projects.sandbox_modepool mode setting
projects.sandbox_credential_idpool credential binding

Do not write new code against these columns. Use /api/execution/* and /api/projects/:projectId/execution-route for all new integrations.

Legacy worker key (transitional fallback)

The global WORKER_API_KEY fallback is transitional and will be removed when Phase 2b completes. Migrate your workers to registration tokens and runtime JWTs before that window closes.

Six session endpoints are still passthrough to the legacy @renseiai/agentfactory-nextjs package because they depend on the platform's Linear OAuth client, which was only brought in-platform during Phase 2a. These endpoints accept WORKER_API_KEY only - they will return 401 if you send a runtime JWT:

EndpointWhy still passthrough until Phase 2b
POST /api/sessions/{id}/statusTerminal transitions emit a Linear agent-session response activity to mark the session complete
POST /api/sessions/{id}/activityUses createAgentActivity from the Linear plugin
POST /api/sessions/{id}/completionBuilds completion comments via Linear plugin helpers
POST /api/sessions/{id}/progressCombines the in-process ring buffer with Linear createAgentActivity
POST /api/sessions/{id}/external-urlsCalls linearClient.updateAgentSession - canonical storage is Linear itself
POST /api/sessions/{id}/tool-errorUses reportEnvironmentIssue() from the Linear plugin

During the transition window: workers using runtime JWTs for all other endpoints must still send WORKER_API_KEY for these six. Both auth paths work simultaneously - this is intentional, not a gap.

Phase 2b will port all six endpoints to platform-native auth, after which the WORKER_API_KEY fallback will be removed from all handlers.

Ported vs. passthrough endpoint summary

Phases 1a-2a landed platform-owned versions of all worker and most session endpoints. Use this table to determine which auth token each endpoint accepts today:

EndpointAuth acceptedPlatform-owned?
POST /api/workers/registerrsp_live_* registration tokenYes
GET /api/workersRuntime JWTYes
GET /api/workers/{id}Runtime JWTYes
DELETE /api/workers/{id}Runtime JWTYes
POST /api/workers/{id}/heartbeatRuntime JWTYes
GET /api/workers/{id}/pollRuntime JWTYes
POST /api/sessions/{id}/claimRuntime JWTYes
POST /api/sessions/{id}/lock-refreshRuntime JWTYes
POST /api/sessions/{id}/transfer-ownershipRuntime JWTYes
GET /api/sessions/{id}/statusRuntime JWTYes
POST /api/sessions/{id}/statusWORKER_API_KEY onlyPhase 2b
POST /api/sessions/{id}/activityWORKER_API_KEY onlyPhase 2b
POST /api/sessions/{id}/completionWORKER_API_KEY onlyPhase 2b
POST /api/sessions/{id}/progressWORKER_API_KEY onlyPhase 2b
POST /api/sessions/{id}/external-urlsWORKER_API_KEY onlyPhase 2b
POST /api/sessions/{id}/tool-errorWORKER_API_KEY onlyPhase 2b

Verify a clean migration

Run through this checklist after upgrading your fleet:

[ ] All workers appear in /admin/workers with a recent heartbeat
[ ] No worker is using a WORKER_API_KEY-only auth path (check worker logs)
[ ] At least one session has been successfully dispatched and completed under the new fleet
[ ] Project execution routes are configured at Settings → Execution for every active project
[ ] shape census for SDLC workflows shows v1: 0 (separate migration - see SDLC v1→v2)

Source references

FileRole
platform/src/lib/project-runtime/Phase 1a: registration tokens, runtime JWTs
platform/src/app/api/workers/register/route.tsWorker registration endpoint
platform/src/app/api/workers/[id]/poll/route.tsPoll endpoint (atomic ZPOPMIN + project filter)
platform/src/lib/providers/linear/client-resolver.tsPer-org Linear client (Phase 2a)
platform/src/lib/activity-buffer/index.tsIn-process ring buffer for session activities
platform/docs/worker-fleet-migration.mdFull internal phased design doc

On this page