Skip to content

feat(install): add graphify vibe install for Mistral Vibe CLI - #2537

Open
xavierpestel-ai wants to merge 1 commit into
Graphify-Labs:v8from
xavierpestel-ai:feat/vibe-install
Open

feat(install): add graphify vibe install for Mistral Vibe CLI#2537
xavierpestel-ai wants to merge 1 commit into
Graphify-Labs:v8from
xavierpestel-ai:feat/vibe-install

Conversation

@xavierpestel-ai

Copy link
Copy Markdown

Summary

Adds Mistral Vibe (mistralai/mistral-vibe) as a full-parity platform integration, matching Claude Code's shape: skill file + AGENTS.md always-on section + hooks.toml pre_tool guards.

What's included

CLI

graphify vibe install                     # global VIBE_HOME (default ~/.vibe/)
graphify vibe install --project           # project ./.vibe/ + ./AGENTS.md
graphify vibe install --strict            # block first raw read per session
graphify vibe uninstall                   # symmetric cleanup
graphify install --platform vibe          # alias for the global install
graphify uninstall                        # uninstall_all sweeps vibe too

Artifacts installed

  • Skill at VIBE_HOME/skills/graphify/SKILL.md (or ./.vibe/skills/… in project scope) with user-invocable: true frontmatter — exposes /graphify as a native slash command in vibe's autocomplete.
  • AGENTS.md section with the shared ## graphify marker (uses graphify's existing _replace_or_append_section helper, matches how other AGENTS.md platforms register).
  • Two pre_tool hooks in hooks.toml — matchers grep and read_file (vibe's real snake-cased tool names per vibe/core/tools/base.py:get_name) that nudge toward graphify query for search / raw-read operations.

Design decisions worth flagging

Hook matchers use vibe's snake-cased class names. Vibe's hook matcher uses fnmatch, and vibe's BaseTool.get_name() snake-cases the class (Grepgrep, ReadFileread_file). Matching on "read" alone would silently never fire against the real read_file tool — this was caught during real-vibe integration testing before landing.

VIBE_HOME honored for all three artifacts. Vibe's harness manager reads VIBE_HOME/skills, VIBE_HOME/hooks.toml, and VIBE_HOME/AGENTS.md; hardcoding ~/.vibe would silently orphan installs for users who set VIBE_HOME=/opt/vibe-shared.

Ownership by hook name, not command substring. Filtering existing [[hooks]] entries by "graphify" in command would silently delete a user's own hook that happens to shell out to graphify for unrelated reasons. Filtering by hook name in {"graphify-nudge-search", "graphify-nudge-read"} is precise.

shlex.join for hook commands. Vibe runs hooks via asyncio.create_subprocess_shell, so metacharacters in the exe path ($, backticks, ;, (, )) parse as shell operators. The previous "quote only if space" heuristic (still used by the older claude/gemini hook installers) leaves injection open on macOS home dirs containing parentheses.

tomlkit for hooks.toml merges. Preserves user comments and unrelated [[hooks]] entries across install/upgrade cycles. Stdlib tomllib is read-only and only 3.11+ (graphify supports 3.10), so tomlkit>=0.13 is added as a runtime dep — small pure-Python wheel.

Skillgen registration as a monolith. Vibe's SkillMetadata schema requires extra frontmatter fields (user-invocable, allowed-tools) that skillgen's _render_frontmatter emits only name + description for. Registering as a monolith bucket (like aider and devin) lets the skill file carry its own frontmatter without extending the shared renderer. Post-v8 monoliths (no pristine baseline to freeze against) opt out of monolith_roundtrip via roundtrip_ref = None — mirrors _v8_baseline_ref's existing post-v8 handling for the agents platform (4-line skillgen change).

uninstall_all sweep. graphify uninstall now removes vibe artifacts alongside every other platform — otherwise vibe hooks would keep firing after users think they've cleaned up.

Files changed (12)

File LOC Purpose
graphify/install.py +287 _PLATFORM_CONFIG["vibe"], _platform_skill_destination branch, _install_vibe_hook / _uninstall_vibe_hook, _vibe_install / _vibe_uninstall orchestrators, _vibe_home, _vibe_hooks_path, _vibe_agents_md_path, _vibe_hook_entries, _normalize_toml, CLI dispatch branch, _CLI_INSTALL_COMMANDS entry, _project_install / _project_uninstall branches, uninstall_all addition
graphify/__main__.py +6 Re-exports (_vibe_install, _vibe_uninstall, _install_vibe_hook, _uninstall_vibe_hook, _vibe_hooks_path, _vibe_hook_entries)
graphify/skill-vibe.md +709 Rendered skill (from skillgen fragment)
tests/test_vibe.py +483 28 tests
tools/skillgen/fragments/core/vibe.md +709 Skillgen source fragment
tools/skillgen/expected/graphify__skill-vibe.md +709 Blessed CI fixture
tools/skillgen/platforms.toml +9 Vibe platform block (monolith bucket, no roundtrip_ref)
tools/skillgen/gen.py +4 monolith_roundtrip opt-out for post-v8 monoliths
pyproject.toml +10 tomlkit>=0.13 runtime dep, skill-vibe.md in package-data, description enumeration
README.md +6 Both platform tables + CLI reference block
CHANGELOG.md +1 Entry under 0.9.33 (unreleased)
uv.lock ± Regenerated by uv sync

Testing

Automated

  • 28 unit tests in tests/test_vibe.py covering CLI paths, VIBE_HOME symmetry, name-based ownership, shlex.join-safe quoting across 9 hostile paths, 4 malformed TOML shapes, idempotency (no .graphify-bak churn on re-install), strict-flag flow.
  • Full suite: 3922 pass, 36 skip (excluding 3 pre-existing broken/flaky suites unrelated to this work: test_ollama.py, test_ollama_retry_cap.py, test_labeling.py::test_label_communities_batches_when_over_batch_size).
  • All 5 skillgen CI checks pass locally (--check, --audit-coverage, --schema-singleton, --monolith-roundtrip, --always-on-roundtrip).

End-to-end against real Mistral Vibe 2.24.0

  • ✅ Skill discovery — vibe -p "/graphify --help" executes the skill body verbatim
  • ✅ Hooks fire correctly on grep and read_file tool invocations (verified via a disk-tracer hook command that touches a file when triggered)
  • ✅ Full pipeline runs on a sample repo (9 files, cross-module deps) producing a queryable graph: 81 nodes, 124 edges, 7 communities, 91% EXTRACTED confidence
  • ✅ Cross-module architecture queries work: graphify path "handle_login()" "execute()" traced the full login flow (handle_login → login → find_user_by_credentials → execute) across 4 modules

Checklist

  • Branched off v8 (active development branch per README)
  • Commit style: feat: <description> per README §Git workflow
  • uv run pytest tests/ -q passes
  • Skill file registered in tools/skillgen/platforms.toml and the blessed expected/ fixture updated
  • CHANGELOG entry added under 0.9.33 (unreleased)
  • README platform tables + CLI reference updated
  • Package description enumeration includes Mistral Vibe

@xavierpestel-ai
xavierpestel-ai force-pushed the feat/vibe-install branch 2 times, most recently from e138e96 to a02e474 Compare August 7, 2026 15:00

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This pull request appears to reintroduce version 0.9.33 as "unreleased" in the CHANGELOG, removing the previously listed 0.9.34 and 0.9.35 entries, and adds a new feature line describing Mistral Vibe support. It updates the README with graphify vibe install documentation across the install tables and command reference, and wires up new Vibe-related imports (install/uninstall hooks, hook path helpers) in __main__.py. The build.py change removes the _coerce_hyperedge_member_refs helper. The changed-symbols list spans a much broader surface than the shown diff—covering skillgen expected fixtures/fragments, extractor engine/resolution logic, CLI and install modules, and multiple test files (serve, watch, cli_export)—suggesting the full changeset also touches skill generation output, extraction/resolution code, and their associated tests.

No blocking issues surfaced.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 5383 functions depend on the 3268 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 33 callees
  • worse: install() — 5 callers, 12 callees
  • worse: _build_server() — 2 callers, 21 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • …and 1 more

Verification — 5383 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 5383 function(s) in the blast radius were not formally verified this run

· 2 grounded finding(s) anchored inline below; 7 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR adds Mistral Vibe (mistralai/mistral-vibe) as a supported platform for graphify vibe install. It introduces a new vibe platform config, a skill file with user-invocable frontmatter, AGENTS.md integration, and two pre_tool hooks (for grep and read_file) merged into vibe's .vibe/hooks.toml via tomlkit, with corresponding install/uninstall helper functions exported from __main__.py. The surface area includes new install helpers in graphify/install.py (_vibe_install, _vibe_uninstall, _install_vibe_hook, _uninstall_vibe_hook, _vibe_hooks_path, _vibe_hook_entries, plus supporting path/normalization utilities), updates to README and CHANGELOG documentation, and changes to skill-generation tooling/fragments and vibe-related tests. Hook ownership is tracked by name, and both global (VIBE_HOME) and project scopes are handled.

No blocking issues surfaced. 6 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 880 functions depend on the 605 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 33 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 880 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 880 function(s) in the blast radius were not formally verified this run

· 2 grounded finding(s) anchored inline below; 6 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

This PR adds Mistral Vibe (mistralai/mistral-vibe) as a supported platform for graphify install. It introduces a new vibe platform config, a skill file with user-invocable frontmatter, an AGENTS.md section, and install/uninstall logic that merges two pre_tool hooks (for grep and read_file) into vibe's hooks.toml using tomlkit, honoring VIBE_HOME for global scope and both project/global paths. The surface area spans install.py (new _vibe_* helpers, hook entries, config entry, dispatch in install()), exports in __main__.py, README/CHANGELOG documentation updates, associated skill-generation fragments, and tests covering the vibe dispatch and uninstall behavior.

No blocking issues surfaced. 8 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 880 functions depend on the 605 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 33 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 880 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 880 function(s) in the blast radius were not formally verified this run

· 2 grounded finding(s) anchored inline below; 6 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

This PR adds Mistral Vibe as a supported platform for graphify install. It introduces a new vibe platform config, a skill-vibe.md skill file, install/uninstall functions (_vibe_install, _vibe_uninstall), and pre_tool hook management (_install_vibe_hook, _uninstall_vibe_hook) that merge two hooks (for grep and read_file) into vibe's hooks.toml using tomlkit. It also wires up VIBE_HOME-aware path resolution, updates the CLI dispatch and __main__ exports, and adds README/CHANGELOG documentation plus corresponding tests. The surface area spans install.py (new functions and platform config), __main__.py (imports), documentation files, skill/fragment generation tooling, and a test module covering hook installation, comment preservation, and user-authored hook ownership.

Worth a look

  • install(platform='vibe') ignores strict flaggraphify/install.py:612 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 886 functions depend on the 611 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 33 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 886 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 886 function(s) in the blast radius were not formally verified this run

· 2 grounded finding(s) anchored inline below; 6 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
Comment thread graphify/install.py
Adds Mistral Vibe (github.com/mistralai/mistral-vibe) as a full-parity platform integration, matching Claude Code's shape: skill file + AGENTS.md always-on section + hooks.toml pre_tool guards.

Vibe reads .vibe/skills (project, trusted) and VIBE_HOME/skills (user global, default ~/.vibe/skills) per its Agent Skills-compliant harness manager. `user-invocable: true` in the skill frontmatter exposes /graphify as a native slash command in vibe's autocomplete.

Two pre_tool hooks (grep + read_file) nudge toward `graphify query` instead of raw filesystem tools, mirroring the claude/gemini/codex guard pattern. The --strict flag flows to the read_file guard only, matching claude --strict. Matchers use vibe's actual snake-cased tool names (Grep -> grep, ReadFile -> read_file per vibe/core/tools/base.py:get_name) since vibe's hook matcher uses fnmatch.

Ownership is decided by hook `name` in a fixed set, NOT a substring match on `command` -- a substring match would silently delete a user's own hooks that shelled out to graphify for unrelated reasons.

Uses tomlkit for hooks.toml merges so hand-authored comments, key ordering, and unrelated [[hooks]] entries survive graphify install/upgrade. Command strings are built with shlex.join so exe paths containing shell metacharacters are quoted safely for vibe's asyncio.create_subprocess_shell executor.

Honors the VIBE_HOME env var for all three artifacts (skill, hooks, AGENTS.md) so users on non-default vibe setups don't get orphaned installs into a directory vibe never reads.

Skillgen registration: vibe is a monolith bucket (its SkillMetadata schema requires extra frontmatter fields user-invocable + allowed-tools that _render_frontmatter emits only name+description for). Post-v8 monoliths opt out of monolith_roundtrip via roundtrip_ref=None (matches _v8_baseline_ref's existing post-v8 handling for the agents platform).

CLI:
  graphify vibe install                     # global VIBE_HOME (default ~/.vibe/)
  graphify vibe install --project           # project ./.vibe/ + ./AGENTS.md
  graphify vibe install --strict            # block first raw read per session
  graphify vibe uninstall                   # symmetric cleanup
  graphify install --platform vibe          # alias for the global install
  graphify uninstall                        # uninstall_all sweeps vibe too

Tests: 28 covering CLI paths, VIBE_HOME symmetry, name-based ownership, shlex-safe quoting across 9 hostile paths, 4 malformed TOML shapes, and idempotency.

Verified end-to-end against real Mistral Vibe 2.24.0: skill discovery, /graphify slash-command execution, pre_tool hooks fire on grep and read_file invocations, and full pipeline runs on a sample repo producing a queryable graph.

Adds tomlkit>=0.13 as a runtime dep (comment-preserving TOML round-trip; stdlib tomllib is read-only and needs 3.11+ while requires-python is 3.10).
@xavierpestel-ai

Copy link
Copy Markdown
Author

Fixed in caa1460.

The bot was right — install(platform="vibe") at graphify/install.py:612 didn't accept strict, and the CLI dispatcher at line 2357-2363 (previous location) silently dropped the flag on bare graphify install --platform vibe --strict while showing the Claude-Code-oriented deprecation note. --project --strict worked because it routed through _project_install(strict=strict).

Two changes:

  1. install() now accepts strict: bool = False and forwards it to _vibe_install. Other platforms ignore it (their bare-install paths don't need it).
  2. CLI dispatcher suppresses the "Claude Code project hook only" note for vibe and forwards strict=strict through install(). Vibe's global ~/.vibe/hooks.toml (or $VIBE_HOME/hooks.toml) is the legitimate strict-mode target — unlike Claude Code which requires project scope.

Added regression test test_install_platform_vibe_propagates_strict_flag that drives dispatch_install_cli with the exact argv shape and asserts the read hook carries --strict while the search hook stays a nudge.

Verified end-to-end:

  • 29 vibe tests pass (was 28 — added the regression)
  • 558 install-suite tests pass (Claude Code note behavior unchanged)
  • All 5 skillgen CI checks pass
  • Real CLI smoke: graphify install --platform vibe --strict (bare global, no --project) now writes command = "…/graphify hook-guard read --strict" into ~/.vibe/hooks.toml

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

This PR adds Mistral Vibe (mistralai/mistral-vibe) as a supported platform for the graphify vibe install / uninstall commands. It introduces a vibe entry in the platform config plus new helper functions for resolving the vibe home directory (honoring VIBE_HOME), destination paths for skill/AGENTS.md files, and merging two pre_tool hooks (grep + read) into .vibe/hooks.toml via tomlkit, with name-based ownership and a --strict option. It also wires these into the installer dispatch, exports the new symbols from __main__.py, and updates the README and CHANGELOG, alongside generated skill fragments and tests.

Worth a look

  • _refuse_to_modify does not stop execution, causing UnboundLocalError on unparseable hooks.tomlgraphify/install.py · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 888 functions depend on the 613 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _project_uninstall() — 5 callers, 14 callees
  • worse: dispatch_install_cli() — 2 callers, 34 callees
  • worse: install() — 5 callers, 12 callees
  • new: _vibe_install() — 4 callers, 9 callees
  • worse: _copy_skill_file() — 9 callers, 4 callees
  • worse: _project_install() — 2 callers, 14 callees
  • worse: uninstall_all() — 2 callers, 14 callees
  • new: _vibe_uninstall() — 4 callers, 5 callees

Verification — 888 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 888 function(s) in the blast radius were not formally verified this run

· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/install.py
except Exception:
pass
def install(platform: str = "claude", *, project: bool = False, project_dir: Path | None = None) -> None:
def install(platform: str = "claude", *, project: bool = False, project_dir: Path | None = None, strict: bool = False) -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regressioninstall()

fans out to 12 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/install.py
print("one `graphify query` runs (toggle with GRAPHIFY_HOOK_STRICT=0).")


def _vibe_install(project_dir: Path | None = None, *, project: bool = False, strict: bool = False) -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression_vibe_install()

fans out to 9 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/install.py
_print_vibe_install_summary(strict)


def _vibe_uninstall(project_dir: Path | None = None, *, project: bool = False, remove_user_skill: bool | None = None) -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Health regression_vibe_uninstall()

high coupling complexity (Ca·Ce = 20).

Grounded coupling-delta finding (deterministic), not an LLM guess.

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.

1 participant