Skip to content

feat: add CodeBuddy Code support#1967

Open
studyzy wants to merge 8 commits into
rtk-ai:developfrom
studyzy:develop
Open

feat: add CodeBuddy Code support#1967
studyzy wants to merge 8 commits into
rtk-ai:developfrom
studyzy:develop

Conversation

@studyzy

@studyzy studyzy commented May 19, 2026

Copy link
Copy Markdown

Closes #1966

Summary

Adds first-class support for CodeBuddy Code, a Claude-powered AI coding assistant whose config lives in .codebuddy/.

CodeBuddy Code uses the same PreToolUse hook JSON protocol as Claude Code, so the hook implementation delegates directly to the existing process_claude_payload logic.

Changes

New commands

  • rtk hook codebuddy — PreToolUse hook processor (reads JSON from stdin, rewrites tool_input.command)
  • rtk init -g --agent codebuddy — installs hook into ~/.codebuddy/settings.json and writes ~/.codebuddy/CODEBUDDY.md
  • rtk init -g --agent codebuddy --uninstall — removes all RTK artifacts

Files changed

File Change
src/hooks/constants.rs Add CODEBUDDY_DIR (.codebuddy) and CODEBUDDY_HOOK_COMMAND constants
src/hooks/hook_cmd.rs Add run_codebuddy() — delegates to process_claude_payload
src/hooks/init.rs Add run_codebuddy_mode(), uninstall_codebuddy(), and patch_settings_json_at() helper
src/main.rs Add AgentTarget::Codebuddy, HookCommands::Codebuddy, dispatch logic
hooks/codebuddy/rtk-awareness.md RTK awareness instructions embedded into ~/.codebuddy/CODEBUDDY.md
hooks/codebuddy/README.md Integration documentation

Design notes

  • Zero new protocol code: CodeBuddy Code uses the identical PreToolUse + tool_input.command JSON format as Claude Code, so run_codebuddy() simply calls process_claude_payload().
  • patch_settings_json_at(): Extracted a new helper that patches settings.json in an arbitrary directory (instead of hardcoding the Claude config dir). This makes it easy to add future agents with similar config layouts.
  • Global-only: Like Gemini and Cursor, CodeBuddy hooks are installed globally (~/.codebuddy/).

Testing

# Hook rewrite works correctly
echo '{"tool_name":"Bash","tool_input":{"command":"git status"}}' | rtk hook codebuddy
# Output: {"hookSpecificOutput":{"hookEventName":"PreToolUse","updatedInput":{"command":"rtk git status"}}}

# Dry-run init
rtk init -g --agent codebuddy --dry-run -v

# All 1901 existing tests pass
cargo test

Implements rtk-ai#1966

- Add CODEBUDDY_DIR (.codebuddy) and CODEBUDDY_HOOK_COMMAND constants
- Add `rtk hook codebuddy` command that reuses Claude Code's PreToolUse
  JSON protocol (tool_input.command + PreToolUse event)
- Add `rtk init -g --agent codebuddy` to install the hook into
  ~/.codebuddy/settings.json and write ~/.codebuddy/CODEBUDDY.md
- Add `rtk init -g --agent codebuddy --uninstall` to remove artifacts
- Add AgentTarget::Codebuddy enum variant
- Extract patch_settings_json_at() helper for patching settings.json
  in an arbitrary agent config directory (used by CodeBuddy; avoids
  hardcoding the Claude config dir)
- Add hooks/codebuddy/rtk-awareness.md and hooks/codebuddy/README.md
@CLAassistant

CLAassistant commented May 19, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

studyzy and others added 3 commits May 28, 2026 11:36
- Extract patch_settings_json_at() as generic version of
  patch_settings_json_command(), accepting an explicit agent dir
- Extract remove_hooks_from_settings_at() as generic version of
  remove_hook_from_settings(), accepting path + hook commands
- Extract remove_matching_hooks_from_json() from remove_hook_from_json(),
  accepting a command list instead of hardcoding CLAUDE_HOOK_COMMAND
- Delete remove_rtk_hook_from_settings() — CodeBuddy uninstall now uses
  the shared remove_hooks_from_settings_at()
- Keep backward-compatible wrappers for Claude-specific behavior
  (manual instructions output, resolve_claude_dir)
@studyzy

studyzy commented Jun 3, 2026

Copy link
Copy Markdown
Author

Hi maintainers 👋

