Skip to content

feat: multi-backend agent launcher with Copilot CLI and Claude CLI support (#3) (#3)#40

Merged
jafreck merged 7 commits intomainfrom
cadre/issue-3
Feb 23, 2026
Merged

feat: multi-backend agent launcher with Copilot CLI and Claude CLI support (#3) (#3)#40
jafreck merged 7 commits intomainfrom
cadre/issue-3

Conversation

@jafreck
Copy link
Copy Markdown
Owner

@jafreck jafreck commented Feb 23, 2026

Summary

This PR introduces a pluggable AgentBackend abstraction that replaces the hardcoded Copilot CLI spawn logic in AgentLauncher. It adds native support for the Anthropic Claude CLI as a first-class agent runner alongside the existing GitHub Copilot CLI, configured via a new agent section in cadre.config.json. Full backward compatibility is maintained — existing configs with only a copilot key continue to work unchanged.

Closes #3

Changes

  • src/agents/backend.ts (new): Defines the AgentBackend interface and provides concrete CopilotBackend and ClaudeBackend implementations. Shared helpers (buildEnv, parseTokenUsage, writeAgentLog) are extracted into module-level functions used by both backends. ClaudeBackend parses Claude's JSON output format for token usage in addition to the text-pattern fallback.
  • src/agents/backend-factory.ts (new): createAgentBackend(config, logger) factory that reads config.agent?.backend and returns the appropriate backend instance; throws a descriptive error for unknown values.
  • src/config/schema.ts: Adds AgentConfigSchema (exported) with backend, model, timeout, copilot, and claude sub-objects. The existing copilot top-level section is kept; the new agent field is optional for full backward compatibility.
  • src/config/loader.ts: After Zod validation, if agent is absent, synthesizes it from config.copilot so downstream code can always read config.agent without null-checks.
  • src/core/agent-launcher.ts: Refactored to delegate all spawn logic to the backend. init() calls backend.init(), launchAgent() calls backend.invoke(). Direct config.copilot access for spawn settings removed.
  • src/validation/agent-backend-validator.ts: Updated to select the CLI command to validate based on the active backend (copilot or claude); falls back to config.copilot.cliCommand when config.agent is absent.
  • README.md: Added "Claude CLI Setup" section with install/auth instructions and a complete cadre.config.json example.

Implementation Details

The backend abstraction uses a simple interface + factory pattern. Both backends share the same environment-building logic (buildEnv) and log-writing logic (writeAgentLog). Token-usage parsing is shared but ClaudeBackend adds a JSON parse pass first (Claude CLI emits --output-format json responses), falling through to text-pattern matching on failure.

Backward compatibility is handled in two layers: the Zod schema marks agent as .optional(), and the config loader synthesizes a normalized agent object from the legacy copilot config so all downstream consumers always see config.agent defined.

Testing

  • tests/agent-backend.test.ts / tests/agent-backends.test.ts (53 tests): CopilotBackend and ClaudeBackend are tested end-to-end with mocked spawnProcess, covering CLI args, env vars, token parsing, log writing, success/failure/timeout paths, and legacy-config fallbacks.
  • tests/agent-backend-factory.test.ts (8 tests): Factory returns correct backend type and name for each backend value; throws on unknown values.
  • tests/backend-factory.test.ts (3 tests): Additional factory coverage including instanceof checks.
  • tests/config-loader-agent.test.ts (12 tests): Backward-compat normalization — synthesized agent from copilot config, preservation of explicit agent config, frozen output.
  • tests/config-schema.test.ts (10 new tests): AgentConfigSchema defaults, all accepted/rejected value combinations in CadreConfigSchema.
  • tests/agent-launcher.test.ts (8 new tests): AgentLauncher delegates init() and launchAgent() to the mocked backend; propagates results and errors correctly.
  • tests/agent-backend-validator.test.ts (8 new tests): Validator uses correct CLI key for copilot and claude backends; always checks agentDir.
  • All existing tests continue to pass — npx vitest run produces 969 tests, 0 failures.

Integration Verification

  • Build: pass (npm run build, exit 0)
  • Tests: pass (npx vitest run, exit 0, 969 tests)
  • Lint: pass (TypeScript zero errors)

Notes

  • The APIBackend (direct Anthropic/OpenAI REST API) described in the issue as a stretch goal is not included in this PR. It can be added as a follow-up by implementing AgentBackend and registering it in the factory.
  • Agent markdown files (agentDir) are still required for all backends — Claude CLI agents are driven by the same context-file approach as Copilot CLI agents.
  • The claude CLI flag --allowedTools accepts a comma-separated list; the current implementation hardcodes Bash,Read,Write,Edit,MultiEdit,Glob,Grep,TodoRead,TodoWrite,mcp__*. This list may need adjustment as Claude CLI evolves.

Cadre Process Challenges

This section is required for all CADRE-generated PRs (dogfooding data).
Document honestly what was difficult, confusing, or error-prone when CADRE processed this issue.

  • Issue clarity: The issue stated that AgentLauncher is "hardcoded" to spawn via Copilot CLI, but no AgentLauncher file existed in the described location at analysis time. The analysis correctly flagged this ambiguity (the feature was building new functionality, not purely extracting existing logic). A brief note in the issue pointing to the actual source file would have eliminated this uncertainty.
  • Agent contracts: The code-writer agent relied on knowing which files to create and the exact exports expected by downstream consumers. Because the AgentBackend interface, CopilotBackend, ClaudeBackend, and factory were all new, the task decomposition worked well — each task had clear acceptance criteria — but the ordering of tasks (schema → loader → backend → factory → refactor) had to be strictly respected to avoid type errors during intermediate states.
  • Context limitations: The ClaudeBackend implementation required knowing the exact CLI flags for the claude CLI (--allowedTools, --output-format). These were not documented in the issue and had to be inferred from public Claude CLI documentation. A link to the relevant CLI reference in the issue would have helped.
  • Git/worktree: No git or worktree problems were encountered during this run. The worktree isolation worked cleanly.
  • Parsing/output: Task result files were written and consumed correctly. No schema mismatches were observed between agent outputs and the orchestrator's expectations.
  • Retry behavior: No retries were needed. All tasks completed on first attempt.
  • Overall: The biggest friction point was the gap between the issue's description of "extracting existing spawn logic" and the reality that most of the spawn infrastructure was being built from scratch. Better issue scoping (distinguishing "extract and refactor" from "implement new") would have accelerated analysis and planning.

Closes #3

@jafreck jafreck marked this pull request as ready for review February 23, 2026 01:03
@jafreck jafreck merged commit 2b3f85b into main Feb 23, 2026
2 checks passed
@jafreck jafreck deleted the cadre/issue-3 branch February 23, 2026 01:03
@jafreck jafreck added the cadre-generated Pull request automatically generated by cadre label Feb 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cadre-generated Pull request automatically generated by cadre

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi-backend agent launcher: native support for Copilot CLI, Claude CLI, and direct API

1 participant