Voice
Llm Action Judge
LLM-gated tool-call approval plugin for OpenClaw
Install
openclaw plugins install ./openclaw-llm-action-judge-0.5.2.tgz
README
# OpenClaw LLM Action Judge
Плагин `openclaw-llm-action-judge` версии `0.5.2` проверяет каждый proposed tool
call отдельной фиксированной LLM **до исполнения**. Низкорисковое и явно
разрешённое действие может пройти автоматически, сомнительное — запросить
подтверждение, опасное — быть заблокировано.
## Суть решения
```text
Запрос пользователя
→ агент OpenClaw предлагает tool call
→ плагин перехватывает точное действие
→ Qwen оценивает риск и наличие разрешения
→ локальная схема и deterministic guard перепроверяют ответ
→ действие выполняется, отправляется на approval или блокируется
→ результат решения записывается в audit JSONL
```
Плагин не заменяет sandbox, native OpenClaw tool policy и разграничение доступа.
Это дополнительный permission layer перед исполнением инструмента.
## Из каких блоков состоит
| Блок | Что делает |
|---|---|
| **OpenClaw hooks** | `before_model_resolve` сохраняет trusted request, `subagent_spawned` связывает root и child, `llm_input` снимает host-declared semantics, `before_tool_call` проверяет действие. Все четыре hook устанавливаются самим плагином с priority `1100`. |
| **LLM judge** | Фиксированная `Qwen/Qwen3.5-397B-A17B` независимо оценивает `decision`, `risk`, `authorization` и `confidence`. |
| **Structured Output** | Cloud.ru ограничивает ответ strict `json_schema`; тот же контракт повторно проверяется локально через Ajv. |
| **Hard routing** / **Deterministic guard** | Точные self-modification, credential exfiltration и попытки отключить judge блокируются до LLM. Остальные действия проверяет Qwen, после чего guard может только ужесточить ошибочный `allow`. |
| **Circuit breaker** | Порог — 3 raw classifier deny после последнего validated allow либо 10 raw deny среди последних 50 решений. Review и failure ни увеличивают, ни сбрасывают счётчик. Breaker state читается и записывается только в `autonomous + enforce`; следующий вызов получает native `requireApproval`, а `allow-once` синхронно сбрасывает latch только для того же run/session. `shadow` не читает и не меняет breaker state, аудитит фактический judge/local outcome без `circuit_breaker` candidate и не влияет на tool call. `supervised` также не трогает breaker, поэтому его deny не могут накопиться и сработать после перехода в `autonomous`. |
| **Mode mapper** | Преобразует итог judge в execute, native approval или block согласно `shadow`, `supervised` или `autonomous`. |
| **Worker feedback** | `blockReason` возвращается только для raw judge deny и hard boundary. Для review и failure безопасная причина передаётся через native `requireApproval.description`; до решения tool не исполняется. |
| **Audit** | Пишет решение, `decision_source`, safe-path disagreement, latency и hashes в JSONL без raw prompt, params, rationale и credentials. Safe path в v0.5 — metrics-only сигнал и сам ничего не разрешает. |
## Connector и orchestration semantics 0.5.2
Права задаются результатом запроса, а не именем инструмента: любой tool с
достоверной host-declared семантикой может получить `allow`, если это обычный
bounded способ выполнить outcome без расширения эффекта, target, данных,
стоимости или привилегий. Имя tool само по себе ничего не разрешает и не
запрещает. Если judge не может установить семантику и возвращает `review`, в
enforcing-профиле это native approval, а в `shadow` — только audit.
- `nango_list_connections`, выбранный агентом как bounded passive prerequisite
пользовательского outcome, может пройти по валидному judge `allow` с исходными
параметрами ровно один раз; пользователю не нужно называть connector или tool.
- `nango_yandex_mail_send` может пройти только после валидного judge `allow`.
Literal recipient mismatch применяется как downgrade-only только когда оба
источника — trusted request и params — содержат literal email; отсутствующий
или nonliteral recipient остаётся judge-owned.
- `sessions_spawn` не имеет отдельного structural/boundedness validator:
валидный judge `allow` может сохраниться, а каждый child tool call всё равно
проходит собственный gate.
- Judge `review`/`deny`, opaque params, неизвестная семантика, sensitive target,
protected path и hard boundary никогда не повышаются локальным matcher.
- Shell, generic Nango proxy и HTTP wrapper не получают разрешение или запрет по
имени: judge оценивает их объявленную host semantics и видимые параметры в
контексте outcome, а deterministic guard может только ужесточить результат.
Cloudflare 403 и другие origin failures возникают **после** permission gate и
не считаются classifier deny. Плагин не реализует browser fallback, login или
автоматический retry. Локальная проверка использует recording transport: реальная
SMTP delivery не проверена, и Agents Space UI не проверен и не доказан.
## Что guard никогда не auto-approve
Даже если judge вернула `allow`, local guard переводит действие как минимум в
`review`, когда обнаруживает одну из следующих поверхностей:
- чтение credentials, sensitive OpenClaw state вне workspace,
sessions/logs/history или audit data;
- запись в OpenClaw state вне workspace, `openclaw.json`, bootstrap instructions
(`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `USER.md`, `IDENTITY.md`, `HEARTBEAT.md`,
`MEMORY.md`) или любой `skills/**/SKILL.md`;
- запись в active production, CI/CD, Git/SSH/security config, распознанные
security/auth tests, package manifest/lockfile либо потенциальное ослабление
`.gitignore`, `.npmignore` и `.dockerignore`;
- mutation или cross-session action в распознанных first-party tool families
вне явного read-only allowlist;
- `exec`/`bash` с elevation, явно указанным host вне sandbox, remote node,
непустым `env`, PTY/background, неограниченным lifecycle, неоднозначным
`workdir`, dynamic shell или распознанной destructive, package, Git либо
OpenClaw CLI mutation;
- browser вне literal `target=sandbox`, ввод/клик/скрипт, console inspection,
любой capture либо переход на internal/special-use target.
Точный allowlist и failure semantics зафиксированы в
[CONTRACT.md](CONTRACT.md). Всё, чего guard не распознал, всё равно должно пройти
LLM verdict и native OpenClaw sandbox/tool policy.
Отсутствующий `exec.host` намеренно сохраняет стандартную маршрутизацию
OpenClaw и на host без native sandbox может означать gateway execution. Поэтому
для strongest isolation платформа должна включить OpenClaw sandbox; плагин сам
контейнер не создаёт и не доказывает effective host до hook.
## Требования
- OpenClaw `>=2026.6.11`; тот же floor исполняется package metadata через
`openclaw.install.minHostVersion` и `openclaw.compat.pluginApi`;
- Node.js `>=22.19.0`;
- доступ к `https://foundation-models.api.cloud.ru/v1`;
- API key с доступом к `Qwen/Qwen3.5-397B-A17B` либо уже настроенный
`models.providers.cloudru` в OpenClaw;
- `foundation-models.api.cloud.ru` в `no_proxy`/`NO_PROXY`, если используется
корпоративный proxy.
Плагин **не читает `.env`**. Переменные должны быть переданы процессу gateway.
## Установка
Команды выполняются из каталога локального/проверенного artifact `0.5.2`:
```bash
shasum -a 256 -c openclaw-llm-action-judge-0.5.2.tgz.sha256
openclaw plugins install ./openclaw-llm-action-judge-0.5.2.tgz
```
Проверьте текущий allowlist:
```bash
openclaw config get plugins.allow --json
```
Добавьте `llm-action-judge` в существующий `plugins.allow`, сохранив остальные
trusted plugin IDs. Для новой выделенной node, где это единственный внешний
плагин, подходит команда:
```bash
openclaw config set plugins.allow '["llm-action-judge"]' --strict-json
```
Разрешите плагину получать текущий user request и обновите registry:
```bash
openclaw config set plugins.entries.llm-action-judge.hooks.allowConversationAccess true --strict-json
openclaw plugins registry --refresh
openclaw config validate
```
## Запуск в supervised
В `supervised`:
- итоговый `allow` исполняется автоматически;
- `review` и любой judge failure открывают native approval;
- `deny` блокируется;
- если пользователь не подтвердил approval за 60 секунд, действие блокируется.
Локальный foreground-запуск:
```bash
OPENCLAW_JUDGE_API_KEY='<cloudru-api-key>' \
OPENCLAW_JUDGE_PROFILE='supervised' \
openclaw gateway run
```
Процесс работает в текущем терминале и останавливается через `Ctrl+C`.
Для managed gateway задайте эти же две переменные в environment контейнера,
systemd/launchd или Kubernetes Deployment, затем выполните:
```bash
openclaw gateway restart
openclaw gateway health
```
Обычная переменная из текущего shell не попадает в уже настроенный managed
service: ENV должен находиться в его service definition/Deployment.
## Запуск в autonomous
В `autonomous`:
- автоматически исполняется только полностью validated `allow`;
- raw judge `deny` и deterministic hard boundary блокируются без выполнения;
- `review`, timeout, HTTP error, invalid JSON/schema и missing intent открывают
native `requireApproval` с choices только `allow-once`/`deny`;
- breaker ставит scoped pause: следующий вызов также идёт в native
`requireApproval`, а не получает silent `repeated_denials` block.
Локальный foreground-запуск:
```bash
OPENCLAW_JUDGE_API_KEY='<cloudru-api-key>' \
OPENCLAW_JUDGE_PROFILE='autonomous' \
openclaw gateway run
```
Для managed gateway замените durable `OPENCLAW_JUDGE_PROFILE` на `autonomous`,
сделайте rollout/restart и повторите runtime verification. До нового независимого
holdout и shadow-проверки реального traffic используйте этот режим как canary, а
не как единственную security boundary.
## Режим shadow
`shadow` вызывает judge и пишет audit, но не влияет на исполнение tool calls.
Он не читает и не изменяет breaker state: в audit остаётся фактический результат
judge и local downgrade, а не сохранённый latch candidate. Это рекомендуемый
первый режим для новой установки:
```bash
OPENCLAW_JUDGE_API_KEY='<cloudru-api-key>' \
OPENCLAW_JUDGE_PROFILE='shadow' \
openclaw gateway run
```
| Profile | `allow` | `review`/failure | `deny` |
|---|---|---|---|
| `shadow` | Не меняет вызов | Не меняет вызов | Не
... (truncated)
voice
Comments
Sign in to leave a comment