From 68a4af4ac19a3f8305bcf6929b43ba6c06bddb9b Mon Sep 17 00:00:00 2001 From: Devin Date: Sun, 28 Jun 2026 19:00:41 +0800 Subject: [PATCH] Add CodeBuddy agent integration (#1581) --- docs/02-usage/030_clients.md | 92 ++++++++++++++++++- src/serena/config/client_setup.py | 27 +++++- src/serena/hooks.py | 5 +- .../resources/config/contexts/codebuddy.yml | 52 +++++++++++ 4 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 src/serena/resources/config/contexts/codebuddy.yml diff --git a/docs/02-usage/030_clients.md b/docs/02-usage/030_clients.md index 0a6e0af5..6241246e 100644 --- a/docs/02-usage/030_clients.md +++ b/docs/02-usage/030_clients.md @@ -525,6 +525,93 @@ You will have to prompt Antigravity's agent to "Activate the current project usi Unlike VSCode, Antigravity does not currently support including the working directory in the MCP configuration. Also, the current client will be shown as `none` in Serena's dashboard (Antigravity currently does not fully support the MCP specifications). This is not a problem, all tools will work as expected. +## CodeBuddy + +Serena provides native support for CodeBuddy, a CLI coding agent that shares a similar architecture with Claude Code. +To set up the Serena MCP server for CodeBuddy, simply run: + + serena setup codebuddy + +### Manual Setup + +**Global Configuration**. To add the Serena MCP server for all your projects, use the user-level configuration of CodeBuddy and the `--project-from-cwd` flag: + +```bash +codebuddy mcp add --scope user serena -- serena start-mcp-server --context codebuddy --project-from-cwd +``` + +**Project-Level Configuration**. To add the Serena MCP server for a single project only: + +```bash +codebuddy mcp add serena -- serena start-mcp-server --context codebuddy --project "$(pwd)" +``` + +Confirm that CodeBuddy is connected to Serena by running the `/mcp` command and reconnecting if necessary. + +### Hooks + +CodeBuddy supports the same hook system as Claude Code. To set up hooks, add the following to your CodeBuddy settings file (`.codebuddy/settings.json` in your project directory, or `~/.codebuddy/settings.json` globally): + +```json +{ + "hooks": { + "PostToolUse": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "serena-hooks remind --client=codebuddy" + } + ] + } + ], + "Notification": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "serena-hooks auto-approve --client=codebuddy" + } + ] + } + ], + "SessionStart": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "serena-hooks activate --client=codebuddy" + } + ] + } + ], + "Stop": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "serena-hooks cleanup --client=codebuddy" + } + ] + } + ] + } +} +``` + +### Hook Descriptions + +- **`remind`**: Remind the agent to use Serena's tools instead of built-in `grep` and `read` tools. +- **`activate`**: Prompt the agent to activate the project at session start and read Serena's instructions. +- **`cleanup`**: Clean up hook session data when the session ends. +- **`auto-approve`**: Auto-approve Serena tool calls whenever CodeBuddy is in a permissive + permission mode (`acceptEdits` or `auto`), so blanket approvals cover Serena's destructive + tools (e.g. `replace_symbol_body`, `rename_symbol`) instead of prompting on every call. + ## Other Clients For other clients, follow the [general instructions](#clients-general-instructions) above to set up Serena as an MCP server. @@ -536,8 +623,9 @@ There are many terminal-based coding assistants that support MCP servers, such a * [Gemini-CLI](https://github.com/google-gemini/gemini-cli), * [Qwen3-Coder](https://github.com/QwenLM/Qwen3-Coder), * [rovodev](https://community.atlassian.com/forums/Rovo-for-Software-Teams-Beta/Introducing-Rovo-Dev-CLI-AI-Powered-Development-in-your-terminal/ba-p/3043623), - * [OpenHands CLI](https://docs.all-hands.dev/usage/how-to/cli-mode) and - * [opencode](https://github.com/sst/opencode). + * [OpenHands CLI](https://docs.all-hands.dev/usage/how-to/cli-mode), + * [opencode](https://github.com/sst/opencode) and + * [CodeBuddy-Code](https://www.codebuddy.cn/cli/). They generally benefit from the symbolic tools provided by Serena. You might want to customize some aspects of Serena by writing your own context, modes or prompts to adjust it to the client's respective internal capabilities (and your general workflow). diff --git a/src/serena/config/client_setup.py b/src/serena/config/client_setup.py index 9116d01f..933ff4a3 100644 --- a/src/serena/config/client_setup.py +++ b/src/serena/config/client_setup.py @@ -53,7 +53,7 @@ class ClientSetupHandlerClaudeCode(ClientSetupHandler): super().__init__("claude-code") def is_applicable(self) -> bool: - result = execute_shell_command("claude --version") + result = execute_shell_command("claude --version", capture_stderr=True) return result.return_code == 0 and "Claude" in result.stdout def get_mcp_server_options(self) -> list[str]: @@ -78,7 +78,7 @@ class ClientSetupHandlerCodex(ClientSetupHandler): super().__init__("codex") def is_applicable(self) -> bool: - result = execute_shell_command("codex --version") + result = execute_shell_command("codex --version", capture_stderr=True) return result.return_code == 0 and "codex-cli" in result.stdout def get_mcp_server_options(self) -> list[str]: @@ -88,4 +88,25 @@ class ClientSetupHandlerCodex(ClientSetupHandler): return self._run_shell_command(f"codex mcp add serena -- {self.get_mcp_server_command()}") -client_setup_handlers = [ClientSetupHandlerClaudeCode(), ClientSetupHandlerCodex()] +class ClientSetupHandlerCodeBuddy(ClientSetupHandler): + def __init__(self) -> None: + super().__init__("codebuddy") + + def is_applicable(self) -> bool: + result = execute_shell_command("codebuddy --version", capture_stderr=True) + return result.return_code == 0 + + def get_mcp_server_options(self) -> list[str]: + return ["--context=codebuddy", "--project-from-cwd"] + + def apply(self) -> bool: + cmd = f"codebuddy mcp add --scope user serena -- {self.get_mcp_server_command()}" + is_success = self._run_shell_command(cmd) + if is_success: + click.echo("\nIMPORTANT: We additionally recommend to set up hooks for CodeBuddy to ensure the best experience.") + click.echo(" Please read the instructions here:") + click.echo(" https://oraios.github.io/serena/02-usage/030_clients.html#codebuddy") + return is_success + + +client_setup_handlers = [ClientSetupHandlerClaudeCode(), ClientSetupHandlerCodeBuddy(), ClientSetupHandlerCodex()] diff --git a/src/serena/hooks.py b/src/serena/hooks.py index 83a0a8cc..e4c76769 100644 --- a/src/serena/hooks.py +++ b/src/serena/hooks.py @@ -22,6 +22,7 @@ class HookClient(Enum): """The client application that triggered the hook.""" CLAUDE_CODE = "claude-code" + CODEBUDDY = "codebuddy" VSCODE = "vscode" CODEX = "codex" @@ -365,7 +366,7 @@ class PreToolUseRemindAboutSymbolicToolsHook(PreToolUseHook): self._file_path = str(file_path).strip() or None def is_grep_call(self) -> bool: - if self._client == HookClient.CLAUDE_CODE: + if self._client in (HookClient.CLAUDE_CODE, HookClient.CODEBUDDY): return self._tool_name == "grep" or "search_for_pattern" in self._tool_name if self._client == HookClient.CODEX and self._is_shell_command_call(): return self._command_name in self._GREP_SHELL_COMMANDS @@ -373,7 +374,7 @@ class PreToolUseRemindAboutSymbolicToolsHook(PreToolUseHook): return "grep" in self._tool_name def is_read_call(self) -> bool: - if self._client == HookClient.CLAUDE_CODE: + if self._client in (HookClient.CLAUDE_CODE, HookClient.CODEBUDDY): return self._tool_name == "read" or "read_file" in self._tool_name if self._client == HookClient.CODEX and self._is_shell_command_call(): return self._command_name in self._READ_SHELL_COMMANDS diff --git a/src/serena/resources/config/contexts/codebuddy.yml b/src/serena/resources/config/contexts/codebuddy.yml new file mode 100644 index 00000000..9e2ff53e --- /dev/null +++ b/src/serena/resources/config/contexts/codebuddy.yml @@ -0,0 +1,52 @@ +description: CodeBuddy (CLI agent where file operations, basic edits, etc. are already covered; single project mode) +prompt: | + You are running in a CLI coding agent context where file operations, basic (line-based) edits and reads + as well as shell commands are handled by your own, internal tools. + + You have access to Serena's code intelligence tools that exploit the symbolic + structure of the code and are much more efficient than your own tools for most coding scenarios. + If you are working on any coding task and if Serena's tools are deferred, you + should load them all immediately, before performing any read, grep or bash commands. + If Serena's tools can be used to achieve your task, you should prioritize them. + **CRITICAL**: If you haven't seen Serena's tools yet, you should use the tool search tool to load all of them + **right now**. + For exploring and reading code in a token-efficient manner, use Serena's code-centric overview and symbolic search tools. + For edits, prefer Serena's editing tools since they are more token efficient. + Especially when editing code you have read through Serena, **ALWAYS** use Serena's tools for editing, because your built-in tools will deny such edits (they will assume you haven't read the content). + **CRITICAL**: Never use a tool before having read its schema via the tool-search tool! + + **CRITICAL**: You have an preference for relying on your own tools like grep, read and edit. It is of paramount + importance that you overcome this preference and instead develop a preference for using Serena's tools since they + are superior for most coding tasks. Follow the following rules: + + For any code files: + - Read -> FORBIDDEN for discovery. Use get_symbols_overview, then find_symbol with include_body. + You may use read only if you already have an overview of the file and if reading whole symbols + is inappropriate (e.g. a few lines of code). + - Glob (by name) -> Allowed for discovery only. + - Grep (content) -> Allowed for discovery only; follow up reads or reference searches must be Serena. + - Edit -> FORBIDDEN. Use replace_symbol_body / insert_*_symbol / replace_content. + + Disallowed reasoning. Do NOT use any of the following to justify Read/Edit on a code file: + - "I already know the path" + - "one Read call is faster than three Serena calls" + - "the built-in tool description says to use Read for known paths" + If you catch yourself reaching for one of these, that is the signal to switch to Serena. + +excluded_tools: + - create_text_file + - read_file + - execute_shell_command + - find_file + - list_dir + - search_for_pattern + +tool_description_overrides: {} + +# whether to assume that Serena shall only work on a single project in this context (provided that a project is given +# when Serena is started). +# If set to true and a project is provided at startup, the set of tools is limited to those required by the project's +# concrete configuration, and other tools are excluded completely, allowing the set of tools to be minimal. +# Tools explicitly disabled by the project will not be available at all. +# The `activate_project` tool is always disabled in this case, as project switching cannot be allowed. +single_project: true