feat: add CodeBuddy agent support#1007
Conversation
Add full CodeBuddy integration mirroring Claude Code support. CodeBuddy uses CODEBUDDY_BASE_URL env var and ~/.codebuddy/ config dir. New files: - headroom/providers/codebuddy/ (runtime, install) - headroom/mcp_registry/codebuddy.py (MCP registrar) - headroom/learn/plugins/codebuddy.py (session log scanner) - headroom/memory/sync_adapters/codebuddy_code.py (memory adapter) - headroom/memory/writers/codebuddy_writer.py (MEMORY.md writer) Modified: - CLI: wrap/unwrap codebuddy, init codebuddy subcommands - Auth mode: codebuddy/ UA prefix and client classification - Install registry: codebuddy env builder and provider scope handler - ToolTarget enum, paths, telemetry updated - Docs: README, wiki, llms.txt, docs/ updated with CodeBuddy
CodeBuddy uses /v2/chat/completions (not /v1) and connects to tencent.sso.copilot.tencent.com as its upstream API gateway. Changes: - runtime.py: proxy_base_url adds /v2 prefix, DEFAULT_API_URL points to tencent.sso.copilot.tencent.com - proxy_routes.py: register /v2/chat/completions route with upstream path override via request.state - openai.py: handler reads upstream_path from request.state instead of hardcoding /v1/chat/completions - wrap.py: auto-configure openai_api_url for CodeBuddy to use tencent.sso.copilot.tencent.com (overridable via OPENAI_TARGET_API_URL)
- proxy.mdx: add CodeBuddy wrap example - integration-guide: list CodeBuddy in proxy table and description - mcp.md: add CodeBuddy to MCP host compatibility table - docker-install, persistent-installs: mention CodeBuddy - specs (ADRs, domain model, capabilities, diagrams): reflect CodeBuddy support
- init.py: fix I001 import ordering (ruff auto-fix) - wrap.py: move DEFAULT_CODEBUDDY_API_URL constant after all imports to fix 24x E402 errors
- wrap.py, codebuddy.py, context.py, test_init_cli.py
PR governanceThis PR follows the template and is marked ready for human review. |
Add codebuddy as a valid --backend option that normalises to anthropic with the default openai_api_url set to tencent.sso.copilot.tencent.com. Changes: - proxy.py: handle --backend codebuddy by normalising to anthropic and setting openai_api_url internally, so the command line stays clean - wrap.py: pass backend=codebuddy instead of openai_api_url; add backend/openai_api_url mismatch detection in _ensure_proxy for both persistent and non-persistent proxy paths; propagate HEADROOM_BACKEND env var to subprocess; skip --openai-api-url on command line when backend is codebuddy (proxy.py handles it) - runtime.py: allow HEADROOM_BACKEND env var to override manifest's --backend value via _override_backend helper
There was a problem hiding this comment.
Pull request overview
Adds CodeBuddy as a first-class wrapped/init-able agent in Headroom (proxy routing, MCP registration, learning + memory interoperability), alongside the existing Claude/Codex integrations.
Changes:
- Introduces a CodeBuddy provider slice (runtime URL, install-time env wiring) and a new
/v2/chat/completionsproxy route. - Adds CLI workflows:
headroom wrap codebuddy,headroom unwrap codebuddy, andheadroom init codebuddy. - Adds CodeBuddy MCP registrar + memory sync adapter/writer + learn plugin, and updates docs/tests to reference CodeBuddy.
Reviewed changes
Copilot reviewed 40 out of 40 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| wiki/quickstart.md | Adds CodeBuddy proxy env example. |
| wiki/persistent-installs.md | Documents provider-scope settings path + adds codebuddy target. |
| wiki/mcp.md | Lists CodeBuddy as MCP-native and updates diagrams/examples. |
| wiki/integration-guide.md | Adds CodeBuddy to proxy usage guidance + env example. |
| wiki/index.md | Adds headroom wrap codebuddy to quick command list. |
| wiki/getting-started.md | Adds CodeBuddy proxy env example. |
| wiki/docker-install.md | Mentions CodeBuddy state dir + wrap support in Docker-native docs. |
| wiki/cli.md | Adds wrap codebuddy to CLI reference and related tables. |
| tests/test_install/test_paths.py | Tests new codebuddy_settings_path() helper. |
| tests/test_cli/test_init_cli.py | Expands init CLI detection/dispatch tests to include CodeBuddy. |
| README.md | Adds CodeBuddy to wrap list and compatibility matrix. |
| llms.txt | Adds CodeBuddy to “wrap an agent” list. |
| headroom/telemetry/context.py | Adds codebuddy to known wrap agent slugs. |
| headroom/proxy/handlers/openai.py | Allows OpenAI handler to use a per-request upstream path (for /v2). |
| headroom/proxy/auth_mode.py | Adds CodeBuddy user-agent classification/prefix. |
| headroom/providers/proxy_routes.py | Adds /v2/chat/completions route delegating to OpenAI chat handler. |
| headroom/providers/install_registry.py | Registers CodeBuddy env builder + provider-scope applier/reverter. |
| headroom/providers/codebuddy/runtime.py | Defines CodeBuddy default upstream + proxy base URL helper. |
| headroom/providers/codebuddy/install.py | Adds provider-scope settings.json env mutation for CodeBuddy. |
| headroom/providers/codebuddy/init.py | Exposes CodeBuddy runtime helpers. |
| headroom/memory/writers/codebuddy_writer.py | Exports Headroom memories in CodeBuddy MEMORY.md/topic-file format. |
| headroom/memory/sync_adapters/codebuddy_code.py | Adds CodeBuddy memory sync adapter and project path encoding. |
| headroom/mcp_registry/install.py | Adds CodeBuddy registrar to the default registrar list. |
| headroom/mcp_registry/codebuddy.py | Implements CodeBuddy MCP registration via CLI or file fallback. |
| headroom/mcp_registry/init.py | Re-exports CodeBuddyRegistrar. |
| headroom/learn/plugins/codebuddy.py | Adds CodeBuddy conversation log scanner plugin for headroom learn. |
| headroom/install/runtime.py | Allows env override of persistent manifest backend for runtime command building. |
| headroom/install/paths.py | Adds codebuddy_settings_path(). |
| headroom/install/models.py | Adds ToolTarget.CODEBUDDY. |
| headroom/cli/wrap.py | Implements wrap/unwrap codebuddy, plus backend propagation for persistent proxy restarts. |
| headroom/cli/proxy.py | Adds codebuddy backend normalization (anthropic + default OpenAI upstream URL). |
| headroom/cli/init.py | Adds init codebuddy and CodeBuddy hook/env wiring support. |
| docs/spec/012-diagrams.md | Updates diagram to include CodeBuddy plugin. |
| docs/spec/008-capabilities.md | Adds CodeBuddy capability bullets. |
| docs/spec/004-domain-model.md | Adds codebuddy to agent_type examples. |
| docs/spec/003-adrs.md | Mentions CodeBuddy in ADR context list. |
| docs/content/docs/proxy.mdx | Adds headroom wrap codebuddy example. |
| docs/content/docs/persistent-installs.mdx | Documents CodeBuddy provider-scope adapter path. |
| docs/content/docs/docker-install.mdx | Adds headroom wrap codebuddy to supported host flows. |
| .codegraph/.gitignore | Ignores local CodeGraph artifacts. |
| [ | ||
| sys.executable, | ||
| "-m", | ||
| "headroom.memory.sync", | ||
| "--db", | ||
| _sync_db, | ||
| "--user", | ||
| _sync_user, | ||
| "--agent", | ||
| "codebuddy", | ||
| "--force", | ||
| ], |
| if path.exists(): | ||
| payload = json.loads(path.read_text()) | ||
| env = payload.get("env") | ||
| env_map = dict(env) if isinstance(env, dict) else {} |
| class CodeBuddyRegistrar(MCPRegistrar): | ||
| """Register MCP servers with CodeBuddy.""" | ||
|
|
||
| name = "codebuddy" | ||
| display_name = "CodeBuddy" | ||
|
|
| class CodeBuddyAdapter(AgentMemoryAdapter): | ||
| """Sync adapter for CodeBuddy's native memory files.""" | ||
|
|
||
| agent_name = "codebuddy" | ||
|
|
||
| def __init__(self, memory_dir: Path | str) -> None: | ||
| self._memory_dir = Path(memory_dir) | ||
|
|
||
| async def read_memories(self) -> list[AgentMemory]: |
| @unwrap.command("codebuddy") | ||
| @click.option("--port", "-p", default=8787, type=int, help="Proxy port (default: 8787)") | ||
| @click.option("--no-stop-proxy", is_flag=True, help="Do not stop the local Headroom proxy") | ||
| @click.option("--keep-mcp", is_flag=True, help="Keep Headroom MCP registrations") | ||
| @click.option("--keep-rtk", is_flag=True, help="Keep rtk CodeBuddy hooks") | ||
| def unwrap_codebuddy( | ||
| port: int, | ||
| no_stop_proxy: bool, | ||
| keep_mcp: bool, | ||
| keep_rtk: bool, | ||
| ) -> None: | ||
| """Undo durable setup from ``headroom wrap codebuddy``.""" |
| path = Path(mutation.path) | ||
| if not path.exists(): | ||
| return | ||
| payload = json.loads(path.read_text()) | ||
| env = payload.get("env") |
JerrettDavis
left a comment
There was a problem hiding this comment.
Found a blocking issue in the advertised CodeBuddy memory path. headroom wrap codebuddy --memory runs python -m headroom.memory.sync --agent codebuddy, but headroom.memory.sync still declares --agent choices as only claude,codex and has no CodeBuddy branch in main(). Repro on this branch: python -m headroom.memory.sync --db .tmp-codebuddy-memory.db --user review --agent codebuddy --force exits with invalid choice: 'codebuddy'. Please wire CodeBuddyAdapter(get_codebuddy_memory_dir()) into the sync CLI and add focused coverage for the CodeBuddy sync path before this is ready.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
…ation - Wire CodeBuddyAdapter into sync CLI (--agent codebuddy) - Add CodeBuddy memory sync tests (read/write/cross-agent interop) - Fix CODEBUDDY_BASE_URL /v2 path in init hooks and wiki docs - Fix wrap codebuddy docstring (ANTHROPIC_BASE_URL -> CODEBUDDY_BASE_URL) - Add CodeBuddy rtk support: try 'rtk init --agent codebuddy', fallback to manual settings.json hook with 'rtk hook codebuddy' - Add encoding='utf-8' to install.py settings reads/writes - Restore ✅ symbols in README agent compatibility table - Add CodeBuddy MCP registrar tests - Add CodeBuddy unwrap CLI tests - Support both 'rtk hook codebuddy' and 'rtk hook claude' in rtk removal/detection
|
Thanks for the thorough review @JerrettDavis and @copilot! All issues have been addressed: Blocking fixes:
Path /v2 consistency:
RTK support:
Other fixes:
All tests pass: 138 new/modified tests across 4 test files, no regressions. Ready for re-review. |
… wrap CLI - test_codebuddy_plugin.py: 28 tests (decode, display, detect, discover, scan) - test_codebuddy_writer.py: 8 tests (format, default_path, export_topics) - test_provider_codebuddy_install.py: 7 tests (apply/revert provider scope) - test_wrap_codebuddy.py: 5 tests (prepare-only, no-rtk, with-rtk, no-mcp, no-serena) All 196 tests pass across 8 test files.
- Add 'codebuddy' to click.Choice for --target option - Add ToolTarget.CODEBUDDY to SUPPORTED_TARGETS so resolve_targets no longer filters it out in manual mode - Auto-switch to --providers manual when --target is specified, preventing auto-detection from routing to wrong targets - Auto-set --backend to match the target name when the sole target doubles as a backend (e.g. --target codebuddy sets --backend codebuddy)
- Fix ruff lint errors: unused imports (F401), unused variables (F841), trailing whitespace (W293), import sorting (I001) - Add shutil.which mock for codebuddy wrap tests (PATH not found in CI) - Add _port_bind_error mock for persistent proxy tests - Update test assertions to match current _ensure_proxy behavior
JerrettDavis
left a comment
There was a problem hiding this comment.
LGTM! Thank you for the massive contribution!
Tagging @chopratejas for a second set of eyes.
Description
Adds full CodeBuddy agent support to headroom, mirroring the existing Claude Code integration. CodeBuddy is a Tencent-hosted CLI AI coding agent that uses a
/v2API path and connects to the Tencent SSO Copilot gateway. This PR enablesheadroom wrap codebuddyandheadroom init codebuddyworkflows, including proxy routing, MCP registration, memory sync, and session learning.Closes #
Type of Change
Changes Made
headroom/providers/codebuddy/runtime.py— CodeBuddy runtime config:/v2API prefix, Tencent SSO Copilot upstreamheadroom/providers/codebuddy/install.py— WritesCODEBUDDY_BASE_URLto~/.codebuddy/settings.jsonheadroom/cli/wrap.py—headroom wrap codebuddy: start proxy, register MCP, launch agent with local proxy URLheadroom/cli/init.py—headroom init codebuddy: persistent/detached setupheadroom/providers/proxy_routes.py—/v2/chat/completionsroute, rewrites path to standard OpenAI handlerheadroom/mcp_registry/codebuddy.py—CodeBuddyRegistrarwritesheadroom+serenaconfigs to~/.codebuddy/mcp.jsonheadroom/memory/sync_adapters/codebuddy_code.py— Sync CodeBuddy session memories → Headroom SQLite DBheadroom/memory/writers/codebuddy_writer.py— WriteMEMORY.mdin CodeBuddy formatheadroom/learn/plugins/codebuddy.py— Scan CodeBuddy session logs for learningTesting
pytest)ruff check .)mypy headroom)Test Output
Real Behavior Proof
headroom wrap codebuddy— proxy started,CODEBUDDY_BASE_URLinjected, CodeBuddy launched; (2)headroom init codebuddy— wroteCODEBUDDY_BASE_URLto~/.codebuddy/settings.json; (3) sent chat request → proxy received/v2/chat/completions, forwarded to upstreamReview Readiness
Checklist
Screenshots (if applicable)
N/A — CLI-only feature, no UI changes.
Additional Notes
test_fetch_extract_zip) is a pre-existing tempfile issue on macOS, not introduced by this PR.mypyhas pre-existing errors in the codebase; no new type errors introduced by these changes./v2(not/v1) for its API path; proxy routes handle this transparently without breaking existing Claude Code routes.