Skip to content

feat(desktop): cap OpenClaw agent parallelism at 5 - #4019

Merged
wpfleger96 merged 4 commits into
mainfrom
duncan/openclaw-parallelism-cap
Aug 5, 2026
Merged

feat(desktop): cap OpenClaw agent parallelism at 5#4019
wpfleger96 merged 4 commits into
mainfrom
duncan/openclaw-parallelism-cap

Conversation

@wpfleger96

@wpfleger96 wpfleger96 commented Jul 31, 2026

Copy link
Copy Markdown
Member

OpenClaw connects to a single shared Gateway daemon. Spawning the default 10 ACP workers per agent is both resource-expensive and architecturally wrong — each worker opens a separate gateway connection. Tyler's ruling: cap at 5, lower if needed.

Contract

Store the requested value (1–32) verbatim at every persistence and wire boundary. Apply effective = min(requested, harness_cap) only at the four enforcement points:

Boundary Implementation
Local spawn BUZZ_ACP_AGENTS env var in child Command
Remote deploy launch.policy_env["BUZZ_ACP_AGENTS"] + legacy parallelism field
Restart badge SpawnConfigSnapshot.parallelism stores effective value; the diff surface displays what actually runs
UI copy Amber hint when requested > cap; no max attribute, no save-path clamp

BUZZ_ACP_AGENTS is added to RESERVED_ENV_KEYS — the Desktop resolves the effective value into policy_env; a user-supplied override in env would bypass the cap and is silently stripped.

Changes

managed_agents/parallelism.rs (new) — policy core:

  • OPENCLAW_MAX_PARALLELISM = 5
  • harness_max_parallelism(command) — keyed on normalize_command_identity so path prefixes, .exe suffixes, and other cosmetic differences are ignored
  • effective_parallelism(command, value) — identity for uncapped harnesses
  • acp_agents_value(command, parallelism)env("BUZZ_ACP_AGENTS", …) helper

runtime.rs — spawn clamp: BUZZ_ACP_AGENTS = acp_agents_value(effective_command, record.parallelism)

agents_deploy.rs — deploy egress clamp: build_deploy_payload resolves effective_parallelism once from descriptor.command; both launch.policy_env["BUZZ_ACP_AGENTS"] and the legacy top-level parallelism field use that value — the two are always consistent regardless of stale record.agent_command pins

spawn_snapshot.rsfrom_inputs stores effective_parallelism(&descriptor.command, record.parallelism) in the parallelism field. Over-cap edits that don't change the pool (e.g. 10 → 8, both clamp to 5 on OpenClaw) produce equal snapshots; cap crossings (8 → 3) produce different snapshots.

AcpRuntimeCatalogEntry.max_parallelism: Option<u32> — derived from the static definition command, not the probed entry.command (which may be null for unavailable entries), so unavailable OpenClaw entries still carry the cap. Propagated through all four catalog constructors (builtin discovery, preset catalog construction, custom discovery, custom-save response), IPC types (RawAcpRuntimeCatalogEntry.max_parallelism), and the frontend catalog type.

UIEditAgentAdvancedFields and PersonaAdvancedFields show an amber hint when selectedRuntime.maxParallelism is set and the current value exceeds it. Cap and label come from the catalog entry — no hardcoded 5 in TS. No max attribute on inputs; the input stays type="text" with 1–32 copy.

Docsdocs/remote-agents.md: BUZZ_ACP_AGENTS moved from the deliberately-non-reserved section to reserved; new contract documented. desktop/src/features/agents/AGENTS.md: command-keyed execution policy documented as the sanctioned second metadata source feeding the catalog projection.

Tests

Rust (parallelism.rs):

  • policy_tableharness_max_parallelism and effective_parallelism across all openclaw variants and uncapped harnesses
  • acp_agents_value_openclaw_above_cap_is_capped — spawn-env seam
  • override_direction_* — both override directions (openclaw runtime + goose override; goose runtime + openclaw override)
  • summary_persona_inherited_* — live persona wins over stale agent_command
  • snapshot_export_carries_requested_definition_parallelism — requested value travels wire/sync unchanged

Rust (spawn_snapshot/tests.rs):

  • openclaw_above_cap_parallelism_snapshots_equal — stored 10 vs 8, both clamp to 5 → snapshots equal
  • openclaw_cap_crossing_parallelism_snapshots_differ — 8 (clamps to 5) vs 3 → snapshots differ

