Skip to content

feat(agents): add VS Code Copilot SDD multi-mode support (backend)#505

Closed
Snakeblack wants to merge 5 commits into
Gentleman-Programming:mainfrom
Snakeblack:feat/vscode-copilot-sdd-multimode
Closed

feat(agents): add VS Code Copilot SDD multi-mode support (backend)#505
Snakeblack wants to merge 5 commits into
Gentleman-Programming:mainfrom
Snakeblack:feat/vscode-copilot-sdd-multimode

Conversation

@Snakeblack

Copy link
Copy Markdown

🔗 Linked Issue

Closes #504


🏷️ PR Type

  • type:feature — New feature (non-breaking change that adds functionality)

📝 Summary

  • Activates sub-agent support in the VS Code Copilot adapter and ships 10 embedded .agent.md templates so SDD multi-mode now works on VS Code Copilot out of the box (10 default agents written to ~/.copilot/agents/).
  • Adds GenerateVSCodeProfileFiles / RemoveVSCodeProfileAgents plus a provider/model → "Display Name (copilot)" mapping table (vscModelEntries) so named profiles can land per-phase models in Copilot's frontmatter.
  • Wires the injection pipeline (inject.go step 2c) and post-injection verification to recognize the .agent.md extension, without touching OpenCode/Cursor/Kiro paths.

Context for prioritization (from the linked issue): GitHub Copilot's billing shifts to AI Credits (usage-based) in June — that change makes per-phase model assignment a real cost lever for the enterprise cohort that's already standardized on Copilot + VS Code. This PR is the backend foundation; TUI integration follows in a separate PR.


📂 Changes