Just a quick update — I've refactored the CodeBuddy/Claude settings.json handling to eliminate the duplication I introduced earlier. The shared logic is now extracted into:

  • patch_settings_json_at(agent_dir, ...) — generic version of patch_settings_json_command(), accepting an explicit agent config directory
  • remove_hooks_from_settings_at(path, hook_commands, ctx) — generic version of remove_hook_from_settings(), accepting a path and command list
  • remove_matching_hooks_from_json(root, hook_commands) — generic version of remove_hook_from_json(), accepting a command list instead of hardcoding CLAUDE_HOOK_COMMAND

CodeBuddy support is now fully wired up and production-ready:

  • rtk hook codebuddy — PreToolUse hook (delegates to process_claude_payload, zero protocol duplication)
  • rtk init -g --agent codebuddy — installs hook + writes ~/.codebuddy/CODEBUDDY.md
  • rtk init -g --agent codebuddy --uninstall — clean removal

All 1996 tests pass. The refactoring makes it straightforward to add future agents that share the same settings.json hook format — just call the shared helpers with a different directory path.

I'd love to get this merged so CodeBuddy Code users can benefit from RTK's token savings. Happy to address any feedback. Thanks for reviewing!

@smilexiaoming

Copy link
Copy Markdown

When will it be released?

@studyzy

studyzy commented Jun 17, 2026

Copy link
Copy Markdown
Author

Hi @FlorianBruniaux @pszymkowiak — gentle ping on this PR. It has been open for about a month and all 1996 tests pass with zero conflicts.

Just a bit of context on why this matters: I am actively working on adding Headroom support for CodeBuddy Code, and that project integrates RTK as its token-optimization layer. Having this PR merged would make the Headroom + RTK + CodeBuddy Code stack work seamlessly out of the box, which benefits both projects.

Quick recap of the change

  • Adds rtk hook codebuddy — a PreToolUse hook for CodeBuddy Code
  • Zero new protocol code: CodeBuddy Code uses the identical PreToolUse JSON format as Claude Code, so it delegates directly to the existing process_claude_payload logic
  • rtk init -g --agent codebuddy — one-command setup
  • I also refactored the shared settings.json helpers (patch_settings_json_at, remove_hooks_from_settings_at) so there is no duplication — just a thin agent-specific wrapper

Scope

  • New: ~120 lines in src/hooks/ + constants
  • Refactored: extracted generic settings.json helpers that benefit future agent integrations
  • Docs: hooks/codebuddy/rtk-awareness.md + hooks/codebuddy/README.md
  • Tests: all 1996 existing tests pass, no regressions

Would really appreciate a review when you have a moment. Happy to address any feedback or make adjustments. Thanks!

@studyzy

studyzy commented Jun 22, 2026

Copy link
Copy Markdown
Author

Hi @aeppling @KuSh — gentle ping on this PR.

