Skip to content

feat(hooks): transparent pre_tool rewrite for Mistral Vibe CLI (closes #800) - #3391

Merged
aeppling merged 6 commits into
rtk-ai:developfrom
xavierpestel-ai:feat/vibe-hook-support
Aug 6, 2026
Merged

feat(hooks): transparent pre_tool rewrite for Mistral Vibe CLI (closes #800)#3391
aeppling merged 6 commits into
rtk-ai:developfrom
xavierpestel-ai:feat/vibe-hook-support

Conversation

@xavierpestel-ai

Copy link
Copy Markdown
Contributor

Closes #800.

Why now

Issue #800 was blocked on mistralai/mistral-vibe#531 — Vibe CLI lacked a
BeforeTool-style hook to intercept and rewrite bash tool calls before
execution. That upstream is now delivered:
https://docs.mistral.ai/vibe/code/cli/hooks documents a pre_tool hook that
returns hook_specific_output.tool_input to fully replace the model's tool
arguments. This is functionally equivalent to Claude Code's PreToolUse and
Gemini's BeforeTool, so RTK can now do a transparent rewrite in Vibe with
the same guarantees as those hosts.

What this PR does

Adds two things:

  1. rtk init -g --agent vibe — installs a pre_tool hook entry into
    ~/.vibe/hooks.toml and (optionally) a system prompt fallback at
    ~/.vibe/prompts/rtk.md. Idempotent, dry-run capable, uninstallable.
  2. rtk hook vibe — the native binary hook process referenced by the
    installed entry. Reads Vibe's pre_tool JSON payload from stdin, decides
    via the shared decide_hook_action engine, and emits Vibe's rewrite
    response shape on stdout.

Result: every bash tool call Vibe makes (including compound && chains) is
rewritten to rtk <cmd> transparently, and the Vibe UI surfaces
[rtk-rewrite] rtk: rewrote to \…`` for visibility.

Files changed (6 files, +525 / −2)

File Change
src/hooks/constants.rs VIBE_DIR, VIBE_HOOKS_FILE, VIBE_HOOK_COMMAND, VIBE_HOOK_NAME, prompts subdir/file, bash match string
src/hooks/permissions.rs Host::Vibe variant — Vibe stores hooks in hooks.toml, not in a settings JSON with permission rules, so no rule loader is wired
src/hooks/hook_cmd.rs pub fn run_vibe() — 56 lines, parses stdin, emits Vibe's rewrite / deny / passthrough response
src/hooks/init.rs run_vibe_mode() + run_vibe_mode_at(), patch_vibe_hooks_toml(), uninstall_vibe() + uninstall_vibe_at(), strip_vibe_rtk_entry(), plus 10 unit tests
src/main.rs AgentTarget::Vibe, HookCommands::Vibe, dispatch through Commands::Init and uninstall dispatch
README.md Vibe row in the supported-agents table flipped from Planned (#800) / Blocked on upstream to rtk init -g --agent vibe / pre_tool hook (hooks.toml)

Design choices (matching existing integrations in this repo)

  • Native binary hook (rtk hook vibe) rather than a shell script — same
    pattern as Claude Code / Cursor / Droid post-v0.37.2. Zero shell / bash /
    jq runtime dependency, works on Windows out of the box.
  • Global-only install (rtk init -g --agent vibe) — same constraint as
    the Gemini integration, since ~/.vibe/hooks.toml is user-scoped.
  • Hook name rtk-rewrite in Vibe's registry, match = "bash",
    strict = false — a crash in rtk hook vibe degrades to a warning and a
    passthrough rather than denying the tool call.
  • String-level TOML patching (append-only, boundary-aware removal)
    rather than a toml_edit parse → serialize round-trip. Preserves any
    user comments and formatting in hooks.toml. Justified because the
    operation is genuinely append-only for install and single-block-removal
    for uninstall — no in-place field mutation is needed.
  • Idempotent install — detects existing name = "rtk-rewrite" before
    appending; re-running the installer is a no-op.
  • Surgical uninstall — strips only the RTK [[hooks]] block plus the
    ~/.vibe/prompts/rtk.md prompt file. Preserves any other user-declared
    hook in the file byte-for-byte. Removes hooks.toml only when the RTK
    entry was the sole content, so no orphan empty file is left behind.
  • Prompt fallback (~/.vibe/prompts/rtk.md) installed alongside the
    hook — belt-and-suspenders behavior described in feat: add transparent hook support for Mistral Vibe (BeforeTool) #800. --hook-only
    skips it if the user doesn't want it.

Hook response contract

Verified against Vibe's docs. On a matching bash command:

{"hook_specific_output":{"tool_input":{"command":"rtk git status"}},"system_message":"rtk: rewrote to `rtk git status`"}
  • Empty command / non-bash tool / RTK-unknown command → passthrough
    (exit 0, empty stdout — Vibe's contract for "no opinion")
  • RTK permission deny → {"decision":"deny","reason":"..."}

Slightly different from Gemini's contract: Vibe uses hook_specific_output
(snake_case) not hookSpecificOutput, has no ask_user decision, and does
not use an allow decision for the passthrough case. The run_vibe
implementation is therefore separate from run_gemini rather than a shared
emitter.

Tests

10 new unit tests in src/hooks/init.rs::tests, grouped under a
// ── Vibe tests ──── divider:

Test Covers
test_vibe_detects_rtk_entry_by_name_field vibe_hooks_toml_has_rtk truth table
test_vibe_hook_entry_shape_matches_docs Emitted entry has every field Vibe requires
test_vibe_strip_returns_none_when_entry_absent Uninstall is a no-op when RTK not installed
test_vibe_strip_removes_only_rtk_entry Sibling [[hooks]] blocks preserved
test_vibe_install_creates_hook_and_prompt Happy path
test_vibe_install_is_idempotent Second install does not duplicate the entry
test_vibe_install_preserves_existing_user_hook User's own hook untouched
test_vibe_hook_only_skips_prompt_file --hook-only flag honored
test_vibe_uninstall_removes_only_rtk_entry_and_prompt Surgical, idempotent removal
test_vibe_uninstall_removes_hooks_file_when_no_other_hooks No orphan empty file

Quality gates

  • cargo fmt --all — clean
  • cargo clippy --all-targets — no issues
  • cargo test --all — 2572 passed / 0 failed in the unit suite; all 10 new
    _vibe tests green
  • Note: 6 guard_integration_test failures reproduce identically on
    unmodified develop — a parallel git init tempdir race in the test
    harness, unrelated to this change (verified by re-running the same test
    set on develop before opening this PR)

End-to-end manual verification against a real ~/.vibe/

Verified live inside a Mistral Vibe session, with the installed hook pointing
at the freshly-built binary:

  • --dry-run prints the plan without touching disk
  • Real install creates the [[hooks]] entry and ~/.vibe/prompts/rtk.md
  • Re-install is idempotent (grep count stays at 1)
  • Uninstall preserves user's own hooks byte-for-byte and removes
    hooks.toml when the RTK entry was the only content
  • Vibe UI surfaces [rtk-rewrite] rtk: rewrote to \rtk git status`` and
    passes the rewritten command to the tool execution path
  • Compound && chains rewrite per-subcommand (cd X && git status && git log ... && git branch → each git subcommand becomes rtk git … while the
    chain structure is preserved) — the trickier case, worked first attempt
    because RTK's shared rewrite_command already handles this

How to review

Suggested reading order:

  1. src/hooks/hook_cmd.rs — the run_vibe() function (~50 lines). This
    is the whole runtime contract. Compare against run_gemini() right above
    it to see the diff in Vibe's response shape.
  2. src/hooks/init.rs — the install / patch / uninstall / strip
    quartet. strip_vibe_rtk_entry is the only piece with non-trivial logic
    (walks [[section]] boundaries in the raw TOML text to know what to
    delete without disturbing siblings) — its behavior is pinned by 4 tests.
  3. The 10 new tests at the bottom of src/hooks/init.rs::tests.
  4. Optional: src/hooks/constants.rs, src/hooks/permissions.rs,
    src/main.rs, README.md — all mechanical wiring, follow the pattern
    of AgentTarget::Droid / HookCommands::Droid / Host::Droid from fix(permissions): stop extra whitespace from evading deny rules #3211.

Try it locally

cargo install --path .
rtk init -g --agent vibe --auto-patch
# restart Vibe CLI
vibe

Then ask Vibe to run any bash command (e.g. run git status). You should
see [rtk-rewrite] rtk: rewrote to \rtk git status`` in the Vibe UI and
compressed RTK output flowing back to the agent.

Uninstall symmetrically:

rtk init -g --agent vibe --uninstall

Out of scope for this PR (deliberately)

Related

Add `rtk init -g --agent vibe` and `rtk hook vibe` to route bash tool
calls through the RTK proxy via Vibe's newly-shipped pre_tool hook.

Implementation follows the Gemini / Droid pattern:
- Native binary hook (`rtk hook vibe`), no shell script dependency.
- Global-only install (`~/.vibe/hooks.toml`); user-scope only.
- Idempotent install: detects existing `name = "rtk-rewrite"` entry.
- Uninstall is surgical: strips only the RTK `[[hooks]]` block and the
  `~/.vibe/prompts/rtk.md` prompt file, preserving any other user hooks
  byte-for-byte. Removes hooks.toml only when it becomes empty.
- Hook response uses Vibe's documented `hook_specific_output.tool_input`
  rewrite contract with a `system_message` for UI visibility.

Vibe hook API reference:
https://docs.mistral.ai/vibe/code/cli/hooks

Closes rtk-ai#800.
@CLAassistant

CLAassistant commented Aug 4, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@aeppling aeppling left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for this — the code follows the Droid (#3211) pattern closely, the install/uninstall logic is well tested, and the transparent-rewrite design is right. Core wiring (constants, permissions, hook_cmd, init, main) is complete. The gaps are in docs, telemetry, and the runtime path:

Blocking

1. Documentation not updated where CONTRIBUTING requires it

  • docs/guide/getting-started/supported-agents.md — still says Vibe is planned: frontmatter description, intro (line 10), tier table (line 46), and the ### Mistral Vibe (planned) section (line 200). Please add a full Vibe section modeled on Factory Droid's (install/uninstall, scope, permission semantics).
  • hooks/README.md — "9 supported agents" (line 7), per-agent sections, and the hook-type comparison tables have no Vibe entry. CONTRIBUTING's documentation table explicitly lists this file for hook system changes.
  • src/hooks/README.md — agent count (line 9) and the per-host ask-support table (line 85) need a Vibe row.
  • README.md:384 — "RTK supports 15 AI coding tools" should now read 16.

(Droid skipped the two hook READMEs too, so part of this is inherited debt — but since this PR flips Vibe from planned to supported, it's the right moment to pay it for Vibe at least.)

2. Runtime hook violates the exit-code contract on malformed JSON

run_vibe uses serde_json::from_str(&input).context(...)?, so a bad payload exits non-zero. src/hooks/README.md § Exit Code Contract is explicit: hook processors must return Ok(()) on every path — success, no-match, parse error, unexpected input. run_copilot, run_cursor, and run_droid all do this (stderr warning, return Ok(())); run_gemini doesn't, and hooks/README.md:223 already lists that as a known bug — please don't add a second instance. strict = false mitigates it for the RTK-installed entry, but manual installs may not set it.

3. No tests for the runtime hook path (run_vibe)

The 10 init/uninstall tests are solid, but the hook contract itself has zero coverage. run_droid is structured as a testable run_droid_inner(input) -> Option<String> with payload tests — please mirror that: extract run_vibe_inner(input) and cover the rewrite happy path, non-bash tool passthrough, empty command, and malformed JSON.

Should fix

4. Telemetry agent detection

src/core/telemetry.rs:362 maps installed hook files to an agent name (claude, gemini, cursor, copilot, …). Without a ~/.vibe/hooks.toml entry, Vibe sessions report as unknown. You offered this as a follow-up in the description — it's a small addition (one map entry plus the test enums at lines 579/591), so consider folding it in here.

5. Dead deny arm

Host::Vibe loads no rules, so the Deny verdict — and the {"decision":"deny"} response — can never fire, though the PR description advertises it. Add a short comment explaining the arm is defensive-only, or wire Vibe's native permission config if one exists. Related: does Vibe expose a denylist/allowlist? Droid steps aside on natively denylisted commands so the host's block fires on the original command — if Vibe has an equivalent, it deserves the same treatment.

6. Broken link in the skip-mode message

https://github.com/rtk-ai/rtk#mistral-vibe doesn't resolve — README has no per-agent headings. Suggest pointing at the supported-agents doc page. (Gemini's #gemini-cli link has the same problem; no need to fix that here.)

Nits (non-blocking)

  • After PatchMode::Skip or a declined prompt, the summary still prints "Mistral Vibe CLI hook installed (global)." — misleading, though Gemini shares the quirk.
  • Install requires -g but uninstall works without it — minor asymmetry.
  • vibe_hooks_toml_has_rtk matches exact spacing name = "rtk-rewrite"; a reformatted file (name="rtk-rewrite") defeats idempotency and causes a duplicate append. Acceptable string-level tradeoff, just noting it.
  • While in src/hooks/README.md: the add-agent checklist's step (3) says to register the hook path in hook_check.rs, but production hook_check only checks the Claude hook nowadays — stale instruction, worth a one-line fix.

…docs

Addresses @aeppling's review on rtk-ai#3391:

Blocking fixes:
- run_vibe now returns Ok(()) on malformed JSON (matches run_droid /
  run_copilot / run_cursor pattern). Prior code violated the exit-code
  contract documented at src/hooks/README.md:100 — a bad payload exited
  non-zero and blocked the agent's command. Fixed via a match on
  serde_json::from_str with a stderr warning fallback.
- Extract run_vibe_inner(input: &str) -> Option<String> from run_vibe so
  the hook contract is unit-testable (mirrors run_droid_inner). Public
  run_vibe becomes a thin stdin/stdout wrapper.
- Add 6 runtime tests exercising the hook contract: bash rewrite happy
  path, non-bash tool passthrough, empty command passthrough, malformed
  JSON returns None, unknown binary passthrough, substitution defers.

Should-fix:
- Telemetry agent detection: add ~/.vibe/hooks.toml to detect_hook_type()
  checks in src/core/telemetry.rs, plus the two test enum arrays so Vibe
  sessions no longer report as 'unknown' in rtk gain history.
- Dead deny arm: add a comment on Host::Vibe in permissions.rs
  documenting that the empty-rules branch is defensive scaffolding for
  when Vibe ships native denylist/allowlist config we can honor.
- Broken link: patch_vibe_hooks_toml skip-message now points at
  https://www.rtk-ai.app/guide/getting-started/supported-agents#mistral-vibe
  instead of a fragment that doesn't resolve.

Nits addressed:
- Install summary no longer prints 'hook installed' when the user chose
  PatchMode::Skip or declined the interactive prompt. patch_vibe_hooks_toml
  now returns a VibeHookPatchOutcome enum (Installed / AlreadyPresent /
  Skipped) and the caller gates the summary on it.
- Document the string-spacing tradeoff on vibe_hooks_toml_has_rtk: a
  reformatted 'name="rtk-rewrite"' would defeat idempotency, acceptable
  because we control the writer and toml_edit round-trip would clobber
  user comments.
- Fix stale line in src/hooks/README.md 'Adding New Functionality':
  hook_check.rs::maybe_warn() only checks the Claude Code hook now,
  not every agent.

Documentation:
- docs/guide/getting-started/supported-agents.md: frontmatter now lists
  Mistral Vibe, drop 'planned' from the intro, tier table row flipped
  from 'Planned (rtk-ai#800)' to 'Rust binary (pre_tool) / Yes', replace the
  ### Mistral Vibe (planned) placeholder with a full user-facing section
  modeled on Factory Droid (install/uninstall commands, hook mechanism,
  permission semantics, idempotency contract).
- hooks/README.md: agent count 9 -> 10, add Vibe entry to Directory
  Structure list, add Vibe row to Supported Agents table, add
  '### Mistral Vibe (Rust Binary)' entry to the JSON Formats section
  showing the pre_tool input shape and rewrite response shape.
- src/hooks/README.md: agent count 5 -> 6, add Vibe row to per-host
  ask-support table.
- README.md: '15 AI coding tools' -> '16'.

No behavior change for existing agents.
Every other agent with a dedicated hook implementation carries a
hooks/<agent>/README.md (see antigravity/cline/opencode/copilot/hermes
for the shape). The initial Vibe commit skipped this, leaving Vibe as
the odd one out in the hooks/ layout.

- Add hooks/vibe/README.md following the Copilot template (Rust binary
  hook, no shell dependency). Documents the pre_tool hook location,
  input JSON shape, rewrite response, passthrough / deny behavior,
  and the belt-and-suspenders prompt fallback.
- Fix hooks/README.md Directory Structure entry to point at
  vibe/README.md (previously claimed 'no dedicated subdirectory').
The comment was previously added in response to review point rtk-ai#5. Removed
per follow-up feedback — the arm itself is self-explanatory in context
alongside the other Host variants.
@xavierpestel-ai

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review, @aeppling — every point landed. Pushed 1847b07, then folded in two follow-ups (94ae76b, 0430df4) covering all 3 blocking + all 3 should-fix + 3 of the 4 nits. Item-by-item:

Blocking

1. Documentation — updated all four files:

  • docs/guide/getting-started/supported-agents.md: frontmatter, intro line 10, tier table row 46 flipped from Planned (#800) / Pending upstream to Rust binary (pre_tool) / Yes, and replaced the ### Mistral Vibe (planned) placeholder with a full user-facing section modeled on Factory Droid (install/uninstall commands, hook mechanism, permission semantics, idempotency contract, prompt-fallback rationale).
  • hooks/README.md: agent count 9 → 10, added Vibe to the Directory Structure list, added the Vibe row to the Supported Agents table, and added a new ### Mistral Vibe (Rust Binary) entry to the JSON Formats by Agent section showing the pre_tool input shape and the hook_specific_output rewrite response.
  • src/hooks/README.md: agent count 5 → 6, added Vibe row to the per-host ask-support table with a note that Vibe has no native ask surface so RTK falls through to Vibe's own approval prompt on the rewritten command.
  • README.md:384: 15 → 16.

Follow-up 94ae76b also adds hooks/vibe/README.md (modeled on the Copilot template) so Vibe carries a per-agent README matching every other agent's hooks/<agent>/README.md. The Directory Structure entry in hooks/README.md now links it correctly.

Agree on the inherited-debt call — flipping the hook READMEs for Vibe was the right moment to pay part of that debt down.

2. Exit-code contract — replaced serde_json::from_str(&input).context(...)? in run_vibe with the run_droid / run_copilot / run_cursor pattern: match … { Err(e) => { writeln!(stderr, "[rtk hook] Failed to parse JSON input: {e}"); return None; } }, with run_vibe itself now returning Ok(()) unconditionally. Verified with a live smoke: echo 'not json' | rtk hook vibe now exits 0 with a stderr warning (was non-zero before, which would have blocked the agent's command). Deliberately didn't touch run_gemini in the same commit — separate PR material as you noted.

3. Runtime tests — extracted run_vibe_inner(input: &str) -> Option<String> mirroring run_claude_inner. Skipped the _with_rules variant that Droid/Cursor have because Host::Vibe loads no rules (see #5), so a single hermetic signature was cleaner. Added 6 tests grouped at the bottom of the tests module: bash rewrite happy path, non-bash tool passthrough, empty command passthrough, malformed JSON returns None, unknown-binary passthrough, and substitution defer — matches the Droid test suite density.

Should fix

4. Telemetry — folded in as suggested. Added (home.join(".vibe/hooks.toml"), "vibe") to detect_hook_type()'s checks array and threaded "vibe" through the two test enum arrays at 580 / 592.

5. Dead deny arm — the arm itself stays for the reason you noted: if Vibe ships a native denylist/allowlist later, wiring it becomes a one-line change in check_command_for instead of a variant-add. I initially landed a 5-line explanatory comment on the empty-rules match arm (per your suggestion), but then removed it in 0430df4 — the neighboring Host:: arms are self-explanatory in context, and the extra prose was heavier than the code it was documenting. Happy to reinstate a shorter one-liner if you'd prefer.

6. Broken link — the skip-mode message now points at https://www.rtk-ai.app/guide/getting-started/supported-agents#mistral-vibe. Left the Gemini #gemini-cli case alone as you suggested.

Nits

N1 — install summary is now gated on a new VibeHookPatchOutcome { Installed, AlreadyPresent, Skipped } enum returned by patch_vibe_hooks_toml. The Skipped path (both PatchMode::Skip and a declined interactive prompt) prints only the manual-setup instructions and returns before the summary block runs; AlreadyPresent surfaces as "Mistral Vibe CLI hook already present (global)."; Installed keeps the original wording. Verified end-to-end via a temp-$HOME smoke.

N3 — extended the vibe_hooks_toml_has_rtk docstring documenting the string-spacing tradeoff: a reformatted name="rtk-rewrite" would defeat idempotency and cause a duplicate append on re-install. Accepted because our own installer only ever writes the canonical spacing, and the alternative (toml_edit parse → serialize round-trip) would clobber user comments and formatting in the file. Documented for future maintainers.

N4 — rewrote the src/hooks/README.md "Adding New Functionality" section. The stale hook_check.rs step is now an explicit note that hook_check.rs::maybe_warn() only checks the Claude Code hook — other agents don't have an outdated-hook warning path. Also expanded the checklist to cover HookCommands::<Agent> + AgentTarget::<Agent> wiring in main.rs and the Host::<Agent> variant in permissions.rs, since Vibe walked me through both and neither was on the original list.

N2 skipped — the install-requires--g/uninstall-doesn't asymmetry matches the existing Gemini path. Left alone here to keep the diff focused on Vibe; happy to unify in a follow-up if you'd prefer it in this PR.

Follow-ups on top of 1847b07

  • 94ae76b — add hooks/vibe/README.md (modeled on the Copilot per-agent README, ~19 lines) and fix the hooks/README.md Directory Structure entry to link it. Brings Vibe up to parity with every other agent's hooks/<agent>/README.md.
  • 0430df4 — remove the 5-line defensive-only comment I had landed above Host::Vibe; see fix: pass git flags transparently to git command #5 above.

Quality gates

  • cargo fmt --all --check — clean
  • cargo clippy --all-targets — no issues
  • cargo test --all — 2578 passed / 0 failed in the unit suite (2572 + 6 new test_vibe_* runtime tests). All 16 Vibe tests green (10 install/uninstall from the initial commit + 6 new runtime).
  • Same 6 guard_integration_test failures as before — reproduce identically on unmodified develop (parallel git init tempdir race in the test harness), unrelated to this diff.

Ready for another look.

…paths

The Semgrep security scan on PR rtk-ai#3391 flagged 2 new fs::remove_file calls
in uninstall_vibe_at as blocking findings under the filesystem-deletion
rule (WARNING severity, but the CI runs semgrep --error which promotes
all findings). Both calls are legitimate uninstall behavior:

- prompt file removal at src/hooks/init.rs:4697 — removes only
  ~/.vibe/prompts/rtk.md, which RTK installed itself.
- hooks.toml removal at src/hooks/init.rs:4714 — removes the file only
  when it becomes empty after stripping the RTK entry, so no orphan
  empty file is left behind.

Both suppressions follow the existing repo convention (`// nosemgrep:
<rule-id> -- <justification>` on the line above the code), matching
precedents in src/discover/lexer.rs and src/core/stream.rs.
@xavierpestel-ai

Copy link
Copy Markdown
Contributor Author

Fixed the Semgrep failure in 4ff41bd — 2 // nosemgrep: filesystem-deletion suppressions on the Vibe uninstall paths, matching the existing repo convention (precedents in src/discover/lexer.rs and src/core/stream.rs).

Root cause: filesystem-deletion is a WARNING-severity rule, but the workflow runs semgrep --error which promotes all findings to blocking. The 17 pre-existing fs::remove_file / fs::remove_dir_all calls in init.rs pass because the scan runs in --baseline-commit mode and only flags new introductions — only my 2 new uninstall calls were flagged.

Both suppressions carry a short justification per the repo pattern:

  • fs::remove_file(&prompt_path) — removes only ~/.vibe/prompts/rtk.md, which RTK installed itself
  • fs::remove_file(&hooks_path) — removes hooks.toml only when it becomes empty after stripping the RTK entry, so no orphan file is left behind

All other CI jobs on the prior commit (0430df4) were already green: fmt, clippy, tests × 3 platforms, benchmark, Security Scan, doc review, test presence, CLA. Local cargo fmt --check + cargo clippy --all-targets + cargo test --bin rtk vibe (16 Vibe tests) confirm the fix is clean.

CI needs a maintainer to click "Approve and run workflows" on https://github.com/rtk-ai/rtk/actions/runs/31018958220 — same external-fork gate as the earlier runs.

@aeppling aeppling left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nits

Comment thread src/hooks/init.rs Outdated
Comment thread src/hooks/init.rs Outdated
Two follow-ups to rtk-ai#3391 (review):

1. Move the summary-verb mapping onto VibeHookPatchOutcome as
   summary_verb() -> Option<&'static str>, returning None for Skipped.
   The call site becomes 'else if let Some(v) = outcome.summary_verb()'
   which collapses the guard and the match into a single decision point
   and removes the unreachable!() branch. If a future variant is added,
   the compiler forces a decision in summary_verb() and the caller
   handles it naturally through the Option.

2. uninstall_vibe now prints a stderr warning when resolve_vibe_dir()
   fails instead of silently returning Ok(()). Users asking to uninstall
   no longer see an empty response when the home dir can't be resolved.
   uninstall_gemini has the same swallow-and-return-Ok pattern; leaving
   that untouched here to keep the diff scoped to Vibe, but the same
   improvement would apply as a follow-up.

Both are quality improvements with no behavior change on the happy path.
@aeppling

aeppling commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Tested on mistral vibe, approved.

@xavierpestel-ai Thanks for contributing to RTK with this new integration !

Follow-up: We should stop tracking all those agent count, this is useless maintenance and can just cause desync between docs -> #3457

@aeppling
aeppling merged commit de1f568 into rtk-ai:develop Aug 6, 2026
11 checks passed
@rtk-release-bot rtk-release-bot Bot mentioned this pull request Aug 6, 2026
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.

feat: add transparent hook support for Mistral Vibe (BeforeTool)

3 participants