Hooks
What vibe-dev runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
> /plugin marketplace add andrewcigan/vibe-dev-plugin > /plugin install vibe-dev@vibe-dev
Ships with vibe-dev. Installing the plugin gets these hooks.
What fires, and when
PreToolUse
- Matches
Write|Edit|MultiEdit|Bashbash "${CLAUDE_PLUGIN_ROOT}/hooks/dispatch-pre-tool-use.sh"
PostToolUse
- Matches
Bash|Edit|Write|MultiEditbash "${CLAUDE_PLUGIN_ROOT}/hooks/dispatch-post-tool-use.sh"
Stop
bash "${CLAUDE_PLUGIN_ROOT}/hooks/dispatch-stop.sh"
UserPromptSubmit
Fires before Claude sees each prompt you send. A plugin can use it to inject context, so the same instruction reaches the model every turn instead of only at session start.
bash "${CLAUDE_PLUGIN_ROOT}/hooks/dispatch-user-prompt.sh"
SessionStart
Fires once when a session begins, and again after a context compaction. It is where a plugin sets up its environment, or restores state the compaction dropped.
bash "${CLAUDE_PLUGIN_ROOT}/hooks/dispatch-session-start.sh"
MessageDisplay
bash "${CLAUDE_PLUGIN_ROOT}/hooks/dispatch-message-display.sh"
PreCompact
bash "${CLAUDE_PLUGIN_ROOT}/hooks/pre-compact.sh"
Where it lives
- hooks/dispatch-message-display.shRunsGitHub
Read the script
#!/bin/bash # Vibe Dev v6 — MessageDisplay dispatcher (точка входа на событие MessageDisplay). Язык-ловец. # # Поток: stdin JSON -> guard (vibe-проект?) -> профиль -> clarity-detector по .message_text. # Нарушение (жаргон / развилка без «что теряешь» / человеко-дни) -> (1) запись в # .harness/clarity-violations.log (метрика повторов), (2) displayContent = оригинал + флаг # ловца на экране пользователя. # # ЧЕСТНО: MessageDisplay display-only (контракт code.claude.com/docs/en/hooks) — меняет только # экран, оригинал сохраняется в transcript и его читает Claude. То есть это НЕ enforcement # поведения модели (заставить меня говорить иначе хук не может), а ДЕТЕКТОР: меряет + подсвечивает, # чтобы нарушение не прошло тихо. Дисциплину держит rules/decision-format.md. standard/strict. set -u DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" . "$DIR/lib/hook-io.sh" export VIBE_HOOK_EVENT="MessageDisplay" # для журнала срабатываний (v9 F0.1) hook_read_stdin CWD="$(hook_field '.cwd')" [ -z "$CWD" ] && CWD="$PWD" hook_is_vibe_project "$CWD" || hook_emit_pass PROFILE="$(hook_profile "$CWD")" ROOT="$(hook_plugin_root)" profile_in "standard,strict" "$PROFILE" || hook_emit_pass # hook_run_check (fail-loud): краш детектора -> пометка на экране + crash-артефакт. ISSUES="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "clarity-detector" text "$ROOT/hooks/checks/clarity-detector.sh" "$CWD")" if [ -n "$(printf '%s' "$ISSUES" | tr -d '[:space:]')" ]; then MSG="$(hook_field '.message_text')" case "$ISSUES" in "⚠️ сторож"*) # Детектор УПАЛ — это не «нарушение языка»: в лог нарушений не пишем, краш показываем. hook_emit_display "$MSG $ISSUES" ;; esac # (1) метрика повторов — лог нарушений (для /audit и саморефлексии). mkdir -p "$CWD/.harness" 2>/dev/null printf '%s\t%s\n' "$(date '+%Y-%m-%d %H:%M' 2>/dev/null || echo '?')" "$ISSUES" >> "$CWD/.harness/clarity-violations.log" 2>/dev/null # (2) флаг на экране пользователя (оригинал + пометка). Только экран — Claude читает оригинал. hook_emit_display "$MSG ⚠️ ловец непонятного: $ISSUES. Это для тебя сигнал — можешь попросить сказать проще/по-деловому." fi hook_emit_pass - hooks/dispatch-post-tool-use.shRunsGitHub
Read the script
#!/bin/bash # Vibe Dev v6 — PostToolUse dispatcher (точка входа на событие PostToolUse). # # ⚠️ Живая модель событий (проверка 2026-06-10, движок 2.1.170): PostToolUse для Bash # приходит НЕ на всех командах, и полей tool_response.exit_code/success НЕТ: # - падение С ВЫВОДОМ (stdout или stderr) -> события НЕТ вообще; # - тихое падение (exit!=0 без вывода) -> событие ЕСТЬ, в tool_response появляется # returnCodeInterpretation ("Condition is false" и т.п.) — признак не-успеха; # - чистый успех -> событие есть, returnCodeInterpretation нет. # Поэтому: # Bash: чистый успех (нет interrupted и нет returnCodeInterpretation) -> СБРОС счётчика # повторов; secret-mask по .tool_response.stdout — на любом пришедшем событии. # Edit/Write/MultiEdit -> сброс счётчика повторов (структурное изменение = прогресс). # Инкремент счётчика повторов живёт в PreToolUse-диспетчере (приходит на каждый запуск). # # warn/inject (не block — PostToolUse не может отменить уже выполненный инструмент). Активен # standard,strict; minimal — off. set -u DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" . "$DIR/lib/hook-io.sh" export VIBE_HOOK_EVENT="PostToolUse" # для журнала срабатываний (v9 F0.1) hook_read_stdin CWD="$(hook_field '.cwd')" [ -z "$CWD" ] && CWD="$PWD" # Guard: только vibe-target-проекты. hook_is_vibe_project "$CWD" || hook_emit_pass PROFILE="$(hook_profile "$CWD")" ROOT="$(hook_plugin_root)" # Активен только в standard,strict. profile_in "standard,strict" "$PROFILE" || hook_emit_pass TOOL="$(hook_field '.tool_name')" # v9 F3.3: пин модели субагента — сверка с реестром по факту старта, а не по фронтматтеру. if [ "$TOOL" = "Agent" ]; then PIN="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "model-pin" text "$ROOT/hooks/checks/model-pin-verify.sh" "$CWD" "$ROOT")" if [ -n "$(printf '%s' "$PIN" | tr -d '[:space:]')" ]; then hook_emit_context "PostToolUse" "$(printf '%s' "$PIN" | sed 's/^WARN\t//')" fi fi case "$TOOL" in Bash) # Чистый успех = нет interrupted (^C) и нет returnCodeInterpretation (тихое падение # exit!=0 без вывода) -> сброс счётчика повторов. INTERRUPTED="$(hook_field '.tool_response.interrupted')" RCI="$(hook_field '.tool_response.returnCodeInterpretation')" if [ "$INTERRUPTED" != "true" ] && [ -z "$RCI" ]; then rm -f "$CWD/.harness/bash-repeat-state" 2>/dev/null fi # secret-mask (F8): живой токен в выводе -> updatedToolOutput (маска) + additionalContext # (предупреждение). Живая проверка 2026-06-10 (2.1.170): updatedToolOutput движком # ИГНОРИРУЕТСЯ (вывод у модели остаётся как был — safe-деградация), поэтому рабочий канал — # additionalContext: громкое предупреждение «не переиспользуй литерал, предложи ротацию». # Оба поля шлём в одном объекте: поддержит будущий движок маску — включится сама. MASKED="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "secret-mask" text "$ROOT/hooks/checks/secret-mask-output.sh" "$CWD")" if [ -n "$(printf '%s' "$MASKED" | tr -d '[:space:]')" ]; then case "$MASKED" in "⚠️ сторож"*) hook_emit_context "PostToolUse" "$MASKED" ;; # краш чекера -> предупреждение *) WARN_TEXT="⚠️ Vibe Dev (secret-mask): в выводе команды был ЖИВОЙ токен/ключ. Не печатай и не переиспользуй его литералом — обращайся только как \$ИМЯ_ПЕРЕМЕННОЙ из .env. Токен уже засветился в контексте — предложи пользователю ротацию." jq -cn --arg o "$MASKED" --arg c "$WARN_TEXT" \ '{hookSpecificOutput:{hookEventName:"PostToolUse", updatedToolOutput:$o, additionalContext:$c}}' exit 0 ;; esac fi ;; Edit|Write|MultiEdit) # Структурное изменение -> сброс счётчика повторов (это прогресс, не слепой retry). rm -f "$CWD/.harness/bash-repeat-state" 2>/dev/null ;; esac hook_emit_pass - hooks/dispatch-pre-tool-use.shRunsGitHub
Read the script
#!/bin/bash # Vibe Dev v6 — PreToolUse dispatcher (единая точка входа на событие PreToolUse). # # Поток: stdin JSON -> разбор полей -> guard (vibe-проект?) -> профиль -> роутинг по tool_name # -> сбор вердиктов проверок -> ОДИН stdout JSON (block | warn) или тихий pass. # # Проверки (hooks/checks/*.sh) печатают строки "<VERDICT><TAB><msg>" (BLOCK|WARN), пусто = OK. # Диспетчер — единственное место, которое реально эмитит ответ Claude Code. # # Контракт: docs/hooks-contract-verified-2026-06-03.md set -u DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" . "$DIR/lib/hook-io.sh" export VIBE_HOOK_EVENT="PreToolUse" # для журнала срабатываний (v9 F0.1) hook_read_stdin TOOL="$(hook_field '.tool_name')" CWD="$(hook_field '.cwd')" [ -z "$CWD" ] && CWD="$PWD" FILE="$(hook_field '.tool_input.file_path')" # Guard: трогаем только vibe-target-проекты (есть .harness/ или feature_list.json). hook_is_vibe_project "$CWD" || hook_emit_pass PROFILE="$(hook_profile "$CWD")" ROOT="$(hook_plugin_root)" TAB="$(printf '\t')" BLOCKS="" WARNS="" # add_verdict <multiline-output-проверки> — раскладывает строки по аккумуляторам. # Используется heredoc (не pipe) чтобы переменные остались в текущем shell (bash 3.2). add_verdict() { local _v _m while IFS="$TAB" read -r _v _m; do [ -z "$_v" ] && continue case "$_v" in BLOCK) BLOCKS="${BLOCKS}- ${_m} " ;; WARN) WARNS="${WARNS}- ${_m} " ;; esac done <<EOF $1 EOF } # --- Роутинг --- case "$TOOL" in Write|Edit|MultiEdit) case "$FILE" in *feature_list.json) if profile_in "standard,strict" "$PROFILE"; then # HOOK_PAYLOAD прокидывает намерение (tool_input.content/old_string/edits) в проверку, # чтобы валидировать то, что записывается, а не старое состояние диска. # hook_run_check (fail-loud): краш проверки -> WARN + crash-артефакт, не молчаливый pass. add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "state-transition" verdict "$ROOT/hooks/checks/state-transition.sh" "$FILE" "$CWD" "$ROOT" "$TOOL")" fi ;; esac # secret-scan (v7 P14): хардкод ЖИВОГО ключа в src -> block. Все профили (safety, как bulk-api). # Escape: цель .env-семейство ИЛИ маркер secret-scan-off (фраза «ключ тестовый/забей»). add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "secret-scan" verdict "$ROOT/hooks/checks/secret-scan-write.sh" "$CWD" "$FILE" "$TOOL")" # folder-scope (v7 P9 → v8 L5-F3): запись ВНЕ корня -> WARN по умолчанию (промоушн из log-only). # Все профили, безвредно (warn, не block; block отложен до замера % ложных на корпусе). add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "folder-scope" verdict "$ROOT/hooks/checks/folder-scope.sh" "$CWD" "$FILE")" # concurrent-write advisory для shared-форматов (json/csv/jsonl/yaml), standard/strict if profile_in "standard,strict" "$PROFILE"; then add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "concurrent-write" verdict "$ROOT/hooks/checks/concurrent-write.sh" "$FILE" "$CWD")" # model-swap-guard: правка вносит модель/настройку, влияющую на каждый вывод -> warn (smoke). add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "model-swap-guard" verdict "$ROOT/hooks/checks/model-swap-guard.sh" "$CWD")" # research-гейт архитектуры (F6): docs/ARCHITECTURE*.md без docs/research/*.md и без # хук-маркера research-skipped -> block (распоряжение пользователя 2026-06-10). add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "architecture-research" verdict "$ROOT/hooks/checks/architecture-research-gate.sh" "$FILE" "$CWD")" fi ;; Bash) # bulk-API gate активен во ВСЕХ профилях (про деньги/safety, learn-режим не понижает). add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "bulk-api" verdict "$ROOT/hooks/checks/bulk-api.sh" "$CWD" "$ROOT")" # bash-repeat (анти-залипание №2): инкремент счётчика класса команды ЗДЕСЬ — PreToolUse # приходит на каждый запуск; PostToolUse приходит только на успехе и сбрасывает (живая # модель событий 2.1.170, проверка 2026-06-10). На пороге (3-й запуск без успеха) -> warn. if profile_in "standard,strict" "$PROFILE"; then add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "bash-repeat" verdict "$ROOT/hooks/checks/bash-repeat-counter.sh" "$CWD")" fi # v9 F1.3, первый рубеж: журнал фич правится только через record-change. Сторож переходов # видит вносимое содержимое при Write/Edit и НЕ видит записи командой оболочки — дыра # подтверждалась дважды независимыми проверками. add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "feature-list-bash" verdict "$ROOT/hooks/checks/feature-list-bash-guard.sh" "$CWD")" # Второй рубеж, фаза «до»: снимок состояния журнала фич. Не зависит от формы команды. HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "feature-list-drift" verdict "$ROOT/hooks/checks/feature-list-drift.sh" "$CWD" before >/dev/null ;; esac # v9 F3.2: роль верхнего уровня (архитектура/план/критика/аудит) не пишет код — решение # владельца «Fable рассуждает, код не пишет». Действует и на правку файлов, и на запись # командой оболочки: иначе замок обходится одной строкой, как это уже случалось. add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "role-scope" verdict "$ROOT/hooks/checks/role-scope-guard.sh" "$CWD")" # lock-protect (F6, lock-паттерн): .harness/locks/* пишут только хуки — запись агентом # (Write/Edit/Bash-redirect) блокируется во ВСЕХ профилях (это инфраструктура согласий). add_verdict "$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "locks-protect" verdict "$ROOT/hooks/checks/locks-protect.sh" "$CWD")" # closing-mode (F7, П6): во время закрытия сессии — деградация прав: запись только в # state-файлы, Bash только git/read-only/скрипты плагина. standard/strict. if profile_in "standard,strict" "$PROFILE"; then add_verdict "$(HOOK_PAYLOAD="$ - hooks/dispatch-session-start.shRunsGitHub
Read the script
#!/bin/bash # Vibe Dev v6 — SessionStart dispatcher (точка входа на событие SessionStart). H6 loop-замыкание. # # Поток: stdin JSON -> guard (vibe-проект?) -> профиль -> handoff-pending-probe # -> inject additionalContext (warn о возможном пропуске handoff) или тихий pass. # # Активен standard,strict; minimal — off. Контракт SessionStart: # docs/hooks-contract-verified-2026-06-03.md §4 (stdout идёт как контекст). set -u DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" . "$DIR/lib/hook-io.sh" export VIBE_HOOK_EVENT="SessionStart" # для журнала срабатываний (v9 F0.1) hook_read_stdin CWD="$(hook_field '.cwd')" [ -z "$CWD" ] && CWD="$PWD" # Guard: только vibe-target-проекты. hook_is_vibe_project "$CWD" || hook_emit_pass # Активация (v6.2 F2): heartbeat «хуки живы» + перевод pending-профиля в боевой. # ДО фильтра профиля: heartbeat — свидетельство активации для ЛЮБОГО профиля. hook_write_heartbeat "$CWD" ACTIVATED="$(hook_activate_pending_profile "$CWD")" PROFILE="$(hook_profile "$CWD")" ROOT="$(hook_plugin_root)" # Активен только в standard,strict. if ! profile_in "standard,strict" "$PROFILE"; then [ -n "$ACTIVATED" ] && hook_emit_context "SessionStart" "✅ Vibe Dev: enforcement активирован живым хуком — профиль «${ACTIVATED}» подтверждён." hook_emit_pass fi # hook_run_check (fail-loud): краш проверки -> WARN-строка + crash-артефакт. VERDICT="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "handoff-probe" verdict "$ROOT/hooks/checks/handoff-pending-probe.sh" "$CWD")" MSG="$(printf '%s' "$VERDICT" | awk -F'\t' '$1=="WARN"{print $2; exit}')" # Crash-probe (F1): на старте сессии сообщить о крашах сторожей из прошлых сессий — # fail-loud не должен оставаться незамеченным (иначе деградирует обратно в тихий fail-open). CRASHES="" if [ -d "$CWD/.harness/hook-crashes" ]; then CRASH_LIST="$(ls -1 "$CWD/.harness/hook-crashes" 2>/dev/null | sed 's/\.log$//' | tr '\n' ' ')" if [ -n "$(printf '%s' "$CRASH_LIST" | tr -d '[:space:]')" ]; then CRASHES="⚠️ Vibe Dev: в прошлых сессиях ПАДАЛИ сторожа: ${CRASH_LIST}— их проверки тогда НЕ выполнялись. Открой .harness/hook-crashes/*.log, почини причину (или сообщи о баге плагина), затем удали логи. Пока логи на месте — действия, которые сторожа охраняют, требуют ручной проверки." fi fi # Сборка inject: активация + handoff-warn + crash-probe (что есть). OUT="" [ -n "$ACTIVATED" ] && OUT="✅ Vibe Dev: enforcement активирован живым хуком — профиль «${ACTIVATED}» подтверждён." if [ -n "$MSG" ]; then [ -n "$OUT" ] && OUT="$OUT " OUT="${OUT}${MSG}" fi if [ -n "$CRASHES" ]; then [ -n "$OUT" ] && OUT="$OUT " OUT="${OUT}${CRASHES}" fi # v9 F5.3: разросшиеся журналы — счёт, который иначе не виден. Замер по живым проектам: # журнал фич доходил до 1,16 МБ (≈290 тысяч токенов на каждое чтение), потому что ротация # искала состояние, которого нет в графе переходов, и не срабатывала ни разу. JOURNALS="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "journal-size" text "$ROOT/hooks/checks/journal-size-probe.sh" "$CWD")" if [ -n "$(printf '%s' "$JOURNALS" | tr -d '[:space:]')" ]; then [ -n "$OUT" ] && OUT="$OUT " OUT="${OUT}${JOURNALS}" fi # Канал доставки правок (v7): установлен новый мажор плагина, а проект закреплён ниже. UPGRADE="$(hook_upgrade_nudge "$CWD")" if [ -n "$UPGRADE" ]; then [ -n "$OUT" ] && OUT="$OUT " OUT="${OUT}${UPGRADE}" fi # C1 (v7 Волна 2): бриф возврата — активные фичи + тупики + слепок сжатия + recall-фраза. BRIEF="$(hook_cold_start_brief "$CWD")" if [ -n "$BRIEF" ]; then [ -n "$OUT" ] && OUT="$OUT " OUT="${OUT}${BRIEF}" fi [ -n "$OUT" ] && hook_emit_context "SessionStart" "$OUT" hook_emit_pass - hooks/dispatch-stop.shRunsGitHub
Read the script
#!/bin/bash # Vibe Dev v6.2 — ЕДИНЫЙ Stop dispatcher (F3). На событии Stop живёт несколько сторожей — # без единой точки они каскадят блоки и зацикливают ход. Здесь: приоритеты + общий cap. # # Приоритеты (один block за раз; после доделки Stop сработает снова и проверит заново): # 1. stop-intent (H19): обещал действие, не сделал -> заставить ДОДЕЛАТЬ (block). # 2. clarity-gate (F4): сообщение непонятно пользователю -> короткий аддендум (block). # 3. (v6.3, слот) wave-continue: прогон утверждённого блока фич. Пререквизит — passthrough # вопросов: ход с вопросом пользователю wave НЕ продолжает (HALT, не давим вопрос). # # Общий cap: ≤3 block на цепочку хода (свой, ниже системного cap 8). Цепочка = от промпта # пользователя до промпта (UserPromptSubmit-диспетчер сбрасывает счётчик). При переполнении — # pass с записью в .harness/stop-cap-log (видно /audit), НЕ бесконечная переписка. # # Активен standard,strict. Контракт Stop: decision:block / additionalContext (>=2.1.163). set -u DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" . "$DIR/lib/hook-io.sh" export VIBE_HOOK_EVENT="Stop" # для журнала срабатываний (v9 F0.1) hook_read_stdin CWD="$(hook_field '.cwd')" [ -z "$CWD" ] && CWD="$PWD" # Guard: только vibe-target-проекты. hook_is_vibe_project "$CWD" || hook_emit_pass PROFILE="$(hook_profile "$CWD")" ROOT="$(hook_plugin_root)" # Активен только в standard,strict. profile_in "standard,strict" "$PROFILE" || hook_emit_pass # --- Общий cap цепочки Stop-блоков --- CHAIN_FILE="$CWD/.harness/stop-chain-count" CHAIN=0 if [ -f "$CHAIN_FILE" ]; then CHAIN="$(tr -dc '0-9' < "$CHAIN_FILE" 2>/dev/null)" CHAIN="${CHAIN:-0}" fi # emit_capped_block <reason> — block с учётом общего cap (3 на цепочку хода). emit_capped_block() { if [ "$CHAIN" -ge 3 ]; then mkdir -p "$CWD/.harness" 2>/dev/null printf '%s\tcap-pass\t%s\n' "$(date '+%Y-%m-%d %H:%M' 2>/dev/null || echo '?')" "$1" \ >> "$CWD/.harness/stop-cap-log" 2>/dev/null hook_emit_pass fi mkdir -p "$CWD/.harness" 2>/dev/null printf '%s\n' "$((CHAIN + 1))" > "$CHAIN_FILE" 2>/dev/null hook_emit_stop_block "$1" } WARNS="" # --- Приоритет 1: stop-intent (H19) — обещание действия без tool_use --- # hook_run_check (fail-loud): краш проверки -> WARN-строка + crash-артефакт. VERDICT="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "stop-intent" verdict "$ROOT/hooks/checks/stop-intent-without-action.sh" "$CWD")" BLOCK_MSG="$(printf '%s' "$VERDICT" | awk -F'\t' '$1=="BLOCK"{print $2; exit}')" if [ -n "$BLOCK_MSG" ]; then emit_capped_block "Vibe Dev (профиль ${PROFILE}): ${BLOCK_MSG}" fi W="$(printf '%s' "$VERDICT" | awk -F'\t' '$1=="WARN"{print $2; exit}')" [ -n "$W" ] && WARNS="$W" # --- Приоритет 2: clarity-gate (F4) — ясность финального сообщения --- # Боль №1 аудита: жаргон / развилки без рекомендации / человеко-дни доходили до пользователя. # BLOCK -> агент дописывает короткий аддендум (не переписывает всё). Tiered по precision. CL_VERDICT="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "clarity-gate" verdict "$ROOT/hooks/checks/clarity-stop-gate.sh" "$CWD" "$PROFILE")" CL_BLOCK="$(printf '%s' "$CL_VERDICT" | awk -F'\t' '$1=="BLOCK"{print $2; exit}')" if [ -n "$CL_BLOCK" ]; then emit_capped_block "Vibe Dev (clarity-gate, профиль ${PROFILE}): ${CL_BLOCK}" fi CW="$(printf '%s' "$CL_VERDICT" | awk -F'\t' '$1=="WARN"{print $2; exit}')" if [ -n "$CW" ]; then if [ -n "$WARNS" ]; then WARNS="$WARNS $CW"; else WARNS="$CW"; fi fi # --- Приоритет 3 (v7 P6): wave-continue — в go-режиме ход кончился вопросом -> gentle inject. --- # Только warn/inject (не block, не capped-block): вопрос не давим (passthrough бизнес-развилок). # Не запускается, если приоритет 1/2 уже сделал block (emit_capped_block выходит из скрипта). WC_VERDICT="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "wave-continue" verdict "$ROOT/hooks/checks/wave-continue.sh" "$CWD")" WCW="$(printf '%s' "$WC_VERDICT" | awk -F'\t' '$1=="WARN"{print $2; exit}')" if [ -n "$WCW" ]; then if [ -n "$WARNS" ]; then WARNS="$WARNS $WCW"; else WARNS="$WCW"; fi fi # WARN'ы (например, краш проверки) -> мягкий additionalContext (>=2.1.163; старые движки игнорируют). if [ -n "$WARNS" ]; then hook_emit_stop_context "Vibe Dev: ${WARNS}" fi hook_emit_pass - hooks/dispatch-user-prompt.shRunsGitHub
Read the script
#!/bin/bash # Vibe Dev v6 — UserPromptSubmit dispatcher (точка входа на событие UserPromptSubmit). H6. # # Поток: stdin JSON -> guard (vibe-проект?) -> профиль -> handoff-reminder # -> inject additionalContext (cold-start чеклист) или тихий pass. # # handoff-reminder — warn-уровень (inject, НЕ block): промпт пользователя легитимен, # блокировать его нельзя; напоминание видно модели. Активен standard,strict; minimal — off. # Контракт UserPromptSubmit: docs/hooks-contract-verified-2026-06-03.md §4 (stdout как контекст). set -u DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" . "$DIR/lib/hook-io.sh" export VIBE_HOOK_EVENT="UserPromptSubmit" # для журнала срабатываний (v9 F0.1) hook_read_stdin CWD="$(hook_field '.cwd')" [ -z "$CWD" ] && CWD="$PWD" # Guard: только vibe-target-проекты. hook_is_vibe_project "$CWD" || hook_emit_pass # Активация (v6.2 F2): heartbeat «хуки живы» + перевод pending-профиля в боевой. # UserPromptSubmit срабатывает каждое сообщение -> bootstrap активируется без рестарта. hook_write_heartbeat "$CWD" ACTIVATED="$(hook_activate_pending_profile "$CWD")" # Новый промпт пользователя = новая цепочка хода: сброс общего cap Stop-блоков (F3) # и счётчика дописок clarity-gate (F4). rm -f "$CWD/.harness/stop-chain-count" "$CWD/.harness/clarity-stop-count" 2>/dev/null PROFILE="$(hook_profile "$CWD")" ROOT="$(hook_plugin_root)" # Активен только в standard,strict. if ! profile_in "standard,strict" "$PROFILE"; then [ -n "$ACTIVATED" ] && hook_emit_context "UserPromptSubmit" "✅ Vibe Dev: enforcement активирован живым хуком — профиль «${ACTIVATED}» подтверждён." hook_emit_pass fi PIECES="" [ -n "$ACTIVATED" ] && PIECES="✅ Vibe Dev: enforcement активирован живым хуком — профиль «${ACTIVATED}» подтверждён (скажи пользователю одной строкой)." # H6: сигнал завершения сессии -> cold-start чеклист + маркер handoff-pending. # hook_run_check (fail-loud): краш проверки -> абзац-предупреждение + crash-артефакт. HANDOFF="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "handoff-reminder" text "$ROOT/hooks/checks/handoff-reminder.sh" "$CWD")" if [ -n "$(printf '%s' "$HANDOFF" | tr -d '[:space:]')" ]; then case "$HANDOFF" in "⚠️ сторож"*) # Проверка УПАЛА, не успев ничего решить — это НЕ сигнал завершения: маркеры не ставим, # но предупреждение о краше доносим. ;; *) # Маркер для SessionStart-probe (loop H6): следующий старт проверит, обновился ли # SESSION.md после этого сигнала. Если нет — handoff мог не записаться -> warn. mkdir -p "$CWD/.harness/locks" 2>/dev/null : > "$CWD/.harness/handoff-pending" 2>/dev/null # closing-mode (F7, П6): на время закрытия — деградация прав (PreToolUse-гейт: # запись только в state-файлы, Bash только git/read-only). Снимется следующим # промптом без сигнала завершения (ветка else ниже). : > "$CWD/.harness/locks/closing-mode" 2>/dev/null ;; esac if [ -n "$PIECES" ]; then PIECES="$PIECES — $HANDOFF" else PIECES="$HANDOFF" fi else # Промпт БЕЗ сигнала завершения: пользователь продолжает работу — режим закрытия снят # (его инструкция главнее; закрывает FP «на сегодня всё… хотя нет, поправь ещё кнопку»). rm -f "$CWD/.harness/locks/closing-mode" 2>/dev/null fi # interrupt-recovery (v6.2.1): хвост последнего хода оборван техническим прерыванием # (обрыв клиента/доставка сообщения), в новом промпте нет стоп-слов -> inject «продолжай, # это был обрыв, не запрет» (агент не стоит часами после лживого "user rejected"). IRECOV="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "interrupt-recovery" text "$ROOT/hooks/checks/interrupt-recovery.sh" "$CWD")" if [ -n "$(printf '%s' "$IRECOV" | tr -d '[:space:]')" ]; then if [ -n "$PIECES" ]; then PIECES="$PIECES — $IRECOV" else PIECES="$IRECOV" fi fi # Анти-залипание (прокси №1 tunnel-vision): стоп-сигнал / коррекция курса -> напоминание # (смена УРОВНЯ, не способа). Маркер handoff НЕ ставит — это не завершение сессии. STUCK="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "stuck-signal" text "$ROOT/hooks/checks/stuck-signal-reminder.sh" "$CWD")" # research-skip (F6, lock-паттерн): явная фраза «пропусти рисёрч» -> хук (не агент!) пишет # маркер .harness/locks/research-skipped с цитатой; гейт архитектуры его уважает. RSKIP="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "research-skip" text "$ROOT/hooks/checks/research-skip-listener.sh" "$CWD")" if [ -n "$(printf '%s' "$RSKIP" | tr -d '[:space:]')" ]; then if [ -n "$PIECES" ]; then PIECES="$PIECES — $RSKIP" else PIECES="$RSKIP" fi fi # secret-skip (v7 P14 escape, lock-паттерн): явная фраза «ключ тестовый / забей» -> хук (не агент!) # пишет одноразовый маркер .harness/locks/secret-scan-off; secret-scan-write снимает по нему блок. SSKIP="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "secret-skip" text "$ROOT/hooks/checks/secret-skip-listener.sh" "$CWD")" if [ -n "$(printf '%s' "$SSKIP" | tr -d '[:space:]')" ]; then if [ -n "$PIECES" ]; then PIECES="$PIECES — $SSKIP" else PIECES="$SSKIP" fi fi # go-mode (v7 P6): явная фраза «не тормози / делай до конца» -> хук ставит .harness/locks/go-mode # (стоп-слово снимает). wave-continue на Stop читает маркер. Тихо (только маркер, без текста). HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "go-mode" text "$ROOT/hooks/checks/go-mode-listener.sh" "$CWD" >/dev/null 2>&1 # secret-in-prompt (F8): живой ключ в сообщении пользователя -> предупреждение о ротации # (inject, не block: ключ уже в контексте — задача предупредить и направить в .env). SECR="$(HOOK_PAYLOAD="$HOOK_INPUT" hook_run_check "$CWD" "secret-in-prompt" text "$ROOT/hooks/checks/secret-in-prompt.sh" "$CWD")" if [ -n "$(printf '%s' "$SECR" | tr -d '[:space:]')" ]; then if [ -n "$PIECES" ]; then PIECES="$PIECES — $SECR" else PIECES="$SECR" fi fi if [ -n "$(printf '%s' "$STUCK" | tr -d '[:space:]')" ]; then if [ -n "$PIECES" ]; then PIECES="$PIECES — $STUCK" else PIECES="$STUC - hooks/pre-commit-scope.shGitHub
- hooks/pre-compact.shRunsGitHub
All 8 scripts are listed above. The source is inlined for 6 of them, starting with whatever hooks.json actually runs. See all of them in the repo.
Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.
🌐 English: this file · Русский: README.ru.md A harness-first plugin that turns a business idea into a shipped product — for founders who build with Codex and Claude Code.
Repo: andrewcigan/vibe-dev-plugin