Rust (discovery/presets.rs):

  • openclaw_preset_unavailable_carries_max_parallelism / openclaw_preset_available_carries_max_parallelism — catalog metadata present with command: null and with a resolved path

Rust (agents_deploy.rs):

  • launch_block_openclaw_over_cap_policy_env_is_capped — direct launch.policy_env seam
  • deploy_payload_json_stale_goose_record_live_openclaw_descriptor_both_capped — stale record.agent_command=goose, live descriptor=openclaw: both fields cap to 5
  • deploy_payload_json_stale_openclaw_record_live_goose_descriptor_both_uncapped — stale record.agent_command=openclaw, live descriptor=goose: both fields pass through requested
  • deploy_payload_json_explicit_openclaw_override_both_capped — explicit agent_command_override=openclaw: both fields cap to 5

Rust (persona_events/stale_pin_tests.rs):

  • apply_persona_snapshot_goose_to_custom_harness_drops_stale_goose_pin — custom-direction stale-pin drop (builtin pin → loaded custom harness via update_loaded_harness_registry)

TypeScript (agentParallelism.test.mjs):

  • parallelismCapHint — at/below cap (null), above cap (hint includes label and cap value), singular form for cap=1, uncapped harness (null)

TypeScript (tauri.test.mjs):

  • fromRawAcpRuntimeCatalogEntry round-trips max_parallelismmaxParallelism; absent when undefined

@wpfleger96
wpfleger96 requested a review from a team as a code owner July 31, 2026 21:39
@wpfleger96
wpfleger96 force-pushed the duncan/openclaw-parallelism-cap branch 8 times, most recently from 187ffbf to 3333dce Compare August 4, 2026 00:43
OpenClaw connects to a single shared Gateway daemon. Spawning the default
10 ACP workers per agent wastes resources and is architecturally wrong.
Tyler's ruling: cap at 5.

Contract: stored = requested; effective = min(requested, harness cap).
The cap is applied only where the value becomes a running worker-pool size.

- parallelism.rs: policy core — OPENCLAW_MAX_PARALLELISM=5,
  harness_max_parallelism(), effective_parallelism(), acp_agents_value().
  Keyed on normalize_command_identity so path prefixes and .exe suffix
  are handled.
- BUZZ_ACP_AGENTS added to RESERVED_ENV_KEYS: the Desktop resolves the
  effective value into launch.policy_env; a user-supplied override would
  bypass the cap against the single Gateway daemon.
- runtime.rs: spawn clamp — BUZZ_ACP_AGENTS = acp_agents_value(cmd, parallelism).
- agents_deploy.rs: deploy egress clamp — policy_env and legacy top-level
  parallelism field both project effective_parallelism.
- SpawnConfigSnapshot: stores effective parallelism so over-cap edits that
  don't change the running pool size (e.g. 10→8, both clamp to 5) don't
  raise a spurious restart badge. The diff surface displays effective value.
- AcpRuntimeCatalogEntry.max_parallelism: Option<u32> — derived from the
  static definition command (not the probed entry.command) so unavailable
  OpenClaw entries still carry the cap. Propagated through all four catalog
  constructors, IPC types, and the frontend catalog type.
- UI: amber hint on both EditAgentAdvancedFields and PersonaAdvancedFields
  when the selected harness has a cap and the requested value exceeds it.
  Allow-and-explain: no max attr, no save-path clamp, cap and label come
  from the catalog entry (no hardcoded 5 in TS).
- docs/remote-agents.md: BUZZ_ACP_AGENTS moved from deliberately-non-reserved
  to reserved; new contract documented.
- desktop/src/features/agents/AGENTS.md: command-keyed execution policy
  documented as the sanctioned second metadata source feeding catalog.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
@wpfleger96
wpfleger96 force-pushed the duncan/openclaw-parallelism-cap branch from 3333dce to 3c34e8a Compare August 4, 2026 18:54
…lelism.rs

hash_above_cap_equivalence and hash_cap_crossing_inequality in parallelism.rs
drove prospective_spawn_config_snapshot for the same two behaviors already
covered by openclaw_above_cap_parallelism_snapshots_equal and
openclaw_cap_crossing_parallelism_snapshots_differ in spawn_snapshot/tests.rs.

The snapshot-module seam tests are the stronger placement. Remove the
duplicate pair and its snapshot_for helper (~42 lines).

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewing on Wes Pfleger's behalf.

The executable launch block and the legacy top-level parallelism field can disagree for inherited or overridden harnesses. build_deploy_payload has already resolved the effective harness into descriptor and uses descriptor.command to cap launch.policy_env["BUZZ_ACP_AGENTS"] (lines 131–142), but deploy_payload_json recomputes the legacy value from record.agent_command (lines 185–189). That field is explicitly a stale create-time snapshot in several supported states: record_agent_command instead prefers agent_command_override, then record.runtime, then the live persona (managed_agents/discovery.rs:308–330). For example, an agent whose stored agent_command is goose but whose live persona now resolves to OpenClaw will execute with BUZZ_ACP_AGENTS=5 while the top-level field still says 10; the opposite transition reports 5 while running 10.

Please derive both projections from the same already-resolved descriptor (for example, pass the effective command/value into deploy_payload_json) and add regression coverage for stale persona inheritance and/or an explicit override. Otherwise the new "display/bookkeeping consistency" guarantee is precisely where the dungeon floor opens.

npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 and others added 2 commits August 4, 2026 17:30
Both the legacy top-level `parallelism` field and
`launch.policy_env["BUZZ_ACP_AGENTS"]` now derive from the same
resolved descriptor command rather than from `record.agent_command`.

Previously the legacy field called `effective_parallelism` on the
stale `record.agent_command` snapshot while the executable
`policy_env` used the live descriptor. For a persona-inherited harness
switch (e.g. record created as Goose, persona later changed to OpenClaw)
the two fields would disagree: policy_env would cap at 5 while the legacy
field would report the uncapped requested value.

`build_deploy_payload` now computes the effective value once from
`descriptor.command` and passes it into `deploy_payload_json` via a
`DeployProjections` struct alongside the other effective-config fields.
The three regression tests cover the stale-goose/live-openclaw,
stale-openclaw/live-goose, and explicit-override directions.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Picks up #4671 (multi-repository projects): adds BUZZ_ACP_DISPLAY_NAME
to launch.policy_env and RESERVED_ENV_KEYS. Auto-merged cleanly with
no conflicts in agents_deploy.rs, env_vars.rs, or runtime.rs.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewing on Wes Pfleger’s behalf.

The requested deploy correction is in place: build_deploy_payload computes effective parallelism once from the resolved descriptor.command, and both the executable launch.policy_env["BUZZ_ACP_AGENTS"] and legacy top-level parallelism now receive that same projection. The added stale-persona and explicit-override regression cases cover the mismatch that blocked the prior head.

I also reviewed the incremental fix and merge result; no new blocking issues found. CI is green at the reviewed head.

@wpfleger96
wpfleger96 merged commit 6c40ce3 into main Aug 5, 2026
26 checks passed
@wpfleger96
wpfleger96 deleted the duncan/openclaw-parallelism-cap branch August 5, 2026 20:09
wpfleger96 pushed a commit that referenced this pull request Aug 5, 2026
…arer-auth

