Files
skills/README.md
T
devandClaude Opus 5 bf67366792 Say which ctxguard path each install layout uses
The examples assumed a repository checkout. A reader who installed from the skill
registry has `plugin/scripts/ctxguard.py` at the archive root instead -- singular,
and without the `plugins/ctxguard/` prefix, because the archive holds exactly one
plugin. Following the examples verbatim gave them "No such file or directory" on the
first command.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 11:41:33 +03:00

26 KiB
Raw Blame History

ctx-tools — как пользоваться

Маркетплейс плагинов для Claude Code. Сейчас в нём один плагин:

ctxguard — санитизация контекста: вырезает креденшлы, подменяет имена компаний, людей и PII на стабильные обратимые алиасы до того, как они попадут в модель. Принуждение живёт в хуках, поэтому агент не может это выключить.

Этот файл — про то, как этим пользоваться. Раздача плагина коллегам и процесс релизов — в README.en.md.


Установка

Вариант 1. Через маркетплейс (рекомендуется)

/plugin marketplace add /path/to/skills
/plugin install ctxguard@ctx-tools

Вместо локального пути можно указать <owner>/<repo> на GitHub, git-URL или любой путь в файловой системе. Ничего не тянется из сети во время работы, зависимостей кроме python3 нет.

Для всей команды — объявить на уровне проекта и закоммитить результат, чтобы клонирования репозитория было достаточно:

claude plugin marketplace add <owner>/<repo> --scope project
claude plugin install ctxguard@ctx-tools --scope project

Вариант 2. Копированием папки

cp -r plugins/ctxguard ~/.claude/skills/ctxguard

Загрузится в следующей сессии как ctxguard@skills-dir, вместе с хуками. Два нюанса:

  • Имя должно быть свободно. Установленный плагин с тем же именем побеждает, и просто отключить его недостаточно — имя остаётся занятым до claude plugin uninstall.
  • Копируйте каталог, а не симлинк на репозиторий, который потом переедет.

Этот способ — для одной машины или одного коллеги. Маркетплейс — когда одну и ту же версию нужно раздать нескольким людям и обновление должно быть командой, а не перекопированием.


ctxguard: повседневное использование

Ниже ctxguard — сокращение для вызова скрипта. Сам путь зависит от того, как инструмент установлен, и это первое, обо что спотыкаются:

Откуда запускаете Путь к скрипту
Клон этого репозитория python3 plugins/ctxguard/scripts/ctxguard.py
Распакованный ZIP из реестра скиллов python3 plugin/scripts/ctxguard.py
Внутри сессии Claude Code python3 "${CLAUDE_PLUGIN_ROOT}/scripts/ctxguard.py"

В ZIP-поставке каталог называется plugin в единственном числе и лежит в корне архива — там нет промежуточного plugins/ctxguard/, потому что архив содержит ровно один плагин.

Удобно завести алиас под свой случай, например для распакованного архива:

alias ctxguard='python3 ~/.local/share/ctxguard/plugin/scripts/ctxguard.py'

Все примеры ниже записаны через это сокращение, подставьте свой путь.

Что он делает

  • Креденшлы удаляются безвозвратно — на их месте остаётся маркер вида SECRET:правило:хэш в угловых скобках. Восстановить значение нельзя, и это осознанно: отредактированный приватный ключ бесполезен.
  • Имена и PII превращаются в стабильные алиасы (CTXG_COMPANY_A, CTXG_PERSON_B, CTXG_EMAIL_7F3A) — и переводятся обратно в реальные значения по пути на диск и в шелл. Поэтому агент продолжает делать реальную работу: код и команды, ссылающиеся на алиасы, работают.
  • Принуждение живёт в хуках, а не в скилле. Агент не может это выключить, а то, что он забыл правила, безвредно — решение принимает хук.

Хуки: SessionStart, UserPromptSubmit, PreToolUse (перехват до запуска инструмента), PostToolUse (обратный перевод при записи), SessionEnd.

Первый запуск в новом проекте

ctxguard init            # создать состояние, показать что активно
ctxguard scan .          # что реально лежит в этом репозитории (только счётчики)
ctxguard entity add "Acme Corp" --type company --hint "розничный клиент"
ctxguard verify          # 43 канареечных кейса через настоящие точки входа хуков
ctxguard scan-transcript # что реально дошло до модели

