name: vibe
description: >
Delegate a coding task to Mistral Vibe and supervise the result via git diff.
Trigger: /vibe . Claude orchestrates, Vibe codes.
Also handles /vibe-report [--since N] [--project NAME] [--fails] — token/cost/failure report.
license: MIT
user-invocable: true
allowed-tools:
- bash
- read_file
- grep
Vibe Orchestrator
/vibeon | /vibeoff | /vibestatus
Toggle auto-delegate mode — Vibe automatically handles coding tasks without requiring /vibe each time.
| Command | Action |
|---|---|
/vibeon |
touch ~/.local/share/vibe-auto.flag → confirm "Auto-vibe ON" |
/vibeoff |
rm -f ~/.local/share/vibe-auto.flag → confirm "Auto-vibe OFF" |
/vibestatus |
report auto-mode (ON/OFF) and active model override |
For /vibestatus, run both checks and print two lines:
Auto-vibe: ON | OFF
Model: <alias> (override) OR Model: deepseek-flash (config default)
Auto-mode pre-filter (when flag is set)
When vibe-auto.flag exists, apply this gate before loading the full skill:
| Task signal | Action |
|---|---|
| 1 file, ≤10 lines, exact location already known | Edit directly — do NOT invoke the skill |
| Logic non-trivial, location unclear, multiple files, HTML/JS content, or >1 change | Invoke /vibe as normal |
/vibe-report
If the user invokes /vibe-report, run ~/tools/delegate-report with any flags
extracted from the arguments, display output verbatim, and stop.
| User says | Flag |
|---|---|
| "last 7 days", "7d" | --since 7 |
| "last 30 days", "30d" | --since 30 |
| "project foo" | --project foo |
| "only failures", "fails", "bugs" | --fails |
| "adapt", "adaptations", "by adaptation" | --adapt |
| "all delegates", "everything", "compare delegates" | --all |
| "delegate foo", "only opencode" | --delegate foo |
| (nothing) | (no flags — vibe runs only) |
The report defaults to vibe runs only. The log is shared across delegate
tools (vibe, opencode, gemini); use --all for the cross-delegate comparison
or --delegate NAME to scope to a different one.
/vibe-model-pick | /vibe-model-clear
Override the Vibe model for all subsequent delegations without touching ~/.vibe/config.toml.
| Command | Action |
|---|---|
/vibe-model-pick <alias> |
echo <alias> > ~/.local/share/vibe-model.flag → confirm |
/vibe-model-clear |
rm -f ~/.local/share/vibe-model.flag → confirm "back to config default" |
Available aliases (from ~/.vibe/config.toml):
| Alias | Model | Provider | Notes |
|---|---|---|---|
deepseek-flash |
deepseek-v4-flash | DeepSeek | Default — fast, cheap; solid for inline edits |
mistral-medium-3.5 |
mistral-vibe-cli-latest | Mistral | Stronger reasoning; reliable for inline edits |
devstral-small |
devstral-small-latest | Mistral | Agent-mode — read/explore only, weak at inline edits |
local |
devstral (llamacpp) | Local | Requires local server on :8080 |
Run the bash command, print one confirmation line showing the active model, and stop.
When the user invokes /vibe <instruction>, Claude delegates the implementation
to Mistral Vibe via its programmatic mode, supervises in real time, and reports.
Known Limits
Hard constraints — not config options. Full details in SKILL-reference.md.
- UTF-8 / special chars → silent
search_replacematch failure. Usepython3 str.replace()for accented chars or emoji. - Code duplication → Vibe may re-insert a block already written. Grep for duplicate definitions after every run.
- HTML in prompt → tags like
<div>are shell redirects (exit 127). Write HTML content to a temp file; reference the path in the prompt. - Source code in bash heredoc → quotes/backslashes mangle. Use
search_replacedirectly; never a helper script that replaces code. - Orchestration chain → 6 failure points in order: CLI auth → pseudo-TTY → stream parser → TOML pricing → git diff → JSON log. When a run produces unexpected results, work down this list. Full details in
SKILL-reference.md.
Step 1 — Detect workdir
git rev-parse --show-toplevelin the current directory.- If ambiguous or no git repo → ask with
AskUserQuestion.
Step 2 — Decompose the task
Critical rule: keep tasks atomic and focused — one objective, one prompt.
| Size | Definition | Max turns | Approach |
|---|---|---|---|
| Trivial | 1 file, change is obvious and located | — | Skip delegation — edit directly |
| Simple | 1 file, non-trivial logic or unknown location | 5–8 | 1 vibe call |
| Medium | 2–3 related files, 1 objective | 8–12 | 1 structured vibe call |
| Complex | >3 files OR business logic OR DB migrations | — | Break into sub-tasks |
Decomposition for complex tasks:
Sub-task 1: Explore / read relevant files (read-only, 5 turns)
Sub-task 2: Implement change A in file X (8 turns)
Sub-task 3: Implement change B in file Y (8 turns)
Sub-task 4: Verify / test (5 turns)
→ Check git diff between each sub-task before launching the next.
Step 3 — Write the Vibe prompt
The prompt must be self-contained.
Structure:
Stack: Python/Flask, SQLAlchemy, SQLite
Key files: app.py (routes + fetch), models.py (Entry)
TASK: [one single thing to do, stated as an imperative]
CONSTRAINTS:
- [what must not break]
- [expected format if relevant]
VERIFY: grep for "def function_name" in file.py and confirm it exists.
Formulation rules:
- One task per prompt — never "also do X and Y"
- Name the exact files to modify
- Include a grep-based verification criterion (not a file re-read)
- Language: English (better Mistral performance)
Prompt adaptations:
- Any task that defines or calls a specific function: include the exact signature —
def validate(data: dict) -> tuple[bool, list[str]]:. - No fixed signature, but conventions matter: point at the file to read first ("read app.py, follow its route/jsonify style") instead — don't do both, they're substitutes.
- Write/modify tasks: append an output format block:
OUTPUT FORMAT: Modified: <file> Does: <one line> No other prose.
⚠️ Shell safety: if the prompt contains UTF-8 accented chars, emojis,
:in Python/YAML code, or typographic apostrophes — the vibe-delegate script passes them safely via a temp file (printf %q). Never interpolate such a prompt directly into a bash heredoc.
Verification — always use grep, not file re-read:
VERIFY: grep for "def extract_labels" in app.py and confirm it exists.
Step 4 — Launch Vibe
~/tools/vibe-delegate "<workdir>" "<prompt>" [max-turns] [agent] [timeout-secs]
| Argument | Default | Notes |
|---|---|---|
workdir |
— | Absolute path, must exist |
prompt |
— | Self-contained task description |
max-turns |
10 |
Mistral turn limit — hard cap at 12, never more |
agent |
(none) | See agent table below |
timeout-secs |
180 |
Wall-clock kill timer |
--require STR |
(none) | Repeatable. Abort before launch if STR is absent in the workdir — pass the search_replace anchor here |
--with-review N |
(none) | After Vibe finishes, Claude reviews the diff and re-delegates fixes up to N times (see Step 8) |
--verbose |
(off) | Print per-token-type cost breakdown (input/output tokens × pricing) instead of the compact summary line |
--no-ghostwrite |
(off) | Disable the ghostwrite fallback — after 3 failed Vibe attempts, halt and ask instead of finishing (see Step 6) |
Available agents:
| Agent | Use |
|---|---|
(default → auto-approve) |
General implementation — all tools run without approval |
code-reviewer |
Review only, no changes |
planner |
Planning before implementing |
code-architect |
Architecture design, read-only |
Recommended max turns:
- Read/explore:
5 - Simple change (1 file):
8 - Medium change (2–3 files):
12 - Never exceed
12— decompose instead
Background launch:
~/tools/vibe-delegate "<workdir>" "<prompt>" 10 > /tmp/vibe_out.txt 2>&1 &
# Monitor with: tail -f /tmp/vibe_out.txt
Step 5 — Supervise in real time
The script prints live:
=== VIBE START ===
Workdir : /path/to/project
Agent : default
Turns : 10
Timeout : 180s
Prompt : Stack: Python/Flask. File: app.py ...
===================
[read] app.py
[tool] file: app.py
[tool] search_replace [OK] ...
[vibe] Done. Converted date to datetime.date in fetch_data().
Tool calls: 5
Delegate tokens (run): 4,800 (last turn: 4,600+200) | cost ~$0.0086
Claude Sonnet 4.6 eq: same tokens would cost ~$0.0168 (ratio x2.0)
=== VIBE DONE (exit: 0) ===
=== SYNTAX OK (1 check(s)) ===
=== UNCOMMITTED CHANGES ===
app.py | 4 ++--
[log] → ~/.local/share/delegate-runs.jsonl (4800 tokens, exit 0, 34.2s)
Vibe never commits. All changes are left unstaged — git checkout . reverts everything if needed.
Red flags to act on immediately:
| Flag | Meaning | Action |
|---|---|---|
[WARN] |
Vibe encountered an error | Read the error, fix manually |
[tool] search_replace [FAIL] |
UTF-8 match failure | Edit manually with Python str.replace() |
exit: 1 or non-zero |
Vibe failed / did not complete verification | Read diff, correct prompt |
No [tool] file: lines |
WROTE_NOTHING — Vibe read but wrote nothing |
Revise prompt and retry; ghostwrite fallback after 3 attempts. Follow Step 6. |
Mangled tool name in output (e.g. write_filecepte) |
Vibe produced a garbled tool call — write never executed | Same as WROTE_NOTHING — treat as failed write. Follow Step 6. |
=== SYNTAX ERRORS === |
Post-run syntax check failed | Fix before committing |
| Same file read 5+ times | Vibe is looping — run likely lost | Abort, check diff, try again |
Known bugs and workarounds:
| Bug | Cause | Fix |
|---|---|---|
| Variable declared twice | Vibe doesn't check scope | Grep the variable before relaunching |
| Truncated prompt | Special chars in inline prompt | Script uses temp file — should be fixed |
| Wrote a Python helper just to replace code | Misdiagnosed search_replace limit | Use search_replace directly for ASCII code; write_file only if new content is too long for the prompt |
| Empty run — 0 files changed despite ≥3 tool calls | Multi-edit prompt: first search_replace target not found byte-for-byte |
Split into sequential single-change runs; grep target string locally before delegating |
If exit non-zero: do not relaunch immediately. Read the diff, understand what was done, fix the prompt.
Step 6 — Iteration
- Max 3 attempts per sub-task before escalating to the user.
- Between attempts, read the git diff to avoid doubling partial work.
WROTE_NOTHING / failed write — auto-retry then ghostwrite (default)
When a run produces any of the following:
- No
[tool] file:lines (WROTE_NOTHING) - Mangled tool call output (e.g.
write_filecepte,search_replacecepte) - Non-zero exit with 0 files changed
First, revise the prompt (simpler target, explicit file path, shorter scope) and re-run. This counts against the 3-attempt limit.
If all 3 attempts still produce WROTE_NOTHING or a failed write, the default is to finish the task, not halt. Claude writes the content itself (ghostwrite) — either delegating only the file-write step to Vibe or writing the file directly — then continues the chain. The task always completes; a stubborn Vibe never strands the run.
The Step 7 report must list ghostwritten files separately from Vibe-authored files — never silently mix them:
Files ghostwritten (Claude-authored after 3 failed Vibe attempts):
- path/to/file.ext
--no-ghostwrite — opt out of the ghostwrite fallback
When the user passes --no-ghostwrite to /vibe, Claude must not ghostwrite. After 3 failed attempts, halt and ask instead:
⛔ Vibe wrote nothing after 3 attempts (--no-ghostwrite set).
File expected : <path>
Failure signal: <WROTE_NOTHING | mangled write | exit N, 0 files>
Sub-task : <description>
Options:
(r) Revise prompt manually and retry
(a) Abort
Do not proceed to subsequent sub-tasks until resolved.
Step 7 — Report to the user
✓ Vibe finished — <1-line summary>
Files modified:
- path/to/file.ext (+X / -Y lines)
[If problem]:
⚠ <description> — completing manually / relaunching?
Ready to commit?
When --verbose was passed: after the file list, quote the full token/cost block verbatim from the script output — the lines starting with Model, Input, Output, Total, Claude. Do not paraphrase or summarize them. Example:
Model : mistral-medium-3.5
Input : 45,120 @ $1.50/M = $0.0677
Output : 1,280 @ $7.50/M = $0.0096
Total : 46,400 = $0.0773
Claude : 46,400 (@ $3/$15/M) = $0.1531 (x1.98 cheaper)
Step 8 — Review pass (--with-review N)
Triggered only when the user passes --with-review N to /vibe. Runs after Step 5 confirms exit 0.
8.1 — Read the diff
Run git diff (or git diff HEAD if changes are staged). Read the full output. This is Claude's review input — do not ask Vibe to review.
8.2 — Classify issues
Scan only for fundamental issues. Flag these:
| Category | Examples |
|---|---|
| Incorrect logic | off-by-one, wrong branch condition, inverted boolean |
| Crash-causing gap | unhandled None/null dereference, missing required field, index out of range |
| Broken contract | function signature changed without updating callers, return type mismatch |
| Wrong scope | change applied to wrong file/function/class |
| Security hole | unsanitized user input passed to shell/SQL/eval, credentials in plaintext |
Do NOT flag: style, naming, formatting, unused imports, performance, readability, or subjective preferences. If unsure whether an issue is fundamental, skip it.
8.3 — Re-delegate one issue per iteration
For each fundamental issue found (up to N):
- Write one atomic Vibe prompt targeting that single issue (follow Step 3 rules).
- Launch via
vibe-delegate(same workdir, same model). - After Vibe finishes, re-read the diff and re-evaluate: did the issue get fixed?
- Move to the next issue (or stop if N exhausted or no issues remain).
Never bundle two fixes into one prompt. One issue → one delegation → one diff check.
If N iterations are exhausted and issues remain, list them but do not attempt further fixes — report and stop.
8.4 — Tracking state across iterations
Maintain these counters locally (not persisted mid-run):
review_iterations_allowed = N
review_iterations_used = 0
review_issues_found = <count from initial diff review>
review_issues_fixed = 0
review_issues_remaining = review_issues_found
Increment review_iterations_used and review_issues_fixed after each successful re-delegation. Update review_issues_remaining accordingly.
8.5 — Report
After all iterations or no issues remain, append to the Step 7 report:
Review pass (--with-review N):
Issues found: X
Issues fixed: Y
Issues remaining: Z
Iterations used: A / N
If issues remain, list each one briefly (file:line — description). Do not re-attempt them.
8.6 — Log fields
After the review pass, the run log entry for the original Vibe run must include these additional fields in ~/.local/share/delegate-runs.jsonl:
"review_iterations_allowed": N,
"review_iterations_used": A,
"review_issues_found": X,
"review_issues_fixed": Y,
"review_issues_remaining": Z
When --with-review is not used, all five fields are omitted (do not write them as 0).
Orchestration rules
- Decompose before delegating — one task, one prompt.
- Streaming always — never
--output text. - Check diff between sub-tasks — never launch the next one blind.
- Ghostwrite only as a last resort — always delegate to Vibe first; never write code yourself before 3 failed attempts. After 3 failures the default is to ghostwrite and finish (declare it in the Step 7 report).
--no-ghostwritedisables the fallback and halts instead. See Step 6. - Max 12 turns per call — decompose instead of extending.
- Grep target before delegating —
grep -n "exact_target" file.pybefore anysearch_replaceprompt. Pass that anchor as--require "exact_target"so the delegate aborts before launching if it's gone. Always use grep for VERIFY, not file re-read. - Match model to task — inline-edit tasks →
deepseek-flashormistral-medium-3.5; never route edits to agent-modedevstral-small(read/explore only). - UTF-8 / emoji in the prompt → the script handles it via temp file, but test with a short prompt first.
- UTF-8 in OLD/NEW strings → mandate python3, no exceptions — before writing any Vibe prompt, scan every OLD and NEW string for accented chars (é è à ç ù ô î û ñ...) or emoji. If ANY are present, the prompt MUST explicitly instruct Vibe to use
python3 -cwithpathlib.Path.read_text/write_text(encoding='utf-8')for those changes — neversearch_replace. Asearch_replace [OK]on UTF-8 content is a silent no-op: the tool call is accepted but the string is never found. This is the #1 cause of phantom successful runs that changed nothing. - Check string delimiters before delegating JS/JSON changes — if a replacement value contains apostrophes (
') and the target JS property uses single-quote delimiters, the NEW string must switch to double-quotes (") for that property. Scan OLD→NEW pairs for this conflict before writing the prompt; never leave it to Vibe to discover at runtime. - After any run that touches imports: grep the import line — always run
grep "^from X import" file.pybefore the next sub-task. - search_replace [OK] ≠ correct change — always grep the specific changed line, not just check syntax.
- Provide data structure context — if a route accesses a DB payload, include the exact field paths (
payload['produit']['nom']) in the prompt. - Reuse existing assets — for UI tasks, tell Vibe to link existing CSS/JS files. "Use
/static/style.cssand CSS classbar-row" is always better than "generate a dark theme".
Run Log
Every run appends one JSON entry to ~/.local/share/delegate-runs.jsonl.
Log fields and jq queries → see SKILL-reference.md.
~/tools/delegate-report # vibe runs only (default)
~/tools/delegate-report --since 7 # last 7 days
~/tools/delegate-report --project myapp # filter by project
~/tools/delegate-report --fails # failures only
~/tools/delegate-report --adapt # failure rates by prompt adaptation
~/tools/delegate-report --all # all delegates (shared log)
~/tools/delegate-report --delegate opencode # a specific delegate
Or via Claude Code: /vibe-report [args]. Log fields and jq queries → SKILL-reference.md.
Review pass fields — see §8.6 for log field definitions. Present only when --with-review N was used.
See Also
A sister delegate using Gemini CLI exists: gemini-skill.
Both write to the same delegate-runs.jsonl log, making runs comparable across delegates.
This skill is improved regularly — run update-skills to pull the latest version of this skill, as well as all your other skills!