I noticed you two have been actively merging PRs this past week (e.g. #2514, #2465, #2416, #2406, #2394, #2294). Would you mind taking a look at this one when you have a moment?

Quick recap

  • Adds rtk hook codebuddy — a PreToolUse hook for CodeBuddy Code
  • Zero new protocol code: CodeBuddy Code uses the same PreToolUse JSON format as Claude Code, so it delegates directly to process_claude_payload
  • rtk init -g --agent codebuddy — one-command setup
  • Refactored shared settings.json helpers (patch_settings_json_at, remove_hooks_from_settings_at) to avoid duplication
  • All 1996 tests pass, no conflicts, CLA signed

This has been open since May 19. Happy to address any feedback or make changes. Thanks!

@KuSh KuSh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for the PR. A few changes are needed before we can consider merging this.

I’m not familiar with CodeBuddy Code, and while we plan to support the main tools, we don’t necessarily want to add every niche one. Especially since this appears to be compatible with Claude, it seems a symlink to the .claude directory might be all that’s needed.

Could you share a bit more context on why CodeBuddy Code should be integrated here, such as what unique needs it covers beyond Claude compatibility, and how significant its user base or adoption is?

Comment thread docs/guide/getting-started/supported-agents.md Outdated
Comment thread hooks/codebuddy/README.md Outdated
Comment thread hooks/codebuddy/rtk-awareness.md Outdated
Comment thread README.md Outdated
Comment thread src/main.rs Outdated
Comment thread src/hooks/init.rs
Comment thread src/hooks/init.rs Outdated
Comment thread src/hooks/init.rs Outdated
Comment thread src/hooks/init.rs Outdated
Comment thread src/hooks/init.rs
- Delegate run_codebuddy to run_claude (zero protocol duplication)
- Switch remove_hooks_from_settings_at to single &str (YAGNI per reviewer)
- Simplify Skip-mode match to unified print_manual_instructions on Skipped|Declined
- Restore Claude-specific output (backup hint + Restart) lost during refactor
- Fix stale doc comment on patch_settings_json_at (relationship reversed)
- Extract uninstall_codebuddy_at for testability + add 3 unit tests
- Simplify resolve_codebuddy_dir match to ?
- Merge Patched|WouldPatch no-op arms; gate Restart print on AlreadyPresent
- Extract patch_mode_from_flags helper (dedup gemini/codebuddy/default)
- Move CodeBuddy entries to list ends per reviewer nitpick
- Add protocol-stability note to hooks/codebuddy/README.md
- Shared rtk_awareness_for_agent template; drop codebuddy/rtk-awareness.md

All 1999 tests pass.
@studyzy

studyzy commented Jun 29, 2026

Copy link
Copy Markdown
Author

Hi @KuSh, thanks for the thorough review — all feedback addressed in the latest push (commit ee31ba6). All 1999 tests pass.

On the top-level question: why CodeBuddy Code, not a symlink

CodeBuddy Code is an independent product (hosted at cnb.cool/codebuddy/codebuddy-code, built by Tencent) — it is not a Claude Code fork or wrapper. A symlink from ~/.codebuddy to ~/.claude would conflate two separate products and:

  • Pollute the user's Claude Code config with CodeBuddy-specific files (CODEBUDDY.md vs CLAUDE.md) and vice versa.
  • Break isolation: uninstalling one would corrupt the other's state.
  • Assume CodeBuddy reads .claude/ at all, which it does not — it ships its own binary, settings loader, and config directory layout.
  • Couple RTK's CodeBuddy support to Claude Code's config schema evolution, which is exactly the protocol-drift risk you raised on hooks/codebuddy/README.md.

The only thing CodeBuddy Code shares with Claude Code is the PreToolUse JSON payload shape (tool_name + tool_input.command), which is a small stable subset. RTK treats them as separate integrations with independent config dirs, hook commands (rtk hook codebuddy vs rtk hook claude), and uninstall paths. I added a Protocol stability section to hooks/codebuddy/README.md making this explicit.

If you'd like more context on adoption: CodeBuddy Code is the AI coding agent bundled with CodeBuddy (Tencent's AI dev suite). I'm actively integrating RTK as the token-optimization layer for CodeBuddy Code via Headroom, so this PR is what makes that stack work out of the box.

Inline comments