Словарь стартует пустым. Детект креденшлов и PII работает сразу; имена компаний, людей и хостов защищены только после регистрации — поэтому scan, а затем entity add — первая работа в новом репозитории.

Словарь привязан к корню git-репозитория, а не к текущему каталогу, так что сессия, начатая в src/, использует тот же словарь.

Как выбрать --match — от этого зависит, скрывает ли алиас хоть что-то

Режим Когда Что ловит
exact (по умолчанию) имя встречается только в прозе целые слова, терпит гомоглифы (кириллическая с вместо латинской c) и разные разделители: Acme Corp / acme-corp / AcmeCorp
stem всё, что склоняется — в первую очередь русские фамилии плюс до четырёх символов окончания на слово: Петров / Петрова / Петровым. Перебирает по замыслу: Петров поймает и Петровский
ident любое имя, встречающееся в коде без границ слова, так что значение находится внутри идентификаторов: ContosoClient, CONTOSO_API_KEY, contoso.rs. С exact все три утекут в реальном написании, выглядя защищёнными. Нужно ≥4 символов
regex точная настройка используется как есть, без именованных групп

Побеждает самый длинный шаблон, так что регистрировать и Acme, и Acme Corporation безопасно.

Ещё два флага:

  • --hint вставляется в контекст модели буквально, поэтому описывайте сущность, не называя её («розничный клиент», а не «Globex — наш клиент»). Хинт, содержащий само значение, отвергается.
  • --variant (можно повторять) — дополнительные написания: транслитерации, аббревиатуры.

Если у значения несколько слов, а режим ident, — зарегистрируйте отдельно и отличительное слово: код обычно пишет GlobexClient для Globex Retail.

Слэш-команды в сессии

Команда Зачем
/ctx-entity <значение> [тип] Защитить название компании, человека, хост или кодовое имя за стабильным алиасом
/ctx-sanitize Превратить текст (тикет, лог, письмо) в версию с алиасами, которую можно куда-то вставить
/ctx-audit Показать, что ctxguard блокировал и подменял
/ctx-verify Доказать, что защита действительно блокирует заявленное, и измерить реальную утечку

Промпт нельзя перезаписать хуком — только заблокировать. Поэтому если ваш промпт отклонён, штатный путь — /ctx-sanitize на текст, ручная подстановка алиасов или регистрация значения через /ctx-entity.

CLI

Команда Что делает
ctxguard init [--force] создать каталог состояния и политику по умолчанию
ctxguard status режим, префикс алиасов, число сущностей, правил, записей аудита
ctxguard mode enforce|observe observe только логирует находки и ничего не блокирует — средство калибровки, не режим эксплуатации
ctxguard entity add <значение> --type <тип> [--match …] [--hint …] [--variant …] защитить значение. Типы: company, person, host, project, email, phone, custom
ctxguard entity list алиасы, типы, режимы совпадения, хинты — значения не печатаются никогда
ctxguard entity remove <алиас> снять защиту
ctxguard entity export --out <файл> выгрузить словарь для коллеги (откажется писать внутрь git-репозитория)
ctxguard entity import <файл> влить словарь, выгруженный на другой машине
ctxguard sanitize < <файл> stdin → текст с алиасами на stdout, сводка по правилам на stderr
ctxguard scan [путь…] какие файлы содержат чувствительные значения (только счётчики и id правил)
ctxguard scan-transcript [--limit N] [--verbose] [--all-projects] что реально дошло до модели
ctxguard audit -n 40 последние решения: id правил, имена инструментов, алиасы — без плейнтекста
ctxguard verify [--adversarial] канареечный корпус через настоящие точки входа хуков
ctxguard run -- <команда> выполнить команду с фильтрацией вывода

Ни одна подкоманда не печатает реальное значение сущности или секрета — именно это делает сам инструмент безопасным для запуска изнутри сессии агента.

Через Makefile

make test        # юнит-тесты движка
make verify      # канареечный корпус через настоящие точки входа хуков
make leaks       # поиск в транскриптах значений, которые реально дошли до модели
make scan        # чувствительные значения в этом репозитории (только счётчики)
make status      # что у ctxguard активно
make lint        # байт-компиляция всех скриптов + валидация JSON
make all         # lint + test + verify

Что видит агент — и что делать, когда вызов отклонён