File / Area What Changed
internal/agents/vscode/adapter.go SupportsSubAgents() = true, new SubAgentsDir, EmbeddedSubAgentsDir, VSCModelID delegate
internal/agents/vscode/adapter_test.go Cross-platform tests for SubAgentsDir (macOS/Linux/Windows)
internal/agents/vscode/vscode_profiles.go New — vscModelEntries table, VSCodeModelID, GenerateAgentFile, GenerateVSCodeProfileFiles, RemoveVSCodeProfileAgents, SDDPhases
internal/agents/vscode/vscode_profiles_test.go New — 9 model mappings + fallbacks + generator + cleanup tests
internal/assets/vscode/agents/*.agent.md New — 10 embedded templates (sdd-init through sdd-onboard) with {{VSC_MODEL}} sentinel
internal/assets/assets.go Embed vscode/ directory tree
internal/assets/assets_test.go Coverage for the 10 new embedded assets
internal/components/sdd/inject.go New step 2c (VS Code named profiles), .agent.md extension support, post-check extended to sdd-apply.agent.md + sdd-verify.agent.md
internal/components/sdd/vscode_inject_test.go New — integration tests for default + named profile flows
docs/vscode-sdd-profiles-research.md Research doc with VS Code Copilot multi-agent documentation findings (May 2026)

🧪 Test Plan

Unit Tests

go test ./...

Manual E2E (verified locally)

  1. go install ./cmd/gentle-ai
  2. Run gentle-ai → Start installation → select VS Code Copilot → choose SDD multi-mode → finish
  3. Verify ~/.copilot/agents/ contains the 10 sdd-*.agent.md files
  4. Open VS Code and confirm Copilot recognizes the agents
  • Unit tests pass (go test ./...) — 0 failures, go vet clean
  • E2E tests pass (cd e2e && ./docker-test.sh) — not run locally (Docker on Windows); CI will validate
  • Manually tested locally: VS Code Copilot picks up the 10 default agents end-to-end

🤖 Automated Checks

Check Expected Note
Check PR Cognitive Load ⚠️ likely fail Diff is ~1500 LOC because of 10 embedded .agent.md templates (markdown content, not logic) + research doc. Requesting size:exception — the Go production+test code alone is ~400 LOC and well within the spirit of the budget. Splitting templates into a separate PR would only churn assets and delay the unified review.
Check Issue Reference Closes #504
Check Issue Has status:approved ⏳ blocked on maintainer Issue #504 is status:needs-review — submitter has no maintainer permissions on the upstream repo
Check PR Has type:* Label ⏳ blocked on maintainer Need type:feature applied by a maintainer
Unit Tests ✅ expected All local tests pass
E2E Tests Docker-based; will run in CI

✅ Contributor Checklist

  • PR is linked to an issue (feat(agents): add VS Code Copilot SDD multi-mode support (backend) #504 — pending maintainer approval label)
  • PR stays within 400 changed lines — requesting size:exception; rationale in the table above
  • type:feature label — needs maintainer to apply (no permissions from submitter)
  • Unit tests pass (go test ./...)
  • E2E tests pass (run in CI)
  • Documentation updated where relevant (docs/vscode-sdd-profiles-research.md)
  • My commits follow Conventional Commits format
  • My commits do not include Co-Authored-By trailers

💬 Notes for Reviewers

  • Architecture: the new VS Code path mirrors the existing Kiro and Claude patterns (kiroModelResolver / claudeModelResolver) — vscModelResolver is the third instance of the same shape. Step 2c is cleanly isolated behind adapter.Agent() == model.AgentVSCodeCopilot; OpenCode / Cursor / Kiro code paths are untouched.
  • Ordering of vscModelEntries is significant: gpt-4o-mini must precede gpt-4o and gpt-4.1-mini must precede gpt-4.1 (substring matching). Comment in vscode_profiles.go documents this plus the latent risk for a future claude-sonnet-4-5.
  • Idempotency: re-running gentle-ai with no changes does not flip InjectionResult.Changed to true (recently fixed at inject.go:456).
  • Windows safety: tests use t.TempDir() for transient paths — no hardcoded /tmp.
  • What's deferred to PR Bug: Luego de instalar la TUI el texto en la terminal se desconfigura #2: TUI welcome menu entry for VS Code profiles, profile create/edit screens for VS Code, a VS Code-specific model picker (static vscModelEntries list, no OpenCode model cache). Named-profile generation is fully implemented in the backend and reachable via the Go API today — the TUI just doesn't expose it yet.

Enable per-phase sub-agents for VS Code Copilot via .agent.md files,
matching the multi-mode capability already shipped for OpenCode, Cursor
and Kiro.

- VS Code adapter now reports SupportsSubAgents() == true and exposes
  SubAgentsDir(homeDir) == ~/.copilot/agents/ plus EmbeddedSubAgentsDir()
  == "vscode/agents".
- 10 embedded .agent.md templates under internal/assets/vscode/agents/
  (one per SDD phase, sdd-init through sdd-onboard). Templates omit the
  model field on the default set so Copilot uses the user's default
  model.
- New profile generator GenerateVSCodeProfileFiles(profile, agentsDir)
  ([]string, error) reads templates, resolves {{VSC_MODEL}} via a
  provider/model → Copilot display name table (vscModelEntries) and
  writes suffixed files atomically.
- inject.go step 2c writes named-profile files for VS Code Copilot
  when SDD mode is multi and a non-default profile is configured;
  step-3c handles the default unsuffixed set unchanged.
- RemoveVSCodeProfileAgents(agentsDir, profileName) removes the 10
  suffixed phase files for a named profile; default profile rejected,
  non-gentle-ai files preserved.
- Post-injection verification extended to recognize the .agent.md
  extension and validate sdd-apply.agent.md plus sdd-verify.agent.md
  are non-empty.

TUI integration (welcome menu entry, profile create/edit screens, VS
Code-specific model picker) lands in a separate PR.
Add two regression tests that explicitly invoke Inject() twice with
identical inputs and assert:
  1. The second run reports InjectionResult.Changed = false.
  2. The file inventory in ~/.copilot/agents/ is unchanged (same set,
     same modification times) — proving filemerge.WriteFileAtomic's
     content-equality short-circuit holds across the full VS Code
     injection path.

Coverage:
  - Default profile path (step 3c only, 10 files).
  - Named profile path (step 2c writes 10 suffixed files on top of
    step 3c's 10 defaults — total 20 files).

These tests blind the recent fix at inject.go:456 (changed = changed
|| len(profileFiles) > 0) against future regressions where a
contributor might re-introduce the unconditional Changed=true that
broke the idempotency contract.
The vscode-sdd-profiles-research.md doc was a working/exploration
artifact useful during design but does not belong in the shipped
codebase. The architectural decisions it captured are reflected in
proposal/spec/design/tasks (kept in engram and locally in
openspec/changes/, which is gitignored).
Snakeblack added a commit to Snakeblack/gentle-ai that referenced this pull request May 11, 2026
…ates agents

VS Code Copilot scans both \`.agent.md\` (its native format) and Claude
\`.md\` agent files in parallel. When a user installs SDD multi-mode for
both VS Code Copilot and Claude Code through the gentle-ai wizard, the
8 sub-agent phases that both adapters ship (sdd-apply, sdd-archive,
sdd-design, sdd-explore, sdd-propose, sdd-spec, sdd-tasks, sdd-verify)
appear twice in the VS Code Agent customizations panel.

This is not a bug — each agent file is correct and functional in its
own host — but it looks broken to a user who sees \"sdd-verify\" listed
twice and assumes gentle-ai wrote duplicates. The case was traced down
in PR Gentleman-Programming#505 manual testing.

Changes:
  - New ScreenSDDDuplicateAgentsWarning with render function that lists
    exactly the 8 phases that duplicate (sdd-init and sdd-onboard are
    excluded because the Claude adapter does not ship them as
    sub-agents).
  - shouldWarnAboutDuplicateAgents() returns true when SDD is selected
    AND both AgentVSCodeCopilot and AgentClaudeCode are in the agent
    set. Extensible: add other Claude-format adapters to the check as
    they are introduced.
  - Wired into the ScreenSDDMode handler: when SDDModeMulti is chosen
    and the warning condition holds, the warning screen is shown before
    the normal post-SDDMode flow (ModelPicker / StrictTDD / etc.).
  - Extracted advanceFromSDDModeSelection() helper so both the SDDMode
    handler (when no warning is required) and the warning's \"Continue
    anyway\" path can share the same forward navigation logic.
  - Warning screen offers two options: \"Continue anyway\" resumes the
    normal flow; \"Back to adapter selection\" returns to ScreenSDDMode
    so the user can unselect one adapter.

Test coverage:
  - TestShouldWarnAboutDuplicateAgents (7 subtests) covers the
    detection helper across all relevant adapter combinations.
  - TestSDDMode_TriggersDuplicateAgentsWarning verifies that selecting
    multi-mode with the offending combination routes to the warning.
  - TestSDDMode_NoWarningWhenNotDuplicating verifies that a benign
    combination skips the warning.
  - TestSDDDuplicateAgentsWarning_ContinueAdvances and
    TestSDDDuplicateAgentsWarning_BackReturnsToSDDMode cover both
    branches of the warning handler.
  - TestRenderSDDDuplicateAgentsWarning_ListsExpectedPhases pins the
    rendered phase list to the contract so a future contributor cannot
    silently drop or add a phase.
Without an orchestrator template, SDD multi-mode on VS Code Copilot
relies on the default chat agent inferring the phase sequence from
sub-agent description fields alone. Weak Copilot models routinely
skip phases or reorder them, breaking the SDD contract.

This change adds an explicit orchestrator template that mirrors the
pattern OpenCode, Claude Code, and Kiro already use:

  - New internal/assets/vscode/agents/sdd-orchestrator.agent.md
    embedded template with tools: ['agent'], an agents: whitelist of
    the 10 phases, user-invocable: true, and a body that documents
    the strict explore → propose → spec → design → tasks → apply →
    verify → archive sequence plus the init / onboard utility flows.
  - {{VSC_PROFILE_SUFFIX}} placeholder so the same template serves
    both the default (unsuffixed) install and named profiles where
    every phase reference is suffixed with -{name}.
  - vscode.OrchestratorPhase constant + generateOrchestratorAgent()
    helper that renders the orchestrator inline for named profiles
    (separate from the embedded template path used by 3c).
  - GenerateVSCodeProfileFiles now writes 11 files per profile
    (orchestrator + 10 phases). RemoveVSCodeProfileAgents already
    matched the suffix pattern, so it cleans up the orchestrator
    automatically.
  - inject.go step 3c resolves {{VSC_PROFILE_SUFFIX}} to empty for
    the default set; post-check conditionally validates the
    orchestrator file only when the adapter ships one (VS Code does,
    Claude Code does not — Claude uses CLAUDE.md as the root
    orchestrator prompt instead of a separate agent file).

Tests:
  - TestGenerateAgentFile_Orchestrator_DefaultProfile_HasAllRequiredFields
    pins the YAML contract (tools, agents, user-invocable, etc.).
  - TestGenerateAgentFile_Orchestrator_NamedProfile_SuffixesAgentNames
    proves the agents: whitelist AND body references get suffixed in
    lockstep — without that, the orchestrator would dispatch to
    nonexistent agents.
  - TestGenerateAgentFile_Orchestrator_OrchestratorModelAssignment
    covers three model resolution paths (omit / known / fallback).
  - TestGenerateVSCodeProfileFiles_IncludesOrchestrator regression
    guard against the previous 10-file design.
  - TestRemoveVSCodeProfileAgents_AlsoRemovesOrchestrator regression
    guard against the orchestrator lingering after delete.
  - Existing idempotency tests updated for the new counts (11 default,
    22 with one named profile).

Docs:
  - docs/prd-vscode-profiles.md captures the full product spec in
    English, mirroring the format of docs/prd-opencode-profiles.md.
    Covers problem statement (June 2026 AI Credits transition +
    enterprise lock-in), vision, scope, detailed requirements,
    technical design, UX flows, edge cases, and open questions.
…templates

Embedded .agent.md templates may contain CRLF line endings on Windows.
The sentinel removal (e.g. model: {{VSC_MODEL}}\n → empty) only
matched LF, silently leaving raw {{VSC_MODEL}} in the deployed files.
VS Code Copilot's YAML parser then rejects the invalid model value.

Normalize \r\n → \n immediately after reading the embedded content,
before any sentinel replacement runs.
@Alan-TheGentleman

Copy link
Copy Markdown
Contributor

Heads-up: this PR is now showing a merge conflict against main. We shipped v1.31.0 (and a number of follow-up fixes) over the past two days — several files this PR touches were also modified upstream.

Could you rebase against current main and resolve the conflicts?

git fetch upstream main
git rebase upstream/main
# resolve any conflicts
git push --force-with-lease

Once it's green again I can review for merge. Sorry for the drift — it's the cost of the cleanup velocity. Thanks for sticking with it.

@Snakeblack

Copy link
Copy Markdown
Author

Closing this as superseded by the newer VS Code Copilot SDD subagents stack:

This older PR used the previous named-profile / {{VSC_MODEL}} direction and is now conflicting with main. The replacement chain keeps the work split into reviewable units and includes the latest validation.

@Snakeblack Snakeblack closed this Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(agents): add VS Code Copilot SDD multi-mode support (backend)

2 participants