refactor: remove bespoke Agent Teams machinery; expose as optional flag#240
Conversation
…e as optional flag Deletes the agent-teams skill, all eight teams-variant command files, and every teamsEnabled / teams manifest field / applyTeamsConfig / stripTeamsConfig touch-point across the CLI. The Claude Code experimental teammate mode is re-exposed as a single optional flag in the existing FLAG_REGISTRY (defaultEnabled: false), giving users devflow flags --enable agent-teams to opt in without a bespoke pipeline. Two migrations clean up stale teammateMode:"auto" written by prior Devflow installs: a global migration for ~/.claude/settings.json and a per-project migration for the project .claude/settings.json. Helpers extracted into src/cli/utils/teammate-mode-cleanup.ts. Applies ADR-001 exception (minimum migration only). Per PF-009, full grep verification performed after changes. BREAKING: devflow init --teams/--no-teams options removed. Use devflow flags --enable agent-teams instead.
- installer.ts: collapse dead -teams.md filter to install every .md unconditionally (rename baseCommands → commandFiles); no teams variants exist anymore (AC13/AC17, plan §D) - teammate-mode-cleanup.ts: delete redundant async file-path variant (zero production call sites); migrations use the sync wrapper, uninstall uses the string→string primitive — collapses to one coherent surface per 'one async pattern' - teammate-mode-cleanup.test.ts: drop the obsolete async describe block + import - uninstall.ts / post-install.ts: route teammateMode strip through the shared stripDevflowTeammateModeFromJson primitive (DRY)
/debug no longer uses the Agent Teams subsystem — it runs competing-hypothesis investigation via regular parallel subagents. Update the description in all three locations (plugins.ts, marketplace.json, plugin.json) to reflect this.
… Remove all bespoke Agent Teams documentation and update references across CLAUDE.md, cli-reference, skills-architecture, file-organization, and three plugin READMEs. Add agent-teams as an optional Claude Code flag (default OFF) accessible via devflow flags --enable agent-teams. Drop the --teams/--no-teams init flags from cli-reference. Note the breaking change in CHANGELOG under Unreleased. Co-Authored-By: Claude <noreply@anthropic.com>
|
src/cli/utils/teammate-mode-cleanup.ts:57-61 — Swallowed write error breaks the documented retry (MEDIUM, ~85%) The Bounded/benign impact — the orphaned Fix: Let the write error propagate (matches MIGRATION_PURGE_STALE_MEMORY_MARKERS at migrations.ts:882-884) or correct the misleading comment. Distinguish "no change needed" from "write failed". |
|
tests/skill-references.test.ts:570 & :602 — Dead The sets claim agent-teams doc cleanup is "pending / separate PR," but commit 378d0a2 already removed every agent-teams doc reference in this same branch (verified: zero matches in READMEs and skills-architecture.md). The guards are dead code with factually-wrong comments and they permanently mask the canonical-name stale-doc guard (PF-009). Fix: Delete both sets and their two |
|
src/cli/commands/init.ts:991 — The kept loop iterates installer.ts:164 wipes Fix: Unconditionally sweep |
Summary: PR #240 Approved with ConditionsThis is a high-quality, well-executed removal refactor (−4131/+601 lines). tsc compiles with zero errors, all 395 tests pass, no orphaned references survive, and the flag re-exposure is idiomatic. Overall RecommendationAPPROVE with three should-fix conditions. No merge-blocking issues. Reviewer scores 8–10/10 across all dimensions. Should-Fix Items (≥80% confidence)1. HIGH:
2. HIGH: Dead test guards masking regression (Consistency/Testing)
3. MEDIUM: Swallowed write error defeats retry (Reliability)
Documentation Corrections (MEDIUM, ~95%)(a) PR description vs commit state: The PR body says markdown docs are "intentionally left for a separate docs-only PR," but commit 378d0a2 already removed all agent-teams references. Fix: Update the description to state docs are complete in this branch. (b) Helper name mismatch: The PR body names the helpers CHANGELOG (LOW, ~80%)The new flag entry says it "sets Reconciled Non-Blocking FindingsAsync conversion (sync I/O in async pool): The review flagged Test coverage gap: The per-project migration test covers Positive Findings✓ Complete & coherent removal: Status: READY TO FIX → APPROVED (after applying the three should-fix items above) |
Rewrites stripDevflowTeammateMode to be async (fs/promises) and delegate parse/strip logic to the existing pure stripDevflowTeammateModeFromJson. Write errors now propagate so a failed migration stays unapplied and retries on next init (avoids PF-004). Removes the synchronous readFileSync/writeFileSync imports and the swallowed write-error catch. The per-project migration's pooled() concurrency now provides real parallelism instead of blocking the event loop. Both call sites in migrations.ts updated to await the now-async helper. Tests updated to await all stripDevflowTeammateMode calls; write-error propagation test added using a read-only file. Co-Authored-By: Claude <noreply@anthropic.com>
…ervation Remove PENDING_README_REMOVAL and PENDING_DOC_REMOVAL exclusion sets from skill-references.test.ts — the agent-teams doc cleanup landed in commit 378d0a2, so these guards were masking the canonical-name stale-doc checks (PF-009 failure mode) permanently. Add in-process teammateMode preservation assertion to the per-project teammate-mode migration test, matching the existing tmux test style. Co-Authored-By: Claude <noreply@anthropic.com>
The LEGACY_COMMAND_NAMES loop only removes the 3 known legacy names (review, specify, specify-teams) plus their -teams variants, but misses the 8 workflow-variant files produced by the Agent Teams refactor (code-review-teams.md, implement-teams.md, plan-teams.md, etc.). On partial installs (devflow init --plugin=X) the full-install dir wipe does not run, so those 8 dead commands survive pointing at the removed agent-teams skill (PF-009). Add an unconditional readdir sweep that removes every *-teams.md file from the commands/devflow dir regardless of install type. No *-teams.md command is ever legitimately installed anymore so the blanket sweep is safe. Co-Authored-By: Claude <noreply@anthropic.com>
Matches flags.ts (value: '1'); clarifies the exact env-var assignment.
Blocking: JSON-null input causes uncaught TypeErrorFile: IssueThe The ImpactThis uncaught error propagates out of the migration, marking it as failed. Since the migration runner never marks it applied on failure, it retries on every Other JSON primitives ( Suggested FixAdd a guard before the property access to handle non-object results: export function stripDevflowTeammateModeFromJson(settingsJson: string): string {
let parsed: unknown;
try {
parsed = JSON.parse(settingsJson);
} catch {
return settingsJson; // Malformed JSON — leave untouched
}
// Tolerant: only object roots can carry the key; primitives/null/arrays are no-ops.
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
return settingsJson;
}
const settings = parsed as Record<string, unknown>;
if (settings['teammateMode'] !== 'auto') return settingsJson;
delete settings['teammateMode'];
return JSON.stringify(settings, null, 2) + '\n';
}Add a regression test for the Claude Code |
Should-Fix: Stale "team" prose in devflow-debug READMEFile: IssueThis PR edited the debug README (removed Prerequisites, rewrote the marketplace description) but three references to the now-removed Agent Teams machinery remain in unchanged lines:
This is the PF-009 straggler pattern: a removal pass that fixes source and primary docs misses narrative prose in README sections. Suggested Fix
Claude Code |
Should-Fix: Write-error test fragile under root (chmod no-op)File: IssueThe write-error-propagation test uses This is the highest-value PF-004 regression guard in this PR (a swallowed write error reintroduces the "falsely applied migration" pitfall), so a guard that flips behavior under root is fragile exactly where it matters most. Suggested FixUse a uid-independent failure method. Minimal variant: make the parent a directory (which rejects writes as EISDIR even by root): it('propagates write errors (avoids PF-004)', async () => {
// Make the file a directory so writeFile rejects (EISDIR) even as root.
const dirAsFile = path.join(tmpDir, 'settings-dir.json');
await fs.mkdir(dirAsFile);
// ...point the cleanup at dirAsFile, or inject a writer stub that rejects.
// EISDIR is uid-independent.
});Or, cleanest: dependency-inject the Claude Code |
Should-Fix: Redundant
|
Pre-existing: [Unreleased] CHANGELOG references removed Teams variantsFile: IssueThe
However, the same [Unreleased] section's Note: Historical CHANGELOG entries under shipped releases (e.g., Suggested Fix (Report Only)Drop the "plus their Teams variants and" clause so line 21 reads:
Claude Code |
Summary: Inline Comments Created (Cycle 2)Blocking & Should-Fix Issues Reported5 inline comments created, 0 skipped (no pre-existing comments at these locations):
Lower-Confidence Suggestions (Summary Comment)Architecture (65%): A cross-reference comment in Overall VerdictClean ~4,100-line removal with one real blocking bug (the JSON-null TypeError). 7 of 10 reviewers APPROVED; 2 CHANGES_REQUESTED both stem from finding #1. The blocking issue is well-scoped (a guard clause + regression test). Other findings are maintainability/documentation polishes (not blocking merge, but recommended before release ships). Claude Code Review Agent |
…l root
JSON.parse("null") returns null (not thrown), escaping the catch block.
The subsequent `settings['teammateMode']` evaluation then threw TypeError on
null — uncaught by either try/catch — causing the migration runner to record
a failure and retry on every devflow init (avoids PF-004).
Fix: narrow parsed value to a non-null plain object before key access;
null/arrays/primitives are tolerated as no-ops consistent with the
malformed-JSON branch. Also rewords the docstring "in-place" to "from a
freshly parsed copy" for accuracy.
Test hardening: replace uid-dependent chmod(0o444) write-failure test with a
vi.mock on fs/promises that wraps writeFile as vi.fn, allowing
mockRejectedValueOnce to simulate EACCES deterministically even as root.
Add regression test asserting 'null', '[]', and '42' inputs return unchanged
and do not throw (covers the exact null-root bug path).
Co-Authored-By: Claude <noreply@anthropic.com>
…engthen migration test - init.ts: remove the -teams.md entry from LEGACY_COMMAND_NAMES suffix array; the blanket readdir sweep (avoids PF-009) is already the single owner of those files - flags.ts: add a one-line cross-reference next to the agent-teams FLAG_REGISTRY entry pointing readers at teammate-mode-cleanup.ts for the legacy teammateMode key cleanup (applies ADR-001) - migrations.test.ts: replace tautological Array.isArray assertions in the purge-devflow-teammate-mode-v1 test with .toEqual([]) to match the style used by the global migration test Co-Authored-By: Claude <noreply@anthropic.com>
…changelog README — reword "Team Spawning"→"Investigation Spawning", "Adversarial Debate / agents challenge each other"→orchestrator-mediated "Adversarial Evaluation", and fix the Related Plugins lines that described removed team-based variants. CHANGELOG — drop the "their Teams variants and" clause from the [Unreleased] knowledge-index entry. Avoids PF-009. Co-Authored-By: Claude <noreply@anthropic.com>
Summary
agent-teamsskill, all eight*-teams.mdcommand variants (implement, plan, debug, explore, code-review, resolve, research, release), and the entireteamsEnabled/teams:manifest field /applyTeamsConfig/stripTeamsConfigpipeline from the CLIid: agent-teams,defaultEnabled: false) — users opt in withdevflow flags --enable agent-teamsrather thandevflow init --teamsstripDevflowTeammateModecleanup helper (src/cli/utils/teammate-mode-cleanup.ts) and two migrations (purge-devflow-teammate-mode-global-v1,purge-devflow-teammate-mode-v1) to clean up the Devflow-writtenteammateMode:"auto"key from existing settings filesChanges
Deleted:
shared/skills/agent-teams/(SKILL.md + 3 reference files)*-teams.mdcommand variants across 8 pluginsapplyTeamsConfig/stripTeamsConfigfrompost-install.tsteamsEnabledfromFileCopyOptions(installer),--teams/--no-teamsfrominit.ts,teams:fromManifestDataAdded:
src/cli/utils/teammate-mode-cleanup.ts— sync + async teammate mode cleanup helpersagent-teamsFLAG_REGISTRY entry inflags.tstargetingCLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMSteammateMode:"auto"cleanup (global + per-project)tests/teammate-mode-cleanup.test.ts, migration tests, flag testsUpdated:
plugin.jsonmanifests — removedagent-teamsfromskillsarraysmarketplace.json— removedagent-teamskeyword fromdevflow-debugentryapplyTeamsConfig/stripTeamsConfig/teamsEnabled/teams-variant test cases; updated thresholds and exclusion sets for removed skillReviewer Focus Areas
src/cli/utils/teammate-mode-cleanup.ts— the sync/async helpers only removeteammateModewhen value is exactly"auto"(Devflow-written); user values like"tmux"or"in-process"are preservedsrc/cli/utils/migrations.ts— per ADR-001 exception: minimum migration only (onlyteammateMode:"auto"cleanup; env var and manifest field self-heal via flag machinery)tests/skill-references.test.ts— the canonical-name stale-doc guards run unguarded foragent-teams(the temporaryPENDING_README_REMOVAL/PENDING_DOC_REMOVALexclusion sets were removed post-review, since the doc cleanup landed in this branch)src/cli/commands/init.ts— theLEGACY_COMMAND_NAMESloop still cleans up thereview/specifylegacy commands; a blanket*-teams.mdsweep was added post-review so the 8 orphaned workflow variants are removed on partial reinstalls too (not only full installs)Post-Review Fixes
Follow-up commits after code review (full suite green — 1541 pass):
asyncand delegates to the purestripDevflowTeammateModeFromJson.*-teams.mdcommands on any install type — partial reinstalls (devflow init --plugin=X) no longer retain the 8 dead workflow*-teams.mdcommands (PF-009).PENDING_*test guards; addedin-processvalue-preservation coverage.=1value for theagent-teamsenv var.Docs: All Agent Teams documentation was removed in this branch (commit
378d0a2) —CLAUDE.md,docs/, the affected pluginREADME.mdfiles, andCHANGELOG.mdare updated here, not deferred to a separate PR.