fix(vibe): follow the v2.21.0 hook rename and three further upstream drifts - #2441
Merged
Merged
Conversation
…drifts Vibe v2.21.0 graduated hooks from experimental and renamed every hook `type`. `HookType` is a strict enum, so **every** `.vibe/hooks.toml` entry rulesync emitted was rejected and dropped with a `HookConfigIssue`: `before_tool` → `pre_tool`, `after_tool` → `post_tool`, `post_agent_turn` → `post_agent`. The same release removed the `enable_experimental_hooks` flag and its env var — "declaring a hook is enough" — so the auxiliary `.vibe/config.toml` write is gone, along with the `VibeConfigToml` file class and the hooks entry in that file's shared-config ownership. `.vibe/config.toml` is now written by the MCP and permissions features only. Three drifts found in the same pass: - **Permission tool names were wrong for three categories.** Vibe's builtin names are the snake_case of each tool class, so `webfetch` → `web_fetch` and `websearch` → `web_search`; `fetch` and `search_web` do not exist, and `BaseToolConfig` allows extra keys, so those blocks were silently inert. `edit` and `write` both collapsed onto `write_file`, which meant the real `edit` tool never received a rule while `write_file` (create-only since v2.14.0) inherited edit rules. They are now distinct. - **Four per-server MCP keys were dropped.** `prompt`, `sampling_enabled`, `disabled` and `disabled_tools` are what Vibe's `/mcp` panel writes back when a user toggles a server or one of its tools. Since `mcp_servers` is replaced as a whole array on each generate, leaving them out of the passthrough wiped the user's toggle on the next run. - **The shared `~/.agents/skills` root was not discovered in global mode.** Vibe's `user_skills_dirs` returns both `~/.vibe/skills` and `~/.agents/skills`, so the alternative root now applies at either scope rather than project only. The issue's sixth item — commands, which Vibe expresses as skills with `user-invocable: true` — is a feature addition rather than a drift and is left for a separate decision. Refs #2423 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…actually survive Review feedback. HIGH — three e2e permission cases (plus one in the MCP suite) still asserted the old `write_file` mapping, so the E2E job failed on all three runners. `pnpm cicheck` does not cover e2e, which is why the first push looked clean. Fixed. MID — the four MCP keys were only added to the field allowlist, which reads the rulesync source, not the file on disk. The clobbering the issue describes therefore still happened: `mcp_servers` is rewritten as a whole array, so a `/mcp` toggle on a rulesync-managed server disappeared on the next generate regardless. A server rulesync writes is now seeded from the on-disk entry of the same name for exactly those keys, with the rulesync source winning when it states a value. MID — `disabled_tools` maps to the canonical `disabledTools` in both directions rather than passing through raw, the way `codexcli` already renames it. Otherwise a canonical `disabledTools` was ignored for Vibe, and importing from Vibe wrote a snake_case key into `.rulesync/mcp.json` that no other tool reads. MID — the shared `.agents/skills` root is registered through `importOnlySkillRoots`, matching `kimi-code`. `alternativeSkillRoots` is scanned for deletion as well as import, so extending it to global scope would have made every skill under the user's `~/.agents/skills` an orphan-deletion candidate for `--targets vibe --delete` — and the docs sentence added in the previous commit promised the opposite. MID — the permissions docs now carry a migration note: rulesync only rewrites the names it emits today, so `write_file` entries derived from the old `edit` mapping, and inert `[tools.fetch]` / `[tools.search_web]` blocks, need removing by hand. LOW — dropped the comment left behind by the deleted `getExtraSharedWritePaths`, renamed the e2e case that no longer tests an experimental flag, and corrected the skills-processor comment about Vibe's user-scope roots. Tests: the four MCP keys now have coverage — on-disk preservation, the rulesync source overriding a toggle, and the `disabledTools` round trip. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review round 2. HIGH — the `disabledTools` mapping added in the previous commit never fired on generate. The MCP factory declared `supportsDisabledTools: false` for `vibe`, and `convertRulesyncFilesToToolFiles` strips the field before calling the adapter, so the code was unreachable. Import, meanwhile, emits it — which is worse than a no-op: importing from Vibe wrote `disabledTools` into `.rulesync/mcp.json`, and regenerating on a machine with no `.vibe/config.toml` to seed from dropped it, re-enabling the MCP tools the user had disabled. Upstream `_MCPBase.disabled_tools` is exactly the canonical field, so the flag is now true; Vibe has no per-server `enabled_tools`, so that one stays false. The supported-tools matrix picks the change up automatically. The new test could not have caught this: it drove the adapter directly, past the strip. An e2e case now goes through the processor in both directions. LOW — a malformed `.vibe/config.toml` reported smol-toml's bare message, which names no file; under `--targets "*"` that leaves the user guessing which tool's config is broken. Wrapped the way the shared-config gateway wraps its own. LOW — the MCP doc's upstream reference pointed at `_settings.py`, which 404s; those models live in `config/models.py` now. Not changed: canonical `agent` still emits `[tools.agent]` where Vibe's subagent tool is `task`, so an `agent` deny is silently inert. It predates this PR and is outside the v2.21.0 drift this issue tracks — worth its own issue rather than a quiet fix here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review round 3 — no mid-or-above findings; these are the lows. Deferring `agent` → `task` did not hold up: the same PR fixes `fetch` and `search_web`, which are equally unrelated to the v2.21.0 drift and fail the same way — a name Vibe does not have, silently ignored. Vibe's subagent tool is `task`, and OpenCode already carries exactly this rename. An `agent` deny was inert, so subagent spawning stayed enabled after the user forbade it. Mapped in both directions, with a round-trip test. Also: the existing-config parse goes through `parseSharedConfig` rather than a hand-copied error message, so the wording and sanitization stay in one place; a unit test pins the `vibe` strip flags, which is what the previous round's HIGH turned on and what only an e2e run could catch before; and the new e2e case uses the file's own `toTable` / `toTableArray` helpers like its neighbours. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Owner
Author
|
@dyoshikawa Thank you! |
This was referenced Jul 27, 2026
rudironsoni
pushed a commit
to rudironsoni/rulesync
that referenced
this pull request
Aug 8, 2026
…tting inert tables toVibeToolName fell back to the canonical category name verbatim, so categories with no Vibe counterpart (glob, notebookedit, ...) emitted [tools.<category>] tables for tools Vibe does not have - a deny authored there looked applied while being silently inert, the dangerous direction. Unlike agent -> task (dyoshikawa#2441) there is no correct name to rename to, so the category is now skipped with a warning naming it and the affected rule count (the grokcli adapter's pattern). The skip also covers the enabled/disabled cleanup loop and the sensitive_patterns override so no phantom tool names are touched. Unknown on-disk [tools.*] tables still round-trip untouched. Closes dyoshikawa#2485 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
1. Every emitted hook was rejected (breaking, v2.21.0)
Vibe v2.21.0 graduated hooks from experimental and renamed every hook
type:HookTypeis a strict enum andHookConfig.model_validateturns a failure into aHookConfigIssue, so every.vibe/hooks.tomlentry rulesync wrote was dropped at load with a TUI warning. The mapping and the tool-event gate are updated to the current names.2.
enable_experimental_hookswas removedSame release, "Removed": the flag and its
VIBE_ENABLE_EXPERIMENTAL_HOOKSenv var — "No flag is required — declaring a hook is enough." The key is gone fromVibeConfigSchema.Rulesync wrote it into
.vibe/config.tomlas an auxiliary file on every hooks generation. That whole path is removed: theVibeConfigTomlclass,VibeHooks.getAuxiliaryFiles,getExtraSharedWritePaths, and thehooksentry in the file'sSHARED_CONFIG_OWNERSHIP..vibe/config.tomlnow has two writers (mcp,permissions) instead of three, which the shared-write derivation snapshot records.3. Three permission tool names were wrong
Vibe's builtin names come from
BaseTool.get_name()— the snake_case of each tool class:webfetchfetchweb_fetchwebsearchsearch_webweb_searcheditwrite_fileeditwritewrite_filewrite_filefetchandsearch_webdo not exist upstream, andBaseToolConfigallows extra keys, so those blocks were silently inert rather than erroring. Worse,editandwriteboth collapsed ontowrite_file: the realedittool never received a permission or allow/deny list, whilewrite_file— create-only since v2.14.0 — inherited edit rules.4. Four per-server MCP keys were dropped and clobbered
prompt,sampling_enabled,disabledanddisabled_toolsare on_MCPBase, andmcp_settings.pypersistsdisabled/disabled_toolsintoconfig.tomlwhen a user toggles a server or a single tool from the/mcppanel. Rulesync's field allowlist omitted all four, andmcp_serversis replaced as a whole array on each generate — so a user's/mcptoggle on a rulesync-managed server was wiped on the nextrulesync generate. They are passthrough fields now.5. The shared global skills root was not discovered
Vibe's
user_skills_dirsreturns both~/.vibe/skillsand~/.agents/skills, and the README lists both under "Global skills directories". Rulesync registered.agents/skillsas an alternative root for project scope only, sorulesync import --globalnever saw it. It now applies at either scope.Not included
The issue's sixth item — commands, which Vibe expresses as skills carrying
user-invocable: true— is a feature addition rather than a drift from a shipped release, and routing commands onto the skills surface is a design decision (the shapedevinuses). Left on the issue.Tests
The existing Vibe hook/permission suites are updated to the corrected names, which is where the behaviour change shows:
disabled_toolsfor a deniededitcategory is now["edit"]rather than["write_file"], and the test that previously asserted "edit and write merge onto write_file" now asserts they stay on their own tools — that assertion was pinning the bug. The e2e hooks cases assert the newtypestrings and that no.vibe/config.tomlis written for hooks at either scope.pnpm cicheckpasses.Refs #2423