Пять правил, которые агент получает в контекст:

  1. CTXG_* — алиасы реальных значений, использовать буквально.
  2. Никогда не восстанавливать реальное значение и не просить пользователя его вставить.
  3. Маркер секрета необратим; записывать его в файл нельзя — это затрёт настоящий креденшл заглушкой, и хук такую запись отклонит. Нужно целиться в более узкий участок через Edit.
  4. Некоторые пути ведут в санитизированный кэш («twin»). Читать и править как обычно — изменение прописывается в настоящий файл за вас. Незнакомый путь — это ожидаемо и само по себе сигнал, что в файле что-то было.
  5. Отказ — это информация, а не препятствие. В причине названо правило и штатный путь; попытки обойти сами попадают в аудит.
Отказ Штатный путь
Чтение .env, *.pem, ~/.ssh/… Читать .env.example или задокументированную схему. Проверить, что переменная задана, не печатая её: test -n "$VAR" && echo set
Команды, чья задача — напечатать креденшл (дамп окружения, выдача токена, чтение секрета кластера) Проверять наличие, не печатая значение
Grep с output_mode: content Bash + grep (этот путь фильтруется), либо Grep с files_with_matches, а затем Read
Поиск реального защищённого значения Искать по алиасу — в санитизированных копиях лежат алиасы, а не реальные значения
Креденшл в командной строке Передать через переменную окружения или файл, который команда читает сама
cd / export / source с алиасом Они выполняются в постоянном шелле и не могут быть обёрнуты фильтром; перестроить команду или выполнить шаг вручную
Аргумент MCP-инструмента с защищённым значением Использовать алиас; если инструменту нужно реальное значение — этот шаг выполняет пользователь

Отдельно про изменение файлов: если правка не появилась в настоящем файле — write-through упал и сообщил об этом (PostToolUse выходит с кодом 2 и печатает write-through to <path> FAILED). Проверьте права на целевой файл и ctxguard audit -n 20. Подготовленное содержимое цело в twin-копии.


Проверка, что защита работает

Два разных вопроса — две разные команды, и путать их нельзя:

ctxguard verify            # работает ли механика?      -> измеряет замысел
ctxguard scan-transcript   # утекло ли что-то реально?  -> измеряет результат

Доказательство — только второе: оно ищет реальные значения из словаря в транскриптах, то есть буквально в том, что было отправлено модели. Ненулевой результат означает, что данные дошли до модели несмотря на хуки — тогда сначала смотрите файлы инструкций (CLAUDE.md / AGENTS.md грузит харнесс, их не видит ни один хук), затем ctxguard audit.

По умолчанию сканируются транскрипты только этого проекта: сессии других проектов оцениваются против словаря, который им не принадлежит. Расширить — --all-projects.

Часть находок может быть помечена как структурные: значение входит в собственный путь проекта, поэтому появляется в каждом абсолютном пути и в метаданных транскрипта. Никаким хуком это не лечится — только переименованием каталога.


Передача словаря другой машине или коллеге

Плагин путешествует через маркетплейс. Словарь — нет, и не должен. ~/.claude/ctx-guard/ живёт на машине и намеренно вне любого репозитория. Передавать его нужно явно, потому что алиасы невозможно воспроизвести:

  • они выдаются в порядке регистрации, так что добавивший две компании в другом порядке получит перевёрнутое соответствие — два человека будут понимать под CTXG_COMPANY_A разные компании;
  • соль генерируется на хранилище, поэтому маркеры секретов и PII-алиасы тоже не совпадут, и находки нельзя сопоставить между людьми.

На это есть тест, так что рекомендация не может тихо устареть.

ctxguard entity export --out ~/team-dict.json   # откажется писать внутрь git-репозитория
# передавать по каналу, по которому вы отправили бы сами реальные значения — файл содержит их
ctxguard entity import team-dict.json           # запускать из каталога проекта
# удалить файл выгрузки сразу после импорта

После импорта обе машины дают побайтово одинаковый вывод — включая маркеры и PII-алиасы. Если в проекте уже есть словарь с другой солью, импорт откажется: принять чужую соль (--adopt-salt) значит поменять все уже используемые PII-алиасы и маркеры секретов.


