Skip to content

Conductor mode

Conductor mode is how LumenFlow lets a cloud control plane — or any remote surface speaking the control-plane SDK — observe and drive a local workspace without breaking the evidence-based control-plane contract. The kernel emits a schema-versioned event stream, packs expose their tools and approvals through a scoped HTTP surface, and every remote action lands in the same audit log as a local one.

This page walks the end-to-end flow: enrollment, tool discovery, scoped invocation, event stream, abort + recovery. For the architectural locks behind every decision on this page, see ADR-013 (conductor-mode pack surfaces) and ADR-011 (conductor-mode kernel surfaces).

1. Enroll

Workspace mints an enrollment token whose subject claim identifies the workspace (or phone device). Token goes to the cloud once, over out-of-band channels. No credentials in the repo.

2. Discover

Cloud hits GET /tools on the sidecar. Response lists every pack-registered tool, its scope, its required approvals, and its schema — derived from the pack manifest, not from prose.

3. Invoke

Cloud issues POST /tools/:name with a scoped token. Kernel routes the call through the tool-dispatch path, records an agent-runtime:tool_called event, and returns the tool’s structured result.

4. Observe

Every emitter call — turn start, turn complete, gate outcome, approval request — flows through buildKernelEventV2 and lands in the cloud event stream with a content-hashed event_id for idempotent consumption.

Enrollment issues a token whose subject is the authoritative identity for every outbound event and every inbound tool invocation. Per ADR-013 §5, cloud must not trust a from field in a request body; it trusts the token subject on the authenticated connection.

Two enrollment shapes exist:

ShapeSubject formatUse
Workspace<workspace_id>Outbound events, inbound tool POSTs
Phone device<workspace_id>:phone:<device_id>Phone-originated inbound commands

The device-registration record maps device_id to a human-readable name. Cloud writes both the raw subject and the resolved device name into the audit log — per-device attribution is load-bearing for the conductor UI.

POST /api/v1/workspaces/enroll
Authorization: Bearer <operator-token>
Content-Type: application/json

{ "workspace_id": "ws-42", "kind": "workspace" }

Response carries the issued token; the operator installs it into the local workspace state (.lumenflow/state/conductor/enrollment.json). The sidecar reads this token on startup and uses its subject claim as the from field on every emitted event.

Once enrolled, the cloud can enumerate the pack-registered tool surface:

GET /tools
Authorization: Bearer <scoped-token>

Response shape (excerpt):

{
  "schema_version": 2,
  "tools": [
    {
      "name": "sidekick:channel_send",
      "pack": "sidekick",
      "scope": "agent:execute-turn",
      "required_approvals": ["sidekick:channel_send"],
      "input_schema": { "type": "object", "required": ["channel_id", "envelope"] },
      "output_schema": { "type": "object" }
    },
    {
      "name": "software-delivery:wu_claim",
      "pack": "software-delivery",
      "scope": "workspace",
      "input_schema": { "type": "object", "required": ["wu_id", "lane"] },
      "output_schema": { "type": "object" }
    }
  ]
}

Every tool in the response corresponds to a manifest-declared entry on a registered pack. Manifest discovery is declarative — no reflection, no code-gen. The cloud builds its registry from this response and refreshes on workspace state change events.

3. Scoped invocation — POST /tools/:name

Section titled “3. Scoped invocation — POST /tools/:name”

Tool calls are authenticated by the scoped token; the token’s scope claim governs which tools it may invoke. A token issued for workspace scope cannot call a tool that requires agent:execute-turn.

POST /tools/software-delivery:wu_claim
Authorization: Bearer <scoped-token>
Content-Type: application/json

{
  "wu_id": "WU-2744",
  "lane": "Content: Site Comms"
}

The kernel’s tool-dispatch path:

  1. Validates the scoped token (subject, scope, expiry).
  2. Resolves the tool from the pack manifest.
  3. Enforces the required_approvals surface, if any (approval providers registered on the workspace).
  4. Invokes the tool handler.
  5. Emits agent-runtime:tool_called with tool_name, a content hash of the envelope, and the resolved tool result outcome.
  6. Returns the tool’s structured result synchronously.

The tool call is the audit record. No fast path, no direct imports around the tool-dispatch layer. A tool invocation that did not go through this path did not happen, from the audit trail’s perspective.

4. Event stream — at-least-once, per-channel ordered

Section titled “4. Event stream — at-least-once, per-channel ordered”

The kernel and registered packs emit a stream of typed events to the cloud. Every emission is built through buildKernelEventV2 (see Events contract) and carries:

FieldMeaning
schema_version2 for conductor-mode events (the 1 variants are legacy task_* kinds).
kind<pack-slug>:<event_name> (or unprefixed for kernel-intrinsic kinds).
event_idContent-hashed string. Cloud dedupes replays by this key.
timestampRFC 3339 emission time.
fromWorkspace or phone-device identity, sourced from the token subject claim.
Payload fieldsKind-specific. Tagged union in @lumenflow/conductor-sdk.

Delivery is at-least-once (ADR-013 §2). Cloud subscribers must be idempotent — content-hashed event_id provides the dedup key, but the handler still has to tolerate re-delivery of the same event after a network retry.

Ordering is per-channel only (ADR-013 §3). Within a single channel (the HTTP sidecar transport, or a phone POST endpoint, or a sidekick bridge instance), emission order is preserved. Across channels, cloud reconciles from emitted_at + seq.

The §4 split rule in ADR-013 is enumerated, not per-emitter:

Kind classPath
agent-runtime:turn_*, software-delivery:gate_*, observational telemetryEphemeral (fail-silent on disconnect)
sidekick:approval_requestedQueue + replay
sidekick:command_received (inbound)Queue + replay
conductor:recovery_requested (inbound)Queue + replay

Ephemeral events are dropped silently when the cloud endpoint is unreachable — cloud reconstructs observational state from whatever arrives later. Commands and approvals live in .lumenflow/state/conductor/outbox/ until the sidecar reconnects, then drain FIFO.

A turn that aborts mid-flight carries a cleanup_status and an optional recovery_action string (ADR-013 §1):

{
  "schema_version": 2,
  "kind": "agent-runtime:turn_aborted",
  "cleanup_status": "needs_recovery",
  "recovery_action": "wu:recover --id WU-2744"
}
  • clean — no state mutation; no recovery needed.
  • partial — some mutations rolled back; state self-consistent but incomplete. recovery_action names the next step as prose.
  • needs_recovery — state inconsistent; recovery_action names a verbatim command. Cloud surfaces it as a button/hint but does not execute it. The operator confirms.

wu:recover is not auto-triggered. State-mutating commands require explicit operator consent; that rule is the seam between an observable control plane and a remote-execution control plane, and it is non-negotiable.

A concrete example. The operator, via the conductor UI, asks the cloud to claim WU-2744 and run its gates. The wire trace, in order:

  1. Operator → cloud UI. “Claim WU-2744 on Content: Site Comms.”

  2. Cloud → sidecar. POST /tools/software-delivery:wu_claim with {wu_id: "WU-2744", lane: "Content: Site Comms"}.

  3. Sidecar → cloud. Sync response with the resolved worktree path.

  4. Kernel → cloud. Event: software-delivery:wu_claimed with event_id and from: ws-42. Ephemeral. Cloud subscriber upserts.

  5. Cloud → sidecar. POST /tools/agent:execute-turn with {goal: "run gates on WU-2744"}.

  6. Kernel → cloud. Event: agent-runtime:turn_started. Ephemeral.

  7. Kernel → cloud. Event: agent-runtime:tool_called with tool_name: "software-delivery:gates". Ephemeral.

  8. Kernel → cloud. Event: software-delivery:gate_passed. Ephemeral.

  9. Kernel → cloud. Event: agent-runtime:turn_completed. Ephemeral.

  10. Sidecar → cloud. Sync response with the turn result and evidence references.

Every step is auditable. The local workspace has a stamp for every event; the cloud has a dedup-stable log; the operator never has to trust either side’s prose.