File Change
src/hooks/hook_cmd.rs run_codebuddy() now delegates to run_claude() — body collapsed to a one-liner.
src/hooks/init.rs (remove_hooks_from_settings_at / remove_matching_hooks_from_json) Switched from &[&str] to a single &str — every call site passed one element, no need for the slice.
src/hooks/init.rs (patch_settings_json_command) Replaced the match mode { Skip => ..., other => other } with a single post-call if matches!(result, Skipped | Declined) that prints manual instructions once.
src/hooks/init.rs (patch_settings_json_command) Restored the Claude-specific success output (backup hint + Restart Claude Code [and OpenCode]) that was lost when the body moved into the shared helper.
src/hooks/init.rs (patch_settings_json_at doc comment) Rewrote — the old "Mirrors patch_settings_json_command" was backwards (Claude is now the wrapper, this is the core helper).
src/hooks/init.rs (uninstall_codebuddy) Extracted pure filesystem logic into uninstall_codebuddy_at(codebuddy_dir, ctx) -> Result<Vec<String>> so it is unit-testable; added 3 tests (removes md+hook, idempotent when nothing installed, preserves third-party hooks).
src/hooks/init.rs (uninstall_codebuddy) Replaced the match resolve_codebuddy_dir() { Ok(d)=>d, Err _=> println + return } with ? — HOME resolution failure now propagates as a hard error instead of being silently swallowed.
src/hooks/init.rs (run_codebuddy_mode result match) Merged `Patched
src/main.rs Extracted patch_mode_from_flags(auto_patch, no_patch) into hooks::init and used it in all three call sites (gemini, codebuddy, default) — removes the duplicated if auto_patch { Auto } else if no_patch { Skip } else { Ask } block.
docs/guide/getting-started/supported-agents.md + README.md Moved the CodeBuddy row to the end of each list (kept tier grouping intact rather than a full alphabetical sort, since the table is grouped by integration tier — happy to do a strict alphabetical sort instead if you prefer).
hooks/codebuddy/README.md Added a Protocol stability section explaining that CodeBuddy Code is independent and that RTK tracks its protocol separately from Claude Code.
hooks/codebuddy/rtk-awareness.md Deleted; the per-agent copy was identical to hooks/claude/rtk-awareness.md except for the agent name and trailing md filename. Replaced with a shared rtk_awareness_for_agent(agent_name, md_filename) helper that generates the content from the Claude template at install time. hooks/codebuddy/README.md updated to reflect the new flow.

Happy to adjust anything else.

- Drop the 'Code' suffix everywhere (code + docs): the product is called
  CodeBuddy, not 'CodeBuddy Code'.
- Update the official URL from cnb.cool/codebuddy/codebuddy-code to
  https://www.codebuddy.ai across hooks/codebuddy/README.md.

No behavioral change. All 1999 tests pass.

@KuSh KuSh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes! Unfortunately, there’s one big blocker: CodeBuddy handles exit codes differently from Claude, so we’ll need to adapt the preToolUse shell to account for that. Otherwise LGTM!

Comment thread hooks/codebuddy/README.md
CodeBuddy's PreToolUse protocol uses `modifiedInput` (not Claude's
`updatedInput`), so delegating to `run_claude` silently dropped
every rewrite. Restore a dedicated path.

Two correctness fixes vs the naive delegation:
- Deny verdict now emits `permissionDecision: "deny"` instead of
  returning empty output (which CodeBuddy treats as allow). Without
  this, RTK deny rules were non-functional under CodeBuddy.
- Ask/Default verdicts map to `"ask"` so CodeBuddy prompts the
  user, matching the existing VSCode/Claude path behavior. Previously
  the dedicated path hard-coded `"allow"`, bypassing ask rules.

Also: use `PRE_TOOL_USE_KEY` constant instead of literal, drop
misleading `rtk rewrite` exit-code comment, and fix a pre-existing
rustfmt nit in init.rs so CI `cargo fmt --check` passes.
@studyzy

studyzy commented Jun 29, 2026

Copy link
Copy Markdown
Author

Thanks for catching the exit-code/protocol blocker (@KuSh). I dug into it and the root cause is a protocol field-name mismatch rather than exit codes themselves: CodeBuddy's PreToolUse expects modifiedInput, while run_claude emits updatedInput. Delegating to run_claude (the earlier suggestion in the inline review) silently dropped every rewrite under CodeBuddy.

Changes in the latest push (run_codebuddy now has a dedicated path):

  1. Deny rules actually block. Previously the deny branch returned Ok(()) with empty stdout, which CodeBuddy interprets as "allow". It now emits permissionDecision: "deny" with a reason. Without this, RTK deny rules were non-functional under CodeBuddy.
  2. Ask/Default verdicts map to "ask". The dedicated path previously hard-coded "allow", bypassing RTK-configured ask rules. It now matches the existing VSCode/Claude path (Allow => "allow", else "ask").
  3. Protocol field. Uses modifiedInput (CodeBuddy) instead of updatedInput (Claude).
  4. Dropped the misleading rtk rewrite exit-code comment — run_claude never called rtk rewrite either, so that rationale was a red herring; the real reason is the field-name difference above.
  5. Replaced the "PreToolUse" string literal with the PRE_TOOL_USE_KEY constant for consistency with process_claude_payload.

On the earlier inline suggestion to collapse run_codebuddy into run_claude(): that was posted before the protocol difference was identified, and the final review (#pullrequestreview-4589492705) confirmed adaptation is needed, so I kept them separate.

Verified locally: cargo test (1999 passed), cargo clippy --all-targets -- -D warnings (clean), cargo fmt --all -- --check (clean).

Regarding the updatedInput vs modifiedInput divergence and the permissionDecision semantics, I referenced the local CodeBuddy docs at <dist>/docs/en/cli/hooks.md. If the protocol evolves further, this path may need revisiting.

@KuSh KuSh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. One last minor change is needed

Comment thread src/hooks/hook_cmd.rs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Add support for CodeBuddy (Tencent Cloud AI Code Editor)

4 participants