Чего ctxguard не покрывает

  • CLAUDE.md и AGENTS.md грузит сам харнесс — ни один хук их не видит. Санитизировать вручную; SessionStart предупредит, если в них найдены реальные имена.
  • Структурные утечки: имя, входящее в путь проекта, защитить нельзя.
  • Пока сущности не зарегистрированы или не импортированы, живы только детект креденшлов и PII — имена компаний, людей и хостов не защищены.

Подробнее — plugins/ctxguard/skills/context-sanitization/references/threat-model.md. Прочитайте его прежде, чем обещать кому-либо, что данные в безопасности.

Необязательно, но полезно — чтобы ожидание пережило отключение плагина, добавьте в свой CLAUDE.md:

Чувствительные данные в этом проекте заменены алиасами (`CTXG_*`), это обеспечивают
хуки ctxguard. Используй алиасы буквально, никогда не восстанавливай реальные
значения, а причину отказа читай вместо того, чтобы его обходить. См. скилл
context-sanitization.

Настройка и отладка

Политика: ~/.claude/ctx-guard/policy.json. Отсутствует или битая — применяются строгие значения по умолчанию, потому что умолчания и есть безопасный откат. Хранится как diff от умолчаний, чтобы исправления правил доходили до установленных копий.

Ключевые поля: mode (enforce / observe), fail_closed (ошибка санитайзера отклоняет вызов инструмента), alias_prefix, entropy_threshold, max_scan_bytes, bash_wrap (выключение убирает фильтрацию вывода шелла целиком — не отключайте ради скорости), deny_read_paths, deny_command_patterns, allowlist, disabled_secret_rules. Полный список — references/policy.md.

Ложные срабатывания — в порядке предпочтения: точное значение в allowlist → конкретный маркер в allowlist_substrings → сужение правила в detect.py с тестом → id правила в disabled_secret_rules. Сначала посмотрите ctxguard audit: правило, которое постоянно срабатывает на безобидном, — это причина, по которой защиту в итоге выключают.

Стоимость: порядка 134 мс на решение по Bash и 155 мс на Read, который должен просканировать файл и материализовать twin. На задачу из 50 вызовов инструментов — примерно 6–7 секунд. Twin-копии кэшируются и инвалидируются по mtime+size, так что повторные чтения дешёвые.

Правка плагина не подействовала. Хуки исполняют установленную копию, а не рабочее дерево, и plugin.json сравнивается по версии, а не по коммиту — релиз без бампа версии не доедет до установленной копии молча. После каждого изменения:

claude plugin marketplace update ctx-tools
claude plugin update ctxguard@ctx-tools        # нужен рестарт сессии

Убедиться: diff -rq ~/.claude/plugins/cache/ctx-tools/ctxguard/<версия>/scripts plugins/ctxguard/scripts.

Выключить. /plugin uninstall ctxguard@ctx-tools. mode observe оставляет детекторы и аудит, но ничего не блокирует — это калибровка, а не способ работать защищённо. Состояние в ~/.claude/ctx-guard/ в обоих случаях остаётся; удалите этот каталог, чтобы убрать и словарь.


Структура репозитория

.claude-plugin/marketplace.json     манифест маркетплейса
plugins/ctxguard/                   санитизация контекста: скилл + хуки + CLI
docs/specs/                         проектный документ (исторический)
Makefile                            единственный вход в проверки

Куда положить новый скилл

Скиллу нужны… Куда
хуки, слэш-команды, MCP-серверы, скрипты отдельный плагин в plugins/<имя>/ + запись в marketplace.json
ничего, кроме инструкций плагин-«ведро»: plugins/<bucket>/skills/<имя>/SKILL.md

Хуки не могут ехать внутри голого скилла — именно поэтому репозиторий сделан маркетплейсом, а не плоским каталогом SKILL.md. Скиллы «только инструкции» стоит собирать в один плагин-ведро: одна установка покрывает все, тогда как плагины, ставящие хуки, добавляются осознанно и по одному. Такого ведра здесь пока нет — создайте его вместе с первым таким скиллом, а не заранее.

Конвенции, вслед за экосистемой установленных плагинов:

  • frontmatter в SKILL.md — name + description, третье лицо, много триггеров
  • детали уходят в references/*.md, не в SKILL.md
  • скрипты — Python 3 только stdlib, вызов через python3 "${CLAUDE_PLUGIN_ROOT}/..."

Начать чтение стоит с plugins/ctxguard/skills/context-sanitization/SKILL.md.