From f9ed6b66bf728d3a60a1dcf57b04e86e37985d36 Mon Sep 17 00:00:00 2001 From: FFE Hive Date: Mon, 29 Jun 2026 01:11:00 -0500 Subject: [PATCH] [plan-graph] remove experimental teams gate Co-authored-by: multica-agent --- hive/references/agent-teams-guide.md | 12 ++++----- .../steps/daily-ceremony/step-07-kick-off.md | 2 +- skills/execute/SKILL.md | 4 +-- skills/execute/references/team-execution.md | 2 +- skills/hive/skills/design-dispatch/SKILL.md | 20 +++++++------- .../skills/design-review-dispatch/SKILL.md | 20 +++++++------- skills/hive/skills/execute-dispatch/SKILL.md | 20 +++++++------- skills/hive/skills/planning-routing/SKILL.md | 2 +- skills/hive/skills/review-dispatch/SKILL.md | 20 +++++++------- skills/review/SKILL.md | 2 +- tests/execute-dispatch-sandcastle.test.js | 27 ++++++++++++------- .../execute-dispatch-multica.test.mjs | 25 +++++++++++------ 12 files changed, 83 insertions(+), 73 deletions(-) diff --git a/hive/references/agent-teams-guide.md b/hive/references/agent-teams-guide.md index 551a0a36..81197973 100644 --- a/hive/references/agent-teams-guide.md +++ b/hive/references/agent-teams-guide.md @@ -1,20 +1,20 @@ # Agent Teams Guide -Agent teams are Claude Code's multi-agent system for parallel task execution. When available, Hive uses agent teams to run independent stories from an epic concurrently: the lead describes the work in natural language, and the Claude Code runtime materializes teammates automatically. Each story becomes a task assigned to a separate teammate with its own context window. When agent teams are unavailable, Hive falls back to sequential story execution. +Agent teams are Claude Code's multi-agent system for parallel task execution. Hive uses agent teams to run independent stories from an epic concurrently: the lead describes the work in natural language, and the Claude Code runtime materializes teammates automatically. Each story becomes a task assigned to a separate teammate with its own context window. Parallel execution is the default for eligible story sets; projects opt out with `hive.config.yaml` → `execution.parallel_teams: false` or with the `--sequential` flag. Reference: https://code.claude.com/docs/en/agent-teams ## Detection -Check whether agent teams are enabled by reading the environment variable: +Agent teams are GA. Do not gate parallel execution on the legacy experimental environment variable: ``` -CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 # or "true" +CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS ``` -If this env var is not set (or is `0`/`false`), agent teams are unavailable. The execute command must always fall back to sequential execution gracefully — no error messages, no warnings. Agent teams are an optimization, not a requirement. +If this env var is present in an existing `.env` file, Hive treats it as deprecated and ignored for compatibility. It must not produce an error, warning, or sequential fallback. -Also check `hive.config.yaml` → `execution.parallel_teams: true`. Both the env var AND the config must be enabled. +Check `hive.config.yaml` → `execution.parallel_teams`. Parallel dispatch is enabled by default when the setting is absent. Only `execution.parallel_teams: false` opts out and routes eligible story sets to sequential execution. ## Mapping Epics to Teams @@ -69,7 +69,7 @@ This is a separate variant, not the default auto-spawn path. The default path as ## Execution Flow 1. **Lead reads the epic** — loads all story YAMLs, builds the dependency graph -2. **Lead checks detection** — if `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is not `1`, falls back to sequential +2. **Lead checks dispatch config** — if `execution.parallel_teams: false` or `--sequential` is set, falls back to sequential 3. **Lead spawns the team** — describes tasks and dependencies in natural language 4. **Teammates self-claim work** — each teammate picks the next available unblocked task 5. **Dependencies auto-unblock** — when a task completes, tasks that depended on it become available diff --git a/hive/workflows/steps/daily-ceremony/step-07-kick-off.md b/hive/workflows/steps/daily-ceremony/step-07-kick-off.md index 4a3be259..314a81c4 100644 --- a/hive/workflows/steps/daily-ceremony/step-07-kick-off.md +++ b/hive/workflows/steps/daily-ceremony/step-07-kick-off.md @@ -41,7 +41,7 @@ Analyze the approved stories for independence: - **Dependent stories:** must execute in dependency order Decision matrix: -- If 2+ independent stories AND `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`: use TeamCreate for parallel execution +- If 2+ independent stories and `execution.parallel_teams` is not `false`: use parallel execution - If all stories are dependent (chain): execute sequentially using the Agent tool - If mixed: group independent stories into a parallel batch, chain dependent stories sequentially diff --git a/skills/execute/SKILL.md b/skills/execute/SKILL.md index 3a33f954..4c81e9be 100644 --- a/skills/execute/SKILL.md +++ b/skills/execute/SKILL.md @@ -31,11 +31,11 @@ If the kickoff checks pass, proceed silently. Only surface kickoff-related outpu | Scope | Tool | Why | |---|---|---| -| **Parallelizing stories across the epic** | `Agent(name:)` or cmux panes | Stories run as named teammates via `Agent(name:)` — one call per story — or in separate cmux panes when `execution.terminal_mux: cmux`. Parallel teammates require `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` (research preview, NOT GA); sequential is the guaranteed floor when the flag is unset. | +| **Parallelizing stories across the epic** | `Agent(name:)` or cmux panes | Stories run as named teammates via `Agent(name:)` — one call per story — or in separate cmux panes when `execution.terminal_mux: cmux`. Parallel teammates are the default for eligible story sets; `execution.parallel_teams: false` or `--sequential` forces sequential execution. | | **Sequential workflow steps within a single story** | `Agent` | Steps within a teammate's pane run inline — this is correct | | **Specialist phase teams (pre-exec, post-exec)** | `Agent(name:)` | Specialist teams are independent coordination units — one `Agent(name:)` call per specialist team | -Spawn each story as a named teammate via `Agent(name:)`. Sequential execution (no flag needed) is always available and is the guaranteed floor. Parallel teammates across stories require `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` (research preview, NOT GA). +Spawn each story as a named teammate via `Agent(name:)`. Sequential execution remains available through `execution.parallel_teams: false` or `--sequential`. ## Process diff --git a/skills/execute/references/team-execution.md b/skills/execute/references/team-execution.md index 93746c8b..18420bb6 100644 --- a/skills/execute/references/team-execution.md +++ b/skills/execute/references/team-execution.md @@ -4,7 +4,7 @@ > > **Parallel-dispatch gate (ed-7):** `Agent(name:)` (this section) and the cmux variant (below) are two of the four in-scope dispatch points for the parallel gate. Each story listed in the prompt must already carry the `parallel_allowed: true` + `parallel_rationale ∈ {variation, read-only, bounded-slice}` pair emitted by `/plan` Phase C step 13, with `bounded-slice` stories declaring disjoint `files_to_modify[]`. The gate runs in `execute-dispatch` Step 1.5 *before* this section's prompt is generated — by the time you arrive here, the depth-0 `unblocked_stories[]` set has already been validated and `mode_decision` was downgraded to `sequential` on any violation. See [`hive/references/parallel-call-sites.md`](../../../hive/references/parallel-call-sites.md) §2 for the catalog of in-scope sites. -Spawn each story as a named teammate via `Agent(name: "{story-id}")` — one `Agent(name:)` call per story, and each call's prompt carries ONLY that one story's scope. Never combine two or more stories into a single teammate's prompt. Parallel teammates require `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` (research preview, NOT GA); sequential is the guaranteed floor when the flag is unset. Generate a natural-language prompt per story that describes that single story's task: +Spawn each story as a named teammate via `Agent(name: "{story-id}")` — one `Agent(name:)` call per story, and each call's prompt carries ONLY that one story's scope. Never combine two or more stories into a single teammate's prompt. Parallel teammates are the default for eligible story sets; `execution.parallel_teams: false` or `--sequential` forces sequential execution. Generate a natural-language prompt per story that describes that single story's task: ``` Execute story "{story-id}" of the "{epic-id}" epic. diff --git a/skills/hive/skills/design-dispatch/SKILL.md b/skills/hive/skills/design-dispatch/SKILL.md index 14e05e19..b1d77dbd 100644 --- a/skills/hive/skills/design-dispatch/SKILL.md +++ b/skills/hive/skills/design-dispatch/SKILL.md @@ -14,7 +14,7 @@ Atomic skill, NOT inline `/design` prose. It resolves the pre-execution dispatch Call this skill once at the single `/design` dispatch point where the caller has both the story execution context and the current workflow handoff context. -**Inputs:** `env` with `HIVE_SESSIONS_ENABLED`, `HIVE_PARALLEL_TEAMS`, `HIVE_TERMINAL_MUX`, `HIVE_DESIGN_MODE`, and `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`; parsed root `hive.config.yaml` containing `sessions.enabled`, `parallel_teams` or `execution.parallel_teams`, and `execution.terminal_mux`; parsed consumer `.pHive/hive.config.yaml` or `None`; parsed graduation registry workflow list or `None`; `workflow_name`; `epic_id` when known; `arguments` containing the `--sequential` flag state plus dependency-depth summary; and `unblocked_stories[]` — the depth-0 ready stories at this dispatch tick, each carrying at minimum `id`, `parallel_allowed`, `parallel_rationale`, and (for `parallel_rationale: bounded-slice`) `files_to_modify[]` whose entries name the declared touch-set. Empty or single-element `unblocked_stories[]` is valid: the parallel-dispatch gate (Step 1.5) skips when there is no peer set to gate. +**Inputs:** `env` with `HIVE_SESSIONS_ENABLED`, `HIVE_PARALLEL_TEAMS`, `HIVE_TERMINAL_MUX`, and `HIVE_DESIGN_MODE`; parsed root `hive.config.yaml` containing `sessions.enabled`, `parallel_teams` or `execution.parallel_teams`, and `execution.terminal_mux`; parsed consumer `.pHive/hive.config.yaml` or `None`; parsed graduation registry workflow list or `None`; `workflow_name`; `epic_id` when known; `arguments` containing the `--sequential` flag state plus dependency-depth summary; and `unblocked_stories[]` — the depth-0 ready stories at this dispatch tick, each carrying at minimum `id`, `parallel_allowed`, `parallel_rationale`, and (for `parallel_rationale: bounded-slice`) `files_to_modify[]` whose entries name the declared touch-set. Empty or single-element `unblocked_stories[]` is valid: the parallel-dispatch gate (Step 1.5) skips when there is no peer set to gate. **Outputs:** `mode_decision` enum `sessions | team | team-cmux | sequential | sandcastle | multica | cc-workflows`; `mode_reason` as a one-line string explaining the selected mode; `runner_path` enum `hive-dag | orchestrator-narrated`; `runner_reason` as a one-line string explaining the selected runner path; `field_sources` map covering `sessions_enabled`, `parallel_teams`, `terminal_mux`, `executor`, `execution_mode`, and `execution_runtime` so callers can attribute every resolution; `field_sources.execution_runtime.epic_override` as a `` traceability field when a per-epic disposition file overrode the auto heuristic, otherwise `null`; and `gate_violations[]` — a list of `{story_id, reason}` records emitted by Step 1.5 when the parallel-dispatch gate refuses fan-out. `gate_violations[]` is `[]` on healthy runs and on any `mode_decision` other than `team | team-cmux | sessions | sandcastle | multica | cc-workflows`. @@ -29,11 +29,10 @@ Call this skill once at the single `/design` dispatch point where the caller has The mode selection uses these exact match conditions, in precedence order: 1. **Sessions check:** match when `env.HIVE_SESSIONS_ENABLED` is exactly truthy by string normalization (`1`, `true`, or `"true"`) OR root `hive.config.yaml` has `sessions.enabled: true`. This wins over every team or sequential input. -2. **Teams availability check:** match only when `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is exactly truthy by string normalization (`1`, `true`, or `"true"`). -3. **Parallel teams config check:** evaluate the resolved `parallel_teams` boolean from Step 0 below. The legacy reads (root `hive.config.yaml` `parallel_teams: true` or `execution.parallel_teams: true`) become the config-source path inside Step 0; this step matches whenever the resolved boolean is `true`. -4. **Concurrency and flag check:** match only when the dependency-depth summary shows more than one story at the same depth AND `arguments` does not contain `--sequential`. +2. **Parallel teams config check:** evaluate the resolved `parallel_teams` boolean from Step 0 below. The legacy reads (root `hive.config.yaml` `parallel_teams` or `execution.parallel_teams`) become the config-source path inside Step 0; this step matches whenever the resolved boolean is `true`. +3. **Concurrency and flag check:** match only when the dependency-depth summary shows more than one story at the same depth AND `arguments` does not contain `--sequential`. -The cmux variant is not a separate team gate. After all four team checks match, return `team-cmux` when the resolved `terminal_mux` from Step 0 equals `cmux`; otherwise return `team`. +The cmux variant is not a separate team gate. After the parallel config and concurrency checks match, return `team-cmux` when the resolved `terminal_mux` from Step 0 equals `cmux`; otherwise return `team`. ## Sane Defaults @@ -151,12 +150,11 @@ When the first branch above selects `mode_decision ∈ {cc-workflows, multica}`, Evaluate in this order and stop at the first selected path: 1. If the sessions check matches, return `mode_decision=sessions` and `mode_reason=sessions-enabled`. -2. If `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is not truthy, return `mode_decision=sequential` and `mode_reason=agent-teams-env-disabled`. -3. If parallel teams config is not true, return `mode_decision=sequential` and `mode_reason=parallel-teams-disabled`. -4. If the dependency-depth summary does not show multiple stories at the same depth, return `mode_decision=sequential` and `mode_reason=no-peer-depth`. -5. If `--sequential` is present in `arguments`, return `mode_decision=sequential` and `mode_reason=sequential-flag`. -6. When the resolved `terminal_mux` field (from Step 0, env > config > default) equals `cmux`, return `mode_decision=team-cmux` and `mode_reason=team-checks-pass-cmux`. -7. Otherwise return `mode_decision=team` and `mode_reason=team-checks-pass`. +2. If parallel teams config is not true, return `mode_decision=sequential` and `mode_reason=parallel-teams-disabled`. +3. If the dependency-depth summary does not show multiple stories at the same depth, return `mode_decision=sequential` and `mode_reason=no-peer-depth`. +4. If `--sequential` is present in `arguments`, return `mode_decision=sequential` and `mode_reason=sequential-flag`. +5. When the resolved `terminal_mux` field (from Step 0, env > config > default) equals `cmux`, return `mode_decision=team-cmux` and `mode_reason=team-checks-pass-cmux`. +6. Otherwise return `mode_decision=team` and `mode_reason=team-checks-pass`. This preserves precedence: `sessions > team-cmux > team > sequential`. diff --git a/skills/hive/skills/design-review-dispatch/SKILL.md b/skills/hive/skills/design-review-dispatch/SKILL.md index 79c4f2f6..d073ac4d 100644 --- a/skills/hive/skills/design-review-dispatch/SKILL.md +++ b/skills/hive/skills/design-review-dispatch/SKILL.md @@ -14,7 +14,7 @@ Atomic skill, NOT inline `/design-review` prose. It resolves the pre-execution d Call this skill once at the single `/design-review` dispatch point where the caller has both the story execution context and the current workflow handoff context. -**Inputs:** `env` with `HIVE_SESSIONS_ENABLED`, `HIVE_PARALLEL_TEAMS`, `HIVE_TERMINAL_MUX`, `HIVE_DESIGN_REVIEW_MODE`, and `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`; parsed root `hive.config.yaml` containing `sessions.enabled`, `parallel_teams` or `execution.parallel_teams`, and `execution.terminal_mux`; parsed consumer `.pHive/hive.config.yaml` or `None`; parsed graduation registry workflow list or `None`; `workflow_name`; `epic_id` when known; `arguments` containing the `--sequential` flag state, `--skip` flag state, `--artifact-target` value, and dependency-depth summary; and `unblocked_stories[]` — the depth-0 ready stories at this dispatch tick, each carrying at minimum `id`, `parallel_allowed`, `parallel_rationale`, and (for `parallel_rationale: bounded-slice`) `files_to_modify[]` whose entries name the declared touch-set. Empty or single-element `unblocked_stories[]` is valid: the parallel-dispatch gate (Step 1.5) skips when there is no peer set to gate. +**Inputs:** `env` with `HIVE_SESSIONS_ENABLED`, `HIVE_PARALLEL_TEAMS`, `HIVE_TERMINAL_MUX`, and `HIVE_DESIGN_REVIEW_MODE`; parsed root `hive.config.yaml` containing `sessions.enabled`, `parallel_teams` or `execution.parallel_teams`, and `execution.terminal_mux`; parsed consumer `.pHive/hive.config.yaml` or `None`; parsed graduation registry workflow list or `None`; `workflow_name`; `epic_id` when known; `arguments` containing the `--sequential` flag state, `--skip` flag state, `--artifact-target` value, and dependency-depth summary; and `unblocked_stories[]` — the depth-0 ready stories at this dispatch tick, each carrying at minimum `id`, `parallel_allowed`, `parallel_rationale`, and (for `parallel_rationale: bounded-slice`) `files_to_modify[]` whose entries name the declared touch-set. Empty or single-element `unblocked_stories[]` is valid: the parallel-dispatch gate (Step 1.5) skips when there is no peer set to gate. **Flag pass-through:** `--skip accessibility`, `--skip animations`, and `--artifact-target {design|implementation}` must be forwarded verbatim to the resolved mode atom (`design-review-mode-multica` or `design-review-mode-cc-workflows`). This dispatch skill does NOT consume or strip those flags — it captures them from `arguments` and passes them along unchanged so the receiving atom can apply the same gate-check and pipeline-skipping logic as the inline path. @@ -31,11 +31,10 @@ Call this skill once at the single `/design-review` dispatch point where the cal The mode selection uses these exact match conditions, in precedence order: 1. **Sessions check:** match when `env.HIVE_SESSIONS_ENABLED` is exactly truthy by string normalization (`1`, `true`, or `"true"`) OR root `hive.config.yaml` has `sessions.enabled: true`. This wins over every team or sequential input. -2. **Teams availability check:** match only when `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is exactly truthy by string normalization (`1`, `true`, or `"true"`). -3. **Parallel teams config check:** evaluate the resolved `parallel_teams` boolean from Step 0 below. The legacy reads (root `hive.config.yaml` `parallel_teams: true` or `execution.parallel_teams: true`) become the config-source path inside Step 0; this step matches whenever the resolved boolean is `true`. -4. **Concurrency and flag check:** match only when the dependency-depth summary shows more than one story at the same depth AND `arguments` does not contain `--sequential`. +2. **Parallel teams config check:** evaluate the resolved `parallel_teams` boolean from Step 0 below. The legacy reads (root `hive.config.yaml` `parallel_teams` or `execution.parallel_teams`) become the config-source path inside Step 0; this step matches whenever the resolved boolean is `true`. +3. **Concurrency and flag check:** match only when the dependency-depth summary shows more than one story at the same depth AND `arguments` does not contain `--sequential`. -The cmux variant is not a separate team gate. After all four team checks match, return `team-cmux` when the resolved `terminal_mux` from Step 0 equals `cmux`; otherwise return `team`. +The cmux variant is not a separate team gate. After the parallel config and concurrency checks match, return `team-cmux` when the resolved `terminal_mux` from Step 0 equals `cmux`; otherwise return `team`. ## Sane Defaults @@ -153,12 +152,11 @@ When the first branch above selects `mode_decision ∈ {cc-workflows, multica}`, Evaluate in this order and stop at the first selected path: 1. If the sessions check matches, return `mode_decision=sessions` and `mode_reason=sessions-enabled`. -2. If `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is not truthy, return `mode_decision=sequential` and `mode_reason=agent-teams-env-disabled`. -3. If parallel teams config is not true, return `mode_decision=sequential` and `mode_reason=parallel-teams-disabled`. -4. If the dependency-depth summary does not show multiple stories at the same depth, return `mode_decision=sequential` and `mode_reason=no-peer-depth`. -5. If `--sequential` is present in `arguments`, return `mode_decision=sequential` and `mode_reason=sequential-flag`. -6. When the resolved `terminal_mux` field (from Step 0, env > config > default) equals `cmux`, return `mode_decision=team-cmux` and `mode_reason=team-checks-pass-cmux`. -7. Otherwise return `mode_decision=team` and `mode_reason=team-checks-pass`. +2. If parallel teams config is not true, return `mode_decision=sequential` and `mode_reason=parallel-teams-disabled`. +3. If the dependency-depth summary does not show multiple stories at the same depth, return `mode_decision=sequential` and `mode_reason=no-peer-depth`. +4. If `--sequential` is present in `arguments`, return `mode_decision=sequential` and `mode_reason=sequential-flag`. +5. When the resolved `terminal_mux` field (from Step 0, env > config > default) equals `cmux`, return `mode_decision=team-cmux` and `mode_reason=team-checks-pass-cmux`. +6. Otherwise return `mode_decision=team` and `mode_reason=team-checks-pass`. This preserves precedence: `sessions > team-cmux > team > sequential`. diff --git a/skills/hive/skills/execute-dispatch/SKILL.md b/skills/hive/skills/execute-dispatch/SKILL.md index 7115fd9b..9f094f1c 100644 --- a/skills/hive/skills/execute-dispatch/SKILL.md +++ b/skills/hive/skills/execute-dispatch/SKILL.md @@ -11,7 +11,7 @@ Atomic skill, NOT inline `/execute` prose. It resolves the pre-execution dispatc Call this skill once at the single `/execute` dispatch point where the caller has both the story execution context and the current workflow handoff context. -**Inputs:** `env` with `HIVE_SESSIONS_ENABLED`, `HIVE_PARALLEL_TEAMS`, `HIVE_TERMINAL_MUX`, `HIVE_EXECUTION_MODE`, and `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`; parsed root `hive.config.yaml` containing `sessions.enabled`, `parallel_teams` or `execution.parallel_teams`, and `execution.terminal_mux`; parsed consumer `.pHive/hive.config.yaml` or `None`; parsed graduation registry workflow list or `None`; `workflow_name`; `epic_id` when known; `arguments` containing the `--sequential` flag state plus dependency-depth summary; and `unblocked_stories[]` — the depth-0 ready stories at this dispatch tick, each carrying at minimum `id`, `parallel_allowed`, `parallel_rationale`, and (for `parallel_rationale: bounded-slice`) `files_to_modify[]` whose entries name the declared touch-set. Empty or single-element `unblocked_stories[]` is valid: the parallel-dispatch gate (Step 1.5) skips when there is no peer set to gate. +**Inputs:** `env` with `HIVE_SESSIONS_ENABLED`, `HIVE_PARALLEL_TEAMS`, `HIVE_TERMINAL_MUX`, and `HIVE_EXECUTION_MODE`; parsed root `hive.config.yaml` containing `sessions.enabled`, `parallel_teams` or `execution.parallel_teams`, and `execution.terminal_mux`; parsed consumer `.pHive/hive.config.yaml` or `None`; parsed graduation registry workflow list or `None`; `workflow_name`; `epic_id` when known; `arguments` containing the `--sequential` flag state plus dependency-depth summary; and `unblocked_stories[]` — the depth-0 ready stories at this dispatch tick, each carrying at minimum `id`, `parallel_allowed`, `parallel_rationale`, and (for `parallel_rationale: bounded-slice`) `files_to_modify[]` whose entries name the declared touch-set. Empty or single-element `unblocked_stories[]` is valid: the parallel-dispatch gate (Step 1.5) skips when there is no peer set to gate. **Outputs:** `mode_decision` enum `sessions | team | team-cmux | sequential | sandcastle | multica | cc-workflows`; `mode_reason` as a one-line string explaining the selected mode; `runner_path` enum `hive-dag | orchestrator-narrated`; `runner_reason` as a one-line string explaining the selected runner path; `field_sources` map covering `sessions_enabled`, `parallel_teams`, `terminal_mux`, `executor`, `execution_mode`, and `execution_runtime` so callers can attribute every resolution; `field_sources.execution_runtime.epic_override` as a `` traceability field when a per-epic disposition file overrode the auto heuristic, otherwise `null`; and `gate_violations[]` — a list of `{story_id, reason}` records emitted by Step 1.5 when the parallel-dispatch gate refuses fan-out. `gate_violations[]` is `[]` on healthy runs and on any `mode_decision` other than `team | team-cmux | sessions | sandcastle | multica | cc-workflows`. @@ -26,11 +26,10 @@ Call this skill once at the single `/execute` dispatch point where the caller ha The mode selection uses these exact match conditions, in precedence order: 1. **Sessions check:** match when `env.HIVE_SESSIONS_ENABLED` is exactly truthy by string normalization (`1`, `true`, or `"true"`) OR root `hive.config.yaml` has `sessions.enabled: true`. This wins over every team or sequential input. -2. **Teams availability check:** match only when `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is exactly truthy by string normalization (`1`, `true`, or `"true"`). -3. **Parallel teams config check:** evaluate the resolved `parallel_teams` boolean from Step 0 below. The legacy reads (root `hive.config.yaml` `parallel_teams: true` or `execution.parallel_teams: true`) become the config-source path inside Step 0; this step matches whenever the resolved boolean is `true`. -4. **Concurrency and flag check:** match only when the dependency-depth summary shows more than one story at the same depth AND `arguments` does not contain `--sequential`. +2. **Parallel teams config check:** evaluate the resolved `parallel_teams` boolean from Step 0 below. The legacy reads (root `hive.config.yaml` `parallel_teams` or `execution.parallel_teams`) become the config-source path inside Step 0; this step matches whenever the resolved boolean is `true`. +3. **Concurrency and flag check:** match only when the dependency-depth summary shows more than one story at the same depth AND `arguments` does not contain `--sequential`. -The cmux variant is not a separate team gate. After all four team checks match, return `team-cmux` when the resolved `terminal_mux` from Step 0 equals `cmux`; otherwise return `team`. +The cmux variant is not a separate team gate. After the parallel config and concurrency checks match, return `team-cmux` when the resolved `terminal_mux` from Step 0 equals `cmux`; otherwise return `team`. ## Sane Defaults @@ -150,12 +149,11 @@ When the first branch above selects `mode_decision ∈ {cc-workflows, multica}`, Evaluate in this order and stop at the first selected path: 1. If the sessions check matches, return `mode_decision=sessions` and `mode_reason=sessions-enabled`. -2. If `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is not truthy, return `mode_decision=sequential` and `mode_reason=agent-teams-env-disabled`. -3. If parallel teams config is not true, return `mode_decision=sequential` and `mode_reason=parallel-teams-disabled`. -4. If the dependency-depth summary does not show multiple stories at the same depth, return `mode_decision=sequential` and `mode_reason=no-peer-depth`. -5. If `--sequential` is present in `arguments`, return `mode_decision=sequential` and `mode_reason=sequential-flag`. -6. When the resolved `terminal_mux` field (from Step 0, env > config > default) equals `cmux`, return `mode_decision=team-cmux` and `mode_reason=team-checks-pass-cmux`. -7. Otherwise return `mode_decision=team` and `mode_reason=team-checks-pass`. +2. If parallel teams config is not true, return `mode_decision=sequential` and `mode_reason=parallel-teams-disabled`. +3. If the dependency-depth summary does not show multiple stories at the same depth, return `mode_decision=sequential` and `mode_reason=no-peer-depth`. +4. If `--sequential` is present in `arguments`, return `mode_decision=sequential` and `mode_reason=sequential-flag`. +5. When the resolved `terminal_mux` field (from Step 0, env > config > default) equals `cmux`, return `mode_decision=team-cmux` and `mode_reason=team-checks-pass-cmux`. +6. Otherwise return `mode_decision=team` and `mode_reason=team-checks-pass`. This preserves precedence: `sessions > team-cmux > team > sequential`. diff --git a/skills/hive/skills/planning-routing/SKILL.md b/skills/hive/skills/planning-routing/SKILL.md index a33fbe70..9746c64f 100644 --- a/skills/hive/skills/planning-routing/SKILL.md +++ b/skills/hive/skills/planning-routing/SKILL.md @@ -115,7 +115,7 @@ Use `routing_decisions` to assemble one conceptual planning team: H/V, structured-outline sign-off) and MUST present and wait at them locally after the graph completes. Do not also create local teammates for a multica-routed persona unless DAG fallback is triggered. -- **Direct path (`Agent(name:)`):** collect every persona routed `direct` and spawn each as an `Agent(name:)` teammate. Parallel dispatch requires `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` (research preview, NOT GA); without the flag, execution is SEQUENTIAL — the guaranteed floor. Use Step 0.4 and include only direct-routed personas in `## Team Members`. +- **Direct path (`Agent(name:)`):** collect every persona routed `direct` and spawn each as an `Agent(name:)` teammate. Parallel dispatch is the default for eligible teammate sets; `execution.parallel_teams: false` or `--sequential` forces sequential execution. Use Step 0.4 and include only direct-routed personas in `## Team Members`. - **Codex path (`agent-spawn` -> `codex-invoke`):** for each persona routed `codex`, create a separate persistent-pane teammate through `agent-spawn`, passing full persona context, resolved paths, memory loading context, and the same planning-team coordination context direct teammates receive. Mixed teams are valid. Some planning personas may come from diff --git a/skills/hive/skills/review-dispatch/SKILL.md b/skills/hive/skills/review-dispatch/SKILL.md index 4f868c5f..ba9b876f 100644 --- a/skills/hive/skills/review-dispatch/SKILL.md +++ b/skills/hive/skills/review-dispatch/SKILL.md @@ -14,7 +14,7 @@ Atomic skill, NOT inline `/review` prose. It resolves the pre-execution dispatch Call this skill once at the single `/review` dispatch point where the caller has both the story execution context and the current workflow handoff context. -**Inputs:** `env` with `HIVE_SESSIONS_ENABLED`, `HIVE_PARALLEL_TEAMS`, `HIVE_TERMINAL_MUX`, `HIVE_REVIEW_MODE`, and `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`; parsed root `hive.config.yaml` containing `sessions.enabled`, `parallel_teams` or `execution.parallel_teams`, and `execution.terminal_mux`; parsed consumer `.pHive/hive.config.yaml` or `None`; parsed graduation registry workflow list or `None`; `workflow_name`; `epic_id` when known; `arguments` containing the `--sequential` flag state and dependency-depth summary; and `unblocked_stories[]` — the depth-0 ready stories at this dispatch tick, each carrying at minimum `id`, `parallel_allowed`, `parallel_rationale`, and (for `parallel_rationale: bounded-slice`) `files_to_modify[]` whose entries name the declared touch-set. Empty or single-element `unblocked_stories[]` is valid: the parallel-dispatch gate (Step 1.5) skips when there is no peer set to gate. +**Inputs:** `env` with `HIVE_SESSIONS_ENABLED`, `HIVE_PARALLEL_TEAMS`, `HIVE_TERMINAL_MUX`, and `HIVE_REVIEW_MODE`; parsed root `hive.config.yaml` containing `sessions.enabled`, `parallel_teams` or `execution.parallel_teams`, and `execution.terminal_mux`; parsed consumer `.pHive/hive.config.yaml` or `None`; parsed graduation registry workflow list or `None`; `workflow_name`; `epic_id` when known; `arguments` containing the `--sequential` flag state and dependency-depth summary; and `unblocked_stories[]` — the depth-0 ready stories at this dispatch tick, each carrying at minimum `id`, `parallel_allowed`, `parallel_rationale`, and (for `parallel_rationale: bounded-slice`) `files_to_modify[]` whose entries name the declared touch-set. Empty or single-element `unblocked_stories[]` is valid: the parallel-dispatch gate (Step 1.5) skips when there is no peer set to gate. **Flag pass-through:** `--sequential` must be forwarded verbatim to the resolved mode atom (`review-mode-multica` or `review-mode-cc-workflows`). This dispatch skill does NOT consume or strip that flag — it captures it from `arguments` and passes it along unchanged so the receiving atom can apply the same gate-check and pipeline-skipping logic as the inline path. @@ -31,11 +31,10 @@ Call this skill once at the single `/review` dispatch point where the caller has The mode selection uses these exact match conditions, in precedence order: 1. **Sessions check:** match when `env.HIVE_SESSIONS_ENABLED` is exactly truthy by string normalization (`1`, `true`, or `"true"`) OR root `hive.config.yaml` has `sessions.enabled: true`. This wins over every team or sequential input. -2. **Teams availability check:** match only when `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is exactly truthy by string normalization (`1`, `true`, or `"true"`). -3. **Parallel teams config check:** evaluate the resolved `parallel_teams` boolean from Step 0 below. The legacy reads (root `hive.config.yaml` `parallel_teams: true` or `execution.parallel_teams: true`) become the config-source path inside Step 0; this step matches whenever the resolved boolean is `true`. -4. **Concurrency and flag check:** match only when the dependency-depth summary shows more than one story at the same depth AND `arguments` does not contain `--sequential`. +2. **Parallel teams config check:** evaluate the resolved `parallel_teams` boolean from Step 0 below. The legacy reads (root `hive.config.yaml` `parallel_teams` or `execution.parallel_teams`) become the config-source path inside Step 0; this step matches whenever the resolved boolean is `true`. +3. **Concurrency and flag check:** match only when the dependency-depth summary shows more than one story at the same depth AND `arguments` does not contain `--sequential`. -The cmux variant is not a separate team gate. After all four team checks match, return `team-cmux` when the resolved `terminal_mux` from Step 0 equals `cmux`; otherwise return `team`. +The cmux variant is not a separate team gate. After the parallel config and concurrency checks match, return `team-cmux` when the resolved `terminal_mux` from Step 0 equals `cmux`; otherwise return `team`. ## Sane Defaults @@ -153,12 +152,11 @@ When the first branch above selects `mode_decision ∈ {cc-workflows, multica}`, Evaluate in this order and stop at the first selected path: 1. If the sessions check matches, return `mode_decision=sessions` and `mode_reason=sessions-enabled`. -2. If `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is not truthy, return `mode_decision=sequential` and `mode_reason=agent-teams-env-disabled`. -3. If parallel teams config is not true, return `mode_decision=sequential` and `mode_reason=parallel-teams-disabled`. -4. If the dependency-depth summary does not show multiple stories at the same depth, return `mode_decision=sequential` and `mode_reason=no-peer-depth`. -5. If `--sequential` is present in `arguments`, return `mode_decision=sequential` and `mode_reason=sequential-flag`. -6. When the resolved `terminal_mux` field (from Step 0, env > config > default) equals `cmux`, return `mode_decision=team-cmux` and `mode_reason=team-checks-pass-cmux`. -7. Otherwise return `mode_decision=team` and `mode_reason=team-checks-pass`. +2. If parallel teams config is not true, return `mode_decision=sequential` and `mode_reason=parallel-teams-disabled`. +3. If the dependency-depth summary does not show multiple stories at the same depth, return `mode_decision=sequential` and `mode_reason=no-peer-depth`. +4. If `--sequential` is present in `arguments`, return `mode_decision=sequential` and `mode_reason=sequential-flag`. +5. When the resolved `terminal_mux` field (from Step 0, env > config > default) equals `cmux`, return `mode_decision=team-cmux` and `mode_reason=team-checks-pass-cmux`. +6. Otherwise return `mode_decision=team` and `mode_reason=team-checks-pass`. This preserves precedence: `sessions > team-cmux > team > sequential`. diff --git a/skills/review/SKILL.md b/skills/review/SKILL.md index 780593c9..db0f1afd 100644 --- a/skills/review/SKILL.md +++ b/skills/review/SKILL.md @@ -34,7 +34,7 @@ See [`hive/references/skill-prelude.md`](../../hive/references/skill-prelude.md) Call `skills/hive/skills/review-dispatch/SKILL.md` once before doing any other work. Pass: -- `env` — current process environment (at minimum `HIVE_SESSIONS_ENABLED`, `HIVE_PARALLEL_TEAMS`, `HIVE_TERMINAL_MUX`, `HIVE_REVIEW_MODE`, `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`) +- `env` — current process environment (at minimum `HIVE_SESSIONS_ENABLED`, `HIVE_PARALLEL_TEAMS`, `HIVE_TERMINAL_MUX`, `HIVE_REVIEW_MODE`) - `rootConfig` — parsed root `hive.config.yaml` - `consumerConfig` — parsed `.pHive/hive.config.yaml` or `None` - `graduationRegistry` — parsed graduation registry workflow list or `None` diff --git a/tests/execute-dispatch-sandcastle.test.js b/tests/execute-dispatch-sandcastle.test.js index 50ab3f4a..d98eaa35 100644 --- a/tests/execute-dispatch-sandcastle.test.js +++ b/tests/execute-dispatch-sandcastle.test.js @@ -17,7 +17,7 @@ * AC-2 config execution.mode=sandcastle (env unset) → source=config * AC-3 neither env nor config → source=default, existing resolution unchanged * AC-4 no-regression: sessions mode still wins when sessions_enabled=true - * AC-5 no-regression: sequential mode when agent-teams disabled + * AC-5 no-regression: sequential mode when execution.parallel_teams=false * AC-6 telemetry line includes execution_mode={source} * AC-7 env HIVE_EXECUTION_MODE set to unknown value → not sandcastle (ignored) */ @@ -74,9 +74,9 @@ function resolveDispatch(env = {}, config = {}) { const sessionsSource = env.HIVE_SESSIONS_ENABLED != null ? 'env' : (config.sessions && config.sessions.enabled != null ? 'config' : 'default'); - const agentTeamsEnabled = - env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === '1' || - env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === 'true'; + const parallelTeams = + config.parallel_teams != null ? config.parallel_teams + : (config.execution && config.execution.parallel_teams != null ? config.execution.parallel_teams : true); // Step 1 – standard mode resolution (sandcastle already excluded above) let mode_decision; @@ -85,9 +85,9 @@ function resolveDispatch(env = {}, config = {}) { if (sessionsEnabled) { mode_decision = 'sessions'; mode_reason = 'sessions-enabled'; - } else if (!agentTeamsEnabled) { + } else if (parallelTeams !== true) { mode_decision = 'sequential'; - mode_reason = 'agent-teams-env-disabled'; + mode_reason = 'parallel-teams-disabled'; } else { // Simplified: no depth/cmux checks in this fixture — return team mode_decision = 'team'; @@ -156,10 +156,19 @@ test('AC-4b (no-regression): sessions wins when sessions.enabled:true in config' assert.equal(result.field_sources.execution_mode, 'default'); }); -test('AC-5 (no-regression): sequential when agent-teams env disabled', () => { - const result = resolveDispatch({}, {}); +test('AC-5 (no-regression): sequential when execution.parallel_teams=false', () => { + const result = resolveDispatch( + {}, + { execution: { parallel_teams: false } } + ); assert.equal(result.mode_decision, 'sequential'); - assert.equal(result.mode_reason, 'agent-teams-env-disabled'); + assert.equal(result.mode_reason, 'parallel-teams-disabled'); +}); + +test('AC-5b (no-regression): default parallel teams route does not require env gate', () => { + const result = resolveDispatch({}, {}); + assert.equal(result.mode_decision, 'team'); + assert.equal(result.mode_reason, 'team-checks-pass'); }); test('AC-6: telemetry line includes execution_mode={source}', () => { diff --git a/tests/hive-lib/execute-dispatch-multica.test.mjs b/tests/hive-lib/execute-dispatch-multica.test.mjs index 5586fa0d..d716196a 100644 --- a/tests/hive-lib/execute-dispatch-multica.test.mjs +++ b/tests/hive-lib/execute-dispatch-multica.test.mjs @@ -49,9 +49,6 @@ function resolveExecutionMode({ ) { modeDecision = "sessions"; modeReason = "sessions-enabled"; - } else if (!truthy(env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS)) { - modeDecision = "sequential"; - modeReason = "agent-teams-env-disabled"; } else if (config.execution?.parallel_teams === false) { modeDecision = "sequential"; modeReason = "parallel-teams-disabled"; @@ -110,11 +107,12 @@ test("AC3: env multica wins over config sandcastle", () => { test("AC4: unknown config execution.mode falls through without error", () => { const result = resolveExecutionMode({ config: { execution: { mode: "bogus" } }, + hasPeerDepth: true, }); assert.equal(result.field_sources.execution_mode, "default"); - assert.equal(result.mode_decision, "sequential"); - assert.equal(result.mode_reason, "agent-teams-env-disabled"); + assert.equal(result.mode_decision, "team"); + assert.equal(result.mode_reason, "team-checks-pass"); }); test("AC5: multica participates in the Step 1.5 parallel gate", () => { @@ -127,10 +125,21 @@ test("AC5: multica participates in the Step 1.5 parallel gate", () => { assert.equal(result.parallel_gate_runs, true); }); -test("AC6: no execution_mode override defaults through to sequential", () => { - const result = resolveExecutionMode(); +test("AC6: no execution_mode override defaults to parallel when peer depth exists", () => { + const result = resolveExecutionMode({ hasPeerDepth: true }); + + assert.equal(result.field_sources.execution_mode, "default"); + assert.equal(result.mode_decision, "team"); + assert.equal(result.mode_reason, "team-checks-pass"); +}); + +test("AC7: execution.parallel_teams=false routes to sequential", () => { + const result = resolveExecutionMode({ + config: { execution: { parallel_teams: false } }, + hasPeerDepth: true, + }); assert.equal(result.field_sources.execution_mode, "default"); assert.equal(result.mode_decision, "sequential"); - assert.equal(result.mode_reason, "agent-teams-env-disabled"); + assert.equal(result.mode_reason, "parallel-teams-disabled"); });