From vassal-litigator
Единый контракт вызова Codex CLI для vassal-litigator. Используй этот скилл, когда любой другой скилл плагина должен диспатчить задачу в Codex: файловый apply на medium, таймлайн на high, визуализацию через image_gen, контрольное ревью на xhigh. Содержит точные команды, monitor-polling, stale-lock workaround, контракт путей [PLUGIN_ROOT] / [CASE_ROOT] и резолв generated image path через sessionId.
npx claudepluginhub strigov/vassal-litigatorThis skill uses the workspace's default tool permissions.
Этот скилл описывает, **как Claude-main вызывает Codex** для ролей плагина vassal-litigator. Он не заменяет профильные скиллы (`intake`, `timeline`, `legal-review` и т.д.), а задаёт общий транспорт, флаги, правила резолвинга путей и отчётности.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Automates semantic versioning and release workflow for Claude Code plugins: bumps versions in package.json, marketplace.json, plugin.json; verifies builds; creates git tags, GitHub releases, changelogs.
Этот скилл описывает, как Claude-main вызывает Codex для ролей плагина vassal-litigator. Он не заменяет профильные скиллы (intake, timeline, legal-review и т.д.), а задаёт общий транспорт, флаги, правила резолвинга путей и отчётности.
Используй этот скилл, если задача требует одного из четырёх Codex-ролей плагина:
file-executor — файловый apply-пайплайн, medium, с --writetimeline-builder — сборка хронологии, high, с --writeimagegen-visualizer — sidecar-визуализация через image_gen, mediumanalytical-reviewer — контрольное ревью аналитики, xhigh, без --writeЕсли это первый вызов Codex на машине юриста, сначала нужен логин:
!codex login
Если логин уже делался, повторять не нужно.
Hardcoded path для companion в v0.5.0:
~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs
Проверка:
node ~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs task --help
Если получаешь ENOENT, почти всегда причина в том, что openai-codex обновился и версия в пути больше не совпадает. В v0.5.0 путь правится здесь, в одном месте.
Для основного Branch A у роли imagegen-visualizer юрист должен один раз включить feature:
codex features enable image_generation
Это включает features.image_generation = true в ~/.codex/config.toml. Если юрист не хочет включать feature глобально, используй Branch B из раздела про визуализатор.
Во всех командах ниже:
[CASE_ROOT] — абсолютный путь к папке дела<PROMPT> — уже отрендеренный промпт, где Claude-main заменил [PLUGIN_ROOT] и [CASE_ROOT] на абсолютные пути1.0.3file-executor — medium, apply, --writenode ~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs task \
--background \
--write \
--effort medium \
"<PROMPT>"
Используется для:
file-executor-intakefile-executor-update-indexfile-executor-catalogfile-executor-add-evidencefile-executor-add-opponenttimeline-builder — high, apply, --writenode ~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs task \
--background \
--write \
--effort high \
"<PROMPT>"
analytical-reviewer — xhigh, read-onlynode ~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs task \
--background \
--effort xhigh \
"<PROMPT>"
Для ревьюера --write не передаётся.
imagegen-visualizer — два branch-вариантаnode ~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs task \
--background \
--write \
--effort medium \
"<PROMPT с вызовом image_gen>"
Когда использовать:
image_generation уже включён у юристаcodex execcodex exec \
--skip-git-repo-check \
--sandbox workspace-write \
--enable image_generation \
-C "[CASE_ROOT]" \
-c model_reasoning_effort=medium \
"<PROMPT с вызовом image_gen>"
Когда использовать:
image_generation глобально--enable image_generationДля file-executor, timeline-builder, analytical-reviewer и Branch A визуализатора используй один и тот же шаблон. case-guard обязателен: без него poll-loop заспамит вывод.
COMPANION=~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs
TASK=task-XXXX
until
st=$(node "$COMPANION" status "$TASK" --json 2>/dev/null \
| python3 -c "import json,sys; print(json.load(sys.stdin)['job']['status'])")
case "$st" in
completed|failed|cancelled) echo "codex task terminal: $st"; true ;;
*) false ;;
esac
do
sleep 25
done
После терминального статуса:
node "$COMPANION" result "$TASK"
Если нужен sessionId, бери JSON:
node "$COMPANION" status "$TASK" --json
--resume-last, stale-lock и --freshОбычный паттерн follow-up:
node ~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs task \
--background \
--write \
--effort medium \
--resume-last \
"<PROMPT>"
Если предыдущий запуск оборвался и companion считает сессию «ещё running», --resume-last может зависнуть на stale-lock. В этом случае workaround только один:
node ~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs task \
--background \
--write \
--effort medium \
--fresh \
"<PROMPT>"
Правило:
--resume-last--fresh[PLUGIN_ROOT] и [CASE_ROOT]Это критичный инвариант v0.5.0.
[CASE_ROOT] — абсолютный путь к папке дела; это cwd Codex-процесса[PLUGIN_ROOT] — абсолютный путь к установленному плагину vassal-litigatorИз-за того, что cwd = [CASE_ROOT], относительные пути scripts/... и shared/... запрещены. Все обращения к файлам плагина делаются только так:
[PLUGIN_ROOT]/scripts/extract_text.py[PLUGIN_ROOT]/scripts/generate_table.py[PLUGIN_ROOT]/scripts/setup.sh[PLUGIN_ROOT]/shared/conventions.md[PLUGIN_ROOT]/shared/case-schema.yaml[PLUGIN_ROOT]/shared/index-schema.yaml[PLUGIN_ROOT]/shared/mirror-template.md[CASE_ROOT]Базовый вариант:
CASE_ROOT="$(pwd)"
Это должен быть корень конкретного дела, а не корень плагина.
[PLUGIN_ROOT] — 3-tier fallbackCLAUDE_PLUGIN_ROOT в main-session обычно не существует, поэтому нужен жёстко задокументированный fallback.
CLAUDE_PLUGIN_ROOT, если уже выставленаif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -d "$CLAUDE_PLUGIN_ROOT" ]; then
PLUGIN_ROOT="$CLAUDE_PLUGIN_ROOT"
fi
~/.claude/plugins/installed_plugins.jsonЭто основной путь для production-установки.
if [ -z "${PLUGIN_ROOT:-}" ]; then
PLUGIN_ROOT="$(python3 - <<'PY'
import json
import os
import sys
path = os.path.expanduser('~/.claude/plugins/installed_plugins.json')
try:
with open(path, 'r', encoding='utf-8') as fh:
data = json.load(fh)
except FileNotFoundError:
sys.exit(0)
plugins = data.get('plugins', {})
for key, entries in plugins.items():
if not key.startswith('vassal-litigator@'):
continue
for entry in entries:
install_path = entry.get('installPath')
if install_path:
install_path = os.path.expanduser(install_path)
if os.path.isdir(install_path):
print(install_path)
raise SystemExit(0)
PY
)"
fi
Если ни env, ни installed_plugins.json не дали путь, первый вызов в сессии должен остановиться с вопросом:
укажи абсолютный путь к плагину vassal-litigator
После ответа:
skills/, shared/, scripts/Пример простого session-cache в shell:
if [ -n "${VASSAL_PLUGIN_ROOT_CACHE:-}" ] && [ -d "$VASSAL_PLUGIN_ROOT_CACHE" ]; then
PLUGIN_ROOT="$VASSAL_PLUGIN_ROOT_CACHE"
fi
Если кеш пуст:
VASSAL_PLUGIN_ROOT_CACHE="$PLUGIN_ROOT"
export VASSAL_PLUGIN_ROOT_CACHE
Перед первым dispatch в сессии проверь:
test -f "$PLUGIN_ROOT/scripts/extract_text.py"
test -f "$PLUGIN_ROOT/shared/conventions.md"
test -d "$CASE_ROOT"
Если любой тест падает, не запускай Codex. Сначала NEEDS_CONTEXT.
Оркестратор делает prompt-assembly step до диспатча, а не рассчитывает, что Codex сам что-то резолвит.
Формальный алгоритм:
PLUGIN_ROOT и CASE_ROOT.{{include _preamble.md}}, expand include буквальной подстановкой содержимого prompts/_preamble.md на место этой директивы.[PLUGIN_ROOT], [CASE_ROOT], {{case_root}}, {{plugin_root}} и остальные {{...}} placeholders конкретной роли.{{include ...}} и прочих {{...}}.companion.mjs task или codex exec.Минимальный пример:
PROMPT_TEMPLATE="$PLUGIN_ROOT/prompts/timeline-builder.md"
PROMPT="$(cat "$PROMPT_TEMPLATE")"
PREAMBLE="$(cat "$PLUGIN_ROOT/prompts/_preamble.md")"
PROMPT="${PROMPT/\{\{include _preamble.md\}\}/$PREAMBLE}"
PROMPT="${PROMPT//\{\{case_root\}\}/$CASE_ROOT}"
PROMPT="${PROMPT//\{\{plugin_root\}\}/$PLUGIN_ROOT}"
Гарантийный check перед dispatch:
ASSEMBLED_PROMPT_FILE="/tmp/vassal-codex-prompt.txt"
printf '%s\n' "$PROMPT" > "$ASSEMBLED_PROMPT_FILE"
grep -n '{{' "$ASSEMBLED_PROMPT_FILE" && echo "UNRESOLVED_TEMPLATE_TOKENS"
grep -n '\[PLUGIN_ROOT\]\|\[CASE_ROOT\]' "$ASSEMBLED_PROMPT_FILE" && echo "UNRESOLVED_PATH_TOKENS"
Ожидание:
grep -n '{{' <assembled-prompt> возвращает 0 совпаденийgrep -n '\[PLUGIN_ROOT\]\|\[CASE_ROOT\]' <assembled-prompt> возвращает 0 совпаденийЖёсткое правило:
{{include _preamble.md}}, [PLUGIN_ROOT], [CASE_ROOT], {{case_root}}, {{plugin_root}} и любые другие {{...}}NEEDS_CONTEXT, а не «попробую с относительным путём»После каждого значимого Codex-dispatch Claude-main сохраняет итоговый отчёт в:
[CASE_ROOT]/.vassal/codex-logs/{ГГГГ-ММ-ДД-ЧЧмм}-{role}.md
Это делается для финального результата конкретного dispatch, а не для каждого промежуточного poll.
Минимальный состав лога:
task_idroleeffortprompt_size_bytesstdoutstderrtaken_msfinal_statusЕсли dispatch не стартовал вовсе, лог всё равно желательно сохранить как локальный failure-report с причиной.
Если Codex недоступен (network down, OpenAI rate limit, companion broker не отвечает, status=failed, timeout, NEEDS_CONTEXT до старта), Claude-main не должен молча зависать.
Правило по ролям:
file-executor-*) — откат на Claude-native исполнение по логике v0.4.0, с явным предупреждением Сюзерену, что Codex-path временно недоступенtimeline-builder — skip по умолчанию; если позже отдельный skill явно задокументирует Claude-native fallback, использовать его, иначе честно вернуть, что таймлайн не собранimagegen-visualizer — skip: визуализация не создаётся, дело продолжается без sidecar-картинкиanalytical-reviewer — skip: показать Сюзерену, что контрольное ревью Codex не проведеноВо всех случаях:
.vassal/codex-logs/Это место обновлено по Q1 AMENDED. Нельзя опираться на строку GENERATED_IMAGE: <abs_path> в stdout, потому что эмпирически Codex её не печатает стабильно.
sessionId.CODEX_HOME как ${CODEX_HOME:-$HOME/.codex}.$CODEX_HOME/generated_images/<sessionId>/ig_*.png
mtime.[CASE_ROOT]/.vassal/visuals/...; исходник в $CODEX_HOME/generated_images/... не трогает.sessionIdЧерез companion status/result JSON:
node ~/.claude/plugins/cache/openai-codex/codex/1.0.3/scripts/codex-companion.mjs status "$TASK" --json \
| python3 -c "import json,sys; print(json.load(sys.stdin)['job']['sessionId'])"
sessionIdПрямой codex exec печатает session id: <UUID> в stderr/stdout. Парсинг делается оркестратором по этой строке.
CODEX_HOME_RESOLVED="${CODEX_HOME:-$HOME/.codex}"
SESSION_ID="<полученный sessionId>"
IMAGE_PATH="$(find "$CODEX_HOME_RESOLVED/generated_images/$SESSION_ID" -maxdepth 1 -type f -name 'ig_*.png' -print \
| xargs ls -t 2>/dev/null | head -n 1)"
Если IMAGE_PATH пустой, это BLOCKED: не пытайся выдумывать путь, не проси Codex «сохранить ещё раз по нужному месту», не пиши в .vassal/visuals/ напрямую из imagegen-подзадачи.
--backgroundscripts/... и shared/...--write для analytical-reviewer$imagegen сам сохранит файл по пути из промптаGENERATED_IMAGE: гарантированным интерфейсом--fresh, если stale-lock уже проявилсяЭтот скилл не задаёт содержание профильного ответа роли, но задаёт транспортный контракт:
[CASE_ROOT]1.0.3, пока Ф7 не внесёт следующую миграциюsessionId + $CODEX_HOME/generated_images/...