Agent provisioning flow
Overview
Console saves new Slack token Secrets from the channel setup modal through the existing Secrets API, then sends inline Configuration and ordinary Secret references to the provisioning API. Model authentication discovers models from an entered API key or service account token, then saves the credential as a Secret before provisioning. Presets retain their existing Secret binding. OCC queues setup work without creating placeholder resources. A worker creates the Configuration and Agent, grants the Agent access to accepted Secrets, provisions trusted-proxy runtime credentials, and admits the first deployment.
This flow ends at deployment submission. The controller worker and Harness execution topology own activation, runtime failures and later deployments.
Entry Points
- Console:
apps/controller/src/console/agents/create.mjs, with the shared Slack Secret select/create modal inapps/controller/src/console/channels/slack.mjs. - API:
packages/contracts/src/api/routes.ts:provisionAgent,apps/controller/src/index.ts:createFastifyApp, andpackages/occ/src/index.ts:OpenClawController.provisionAgent. - Preconditions: a ready Namespace, supported Dedicated runtime and selected Drivers, PostgreSQL-backed work storage, required Agent/Configuration/deploy permissions, exact Secret access and existing transactional IAM authority. No provisioning-input keyring is required.
Flow
graph TD
Console["<b>Console</b><br/>Save entered Secrets"] --> Secrets["<b>Existing Secrets API</b><br/>Return ordinary references"]
Secrets --> API["<b>Provision API</b><br/>Inline config and references"]
API --> Queue["<b>Existing work queue</b><br/>Return job handle"]
Queue --> Claim["<b>Worker</b><br/>Claim and authorize"]
Claim --> Config["<b>Create Configuration</b><br/>Record completed identity"]
Config --> Agent["<b>Create Agent</b><br/>Grant exact Secret access"]
Agent --> Transport["<b>Compute Driver</b><br/>Trusted-proxy credentials"]
Transport --> Deploy["<b>Ordinary deploy</b><br/>Record first revision"]
Deploy --> UI["<b>Agent deployment view</b><br/>Follow activation"]
Claim -->|Failure| Failed["<b>Retain outputs</b><br/>Retry known failures"]
Failed -->|Uncertain write| Recovery["<b>Recovery required</b><br/>Do not repeat blindly"]
classDef state fill:#EDF2F7,stroke:#879AB0,color:#25364A,stroke-width:1px
classDef operation fill:#EBF3F0,stroke:#7F9D93,color:#2B4038,stroke-width:1px
classDef condition fill:#F7F1E5,stroke:#B3A078,color:#514532,stroke-width:1px
class Console,Secrets,API,Queue state
class Claim,Config,Agent,Transport,Deploy,UI operation
class Failed,Recovery conditionExecution Trace
1. Console saves credentials and freezes a provisioning request
apps/controller/src/console/agents/create.mjs:renderCreateAgent
The Slack channel setup modal sends each new token to ordinary POST /namespaces/:namespaceId/secrets immediately, before an Agent exists. It clears entered values after the save attempt. Applying channel settings stages the returned references and environment bindings in the form. Cancelling the drawer discards its selections but retains created namespace Secrets. Model discovery uses the entered API key or service account token without saving it. Create Agent saves that credential as an ordinary Namespace Secret, clears the input, and reuses its returned reference for provisioning retries. Bound Presets retain their credential and provider. A lost Secret-save response needs recovery rather than automatic repetition.
Create Agent sends the parsed inline Configuration, ordinary Secret bindings, model-auth references, supported Agent options, selected repository bindings with an explicit access profile, and a stable request ID. The provisioning worker owns exact Secret grants; Slack has no special worker path. After an uncertain admission response, the Console resends the same request ID and accepted inputs, without resaving acknowledged Secrets.
On ordinary draft creation paths, Console creates the Configuration and Agent, then grants access to the selected Slack Secrets. A grant failure retains the saved Agent and offers Retry credential access on that Agent, without repeating creation.
2. OCC admits one job
packages/occ/src/index.ts:OpenClawController.provisionAgent
OCC validates the accepted Configuration, references, workspace inputs, supported execution mode and current authority. Before a new API request enters the write transaction, the selected ChannelDriver checks configured credentials through authorized Secret callbacks. The Slack Driver checks token roles and bot authentication; this does not pin Secret versions or add worker revalidation. The repository Driver validates current Namespace selections before job admission and again when the worker creates the Agent; deployment checks the exact Harness topology through the Compute Driver. It stores the accepted request and its deduplication fingerprint in agent_provisioning_work, then enqueues controller_work with work_kind = 'provisioning'. Agent and Configuration creation happen later. Identical actor/Namespace/request IDs return the same work; changed input conflicts.
The 202 response contains data.provisioning, with the work ID and status URL. Public progress exposes result IDs and safe errors without input values or backend credentials.
3. The worker creates resources and credentials
packages/occ/src/index.ts:OpenClawController.processAgentProvisioning
The existing worker dispatches the job under its queue claim. Before effects and result commits, OCC verifies current ownership, Namespace readiness and exact authority. Completed outputs are reused on retry. Configuration creation uses the accepted inline values and existing bindings. Once that Configuration exists, OCC creates a stopped Agent, persists its auth/provider/plugin/repository/workspace selections and grants its service principal exact Secret permissions.
The Compute Driver prepares runtime credentials through the existing credential path, without a loopback HTTP call. The Kubernetes Driver owns trusted-proxy configuration and generated credential protection; provisioning carries no gateway token or trust override.
4. Deployment becomes the lifecycle owner
packages/occ/src/index.ts:OpenClawController.deployAgent
The job admits one first revision and records its ID. Provisioning reports success at this handoff. apps/controller/src/console/agents/create.mjs:waitForProvisioning returns those IDs immediately; the submit handler opens Agent details for that revision without waiting for activation. The detail page's Deployment activity panel reads the recorded startup result and exposes Refresh deployment. Ordinary revision reconciliation owns startup, activation and runtime failure. Later deployments use the regular Deploy API.
5. Failures preserve useful outputs
packages/occ/src/state/postgres-state.ts:provisioning
Safe failed steps can retry under a fresh claim and authorization check. Completed resources are retained and reused. An unresolved external write keeps its exact target and ownership evidence; lease expiry or a not-found response alone does not justify dispatching it again. No provisioning rollback or Secret deletion runs.
While initialization owns an Agent, conflicting edits and manual deployment are guarded. Stop/Delete invalidate provisioning, and stale workers cannot hand off a deployment afterward. Ordinary deletion retains its lifecycle and in-flight credential safety. Because a cancelled provisioning never runs again, Agent deletion resolves an effect it left unsettled: it waits one worker lease after the cancellation, removes runtime credentials, and records the effect receipt in the same transaction as the finalizer. The wait is deferred and does not use deletion attempts. Namespace Secrets and completed Configurations remain available through their existing resource APIs.
Debugging and Verification
- Follow the returned
data.provisioning.urlor readGET /namespaces/:namespaceId/agents/provision/:workId. Failed work reports a safe error. Explicit retry uses the same URL plus/retryand an empty body. - Inspect
worker.completed,worker.errorand theagent_provisioningwork metric. PostgreSQL job state lives inocc.controller_workandocc.agent_provisioning_work. - Use
tests/integration/postgres-agent-provisioning.test.mjsfor persisted admission, deduplication, safe retry, retained outputs and authorization behavior. - Use Console browser coverage for channel Secret creation before provisioning, reference reuse after failure and job-to-deployment navigation. The disposable Kubernetes fixture proves actual Driver handoff, not native enrollment, model execution or Slack replies.