* origin/main: (65 commits)
  fix(desktop): route macos notification clicks (#4799)
  feat(mobile): sync themes per community (#3767)
  feat(desktop): sync themes per community (#3653)
  feat(desktop): cap OpenClaw agent parallelism at 5 (#4019)
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)
  fix(desktop): allow shared agent mentions (#4913)
  Polish mobile top navigation (#4778)
  fix(release): tag immutable desktop candidates (#4811)
  fix(channels): restrict private-channel invitations (#4612)
  fix(acp): reject unattended permission requests (#4609)
  fix(workflow): bind trigger author to the signed event (#4607)
  fix(git): revoke access for banned relay members (#4608)
  fix(agent): recover from unsupported image input instead of poisoning the turn (#4896)
  Define private managed agent wire protocol (#4593)
  fix(mobile): serialize channel sections sync (#3165)
  fix(desktop): make missing-command error actionable for released builds (#4802)
  ...

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

# Conflicts:
#	CHANGELOG.md
wpfleger96 added a commit that referenced this pull request Aug 5, 2026
Resolve two conflicts:

1. crates/buzz-acp/src/config.rs: PermissionMode::BypassPermissions removed
   by main (#4609, security fix). Branch added PermissionMode::Auto and
   effort_level. Resolution: keep Auto and effort_level additions; drop
   BypassPermissions (aligns with #4609's intent that the variant cannot
   be restored by configuration). One test assertion for
   BypassPermissions.is_default() removed accordingly.

2. desktop/src-tauri/src/commands/agents_deploy.rs: branch added claude
   B2/I-4 tests (ANTHROPIC_MODEL routing, BUZZ_ACP_EFFORT_LEVEL); main
   added OpenClaw parallelism-cap tests via #4019. Resolution: keep both
   test sets; fix trailing blank line introduced by merge tool.

Also: desktop/src-tauri/src/managed_agents/parallelism.rs (new in main
via #4019) constructs ManagedAgentRecord in tests without the
effort_level field added by this branch. Added effort_level: None to the
test helper to satisfy the struct initializer.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 pushed a commit that referenced this pull request Aug 5, 2026
…ed-agent-store-merge

* origin/main: (24 commits)
  fix(reactions): support max-length custom emoji (#3833)
  feat(desktop): allow leaving your final community (#3621)
  fix(buzz-agent): recover from context-window 400s instead of sticking (#4946)
  docs(persona-pack): fix stale desktop import instructions (#4500)
  fix(desktop): route macos notification clicks (#4799)
  feat(mobile): sync themes per community (#3767)
  feat(desktop): sync themes per community (#3653)
  feat(desktop): cap OpenClaw agent parallelism at 5 (#4019)
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)
  fix(desktop): allow shared agent mentions (#4913)
  Polish mobile top navigation (#4778)
  fix(release): tag immutable desktop candidates (#4811)
  fix(channels): restrict private-channel invitations (#4612)
  fix(acp): reject unattended permission requests (#4609)
  fix(workflow): bind trigger author to the signed event (#4607)
  fix(git): revoke access for banned relay members (#4608)
  ...

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

# Conflicts:
#	desktop/src-tauri/src/managed_agents/runtime.rs
elifoster-block added a commit that referenced this pull request Aug 5, 2026
…p-csp

* origin/main: (66 commits)
  fix(reactions): support max-length custom emoji (#3833)
  feat(desktop): allow leaving your final community (#3621)
  fix(buzz-agent): recover from context-window 400s instead of sticking (#4946)
  docs(persona-pack): fix stale desktop import instructions (#4500)
  fix(desktop): route macos notification clicks (#4799)
  feat(mobile): sync themes per community (#3767)
  feat(desktop): sync themes per community (#3653)
  feat(desktop): cap OpenClaw agent parallelism at 5 (#4019)
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)
  fix(desktop): allow shared agent mentions (#4913)
  Polish mobile top navigation (#4778)
  fix(release): tag immutable desktop candidates (#4811)
  fix(channels): restrict private-channel invitations (#4612)
  fix(acp): reject unattended permission requests (#4609)
  fix(workflow): bind trigger author to the signed event (#4607)
  fix(git): revoke access for banned relay members (#4608)
  ...
tellaho added a commit that referenced this pull request Aug 5, 2026
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>

* origin/main:
  fix(reactions): support max-length custom emoji (#3833)
  feat(desktop): allow leaving your final community (#3621)
  fix(buzz-agent): recover from context-window 400s instead of sticking (#4946)
  docs(persona-pack): fix stale desktop import instructions (#4500)
  fix(desktop): route macos notification clicks (#4799)
  feat(mobile): sync themes per community (#3767)
  feat(desktop): sync themes per community (#3653)
  feat(desktop): cap OpenClaw agent parallelism at 5 (#4019)
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)
  fix(desktop): allow shared agent mentions (#4913)

Signed-off-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
wpfleger96 added a commit that referenced this pull request Aug 5, 2026
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

* origin/main:
  fix(reactions): support max-length custom emoji (#3833)
  feat(desktop): allow leaving your final community (#3621)
  fix(buzz-agent): recover from context-window 400s instead of sticking (#4946)
  docs(persona-pack): fix stale desktop import instructions (#4500)
  fix(desktop): route macos notification clicks (#4799)
  feat(mobile): sync themes per community (#3767)
  feat(desktop): sync themes per community (#3653)
  feat(desktop): cap OpenClaw agent parallelism at 5 (#4019)
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
tellaho added a commit that referenced this pull request Aug 5, 2026
…-setting

* origin/main:
  fix(reactions): support max-length custom emoji (#3833)
  feat(desktop): allow leaving your final community (#3621)
  fix(buzz-agent): recover from context-window 400s instead of sticking (#4946)
  docs(persona-pack): fix stale desktop import instructions (#4500)
  fix(desktop): route macos notification clicks (#4799)
  feat(mobile): sync themes per community (#3767)
  feat(desktop): sync themes per community (#3653)
  feat(desktop): cap OpenClaw agent parallelism at 5 (#4019)
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants