Skip to content

feat(daemon): support per-provider concurrency for parallel agent execution on single machine #6

Description

@returnSGD

Motivation

Currently, a single daemon registers only 1 runtime per provider CLI (e.g., one claude runtime). This means only one Claude Code Agent can run at a time on a given machine, regardless of how many CPU cores are available. Users with multi-core machines should be able to run multiple Claude Code instances in parallel, each handling independent tasks.

Root Cause

The limit comes from daemon registration in remote-daemon.ts:

// Only 1 runtime per detected provider
runtimes: detected.map((provider) => ({
  provider: provider.provider,
  name: `${config.runtimeName} · ${provider.label}`,
  ...
}))

The activeRuntimes Set tracks whether a runtime is busy. Each runtime handles only one task at a time. To support concurrency, N runtimes of the same provider must be registered.

Required Changes

P0 — Agent-level task mutual exclusion (packages/db/src/task-queue.tsclaimNextQueuedTaskForRuntimeSync)

Two claude runtimes must not execute tasks for the same Agent simultaneously. The claim query should skip tasks whose agent already has a claimed or running task.

P0 — workDir isolation (packages/daemon/src/remote-daemon.tsresolveRemoteTaskWorkDir)

Channel-scoped task workDirs use the pattern channels/{threadId}/{agentId}/. Two runtimes executing for the same agent+channel would share the same workDir. When concurrency > 1, workDir paths must include a runtime instance suffix as a physical isolation safeguard.

P1 — Auto Continuation concurrency guard (packages/services/src/automations/auto-continuation.ts)

continueAutoContinuationAfterTaskSync should check whether the agent already has a claimed/running task before creating a new continuation, preventing duplicate continuations under concurrency.

P2 — CLI flag and help text (packages/daemon/src/remote-daemon.ts)

Add --provider-concurrency flag and AGENT_SPACE_PROVIDER_CONCURRENCY env variable. Default to 1 for backward compatibility.

What Does NOT Need Changes

  • AgentRouter / Claude adapter — each invocation spawns an independent subprocess, naturally concurrency-safe
  • Task queue — already claims tasks per runtimeId
  • Server-side registration API — transparent to multiple runtimes of the same provider
  • Approval flow — scoped per taskId, no shared state

Estimated Diff

~60–80 lines, concentrated in daemon/src/remote-daemon.ts and db/src/task-queue.ts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions