Kansoku (観測, «наблюдение») — локальная платформа наблюдаемости для AI coding агентов (Codex, Claude Code и других). Она отвечает на простой вопрос: чем твои агенты реально пользуются — какие skills, plugins и MCP-инструменты активируются, как часто, с каким успехом и в каких сессиях, — не сохраняя ни одного prompt'а, ответа модели или фрагмента кода.
Всё работает на устройстве пользователя: один Docker Compose стек, один порт для дашборда, PostgreSQL для хранения. Ничего не уходит во внешние сервисы.
Агенты вроде Codex и Claude Code уже умеют экспортировать телеметрию (OTel) и слать хуки, но
у этих данных нет единого места, где видно фактическое использование агента — с учётом
ненадёжных источников, обрывов данных и разной степени доказательности события. Kansoku
собирает эти источники, честно помечает то, что не удалось подтвердить (unknown ≠ zero), и
показывает результат в локальном дашборде.
- Local-first. Runtime и данные — на устройстве пользователя; UI слушает только loopback.
- Metadata by default. Raw prompts, ответы моделей, tool input/output и код не сохраняются.
- No silent loss. Каждый источник данных измеряется на покрытие; разрывы помечаются явно, а не заполняются нулями.
- Adapter-first. Codex и Claude — обычные адаптеры, а не частные случаи в модели данных.
- Lineage everywhere. У каждой метрики есть источник, версия адаптера, schema fingerprint и время наблюдения.
- Unknown is not zero. Отсутствие данных, неподдерживаемый источник и настоящий ноль — три разных состояния, и они никогда не смешиваются.
- Useful over performative. Никакого сводного «productivity score» — только объяснимые метрики с явным числителем, знаменателем и ограничениями.
- Cheap to keep running. Один
docker compose up,restart: always, ограниченное хранение и предсказуемое потребление ресурсов.
Нужны Docker (Desktop или Engine) и Docker Compose v2. Все команды ниже выполняются из
каталога deploy/.
cd deploy
# 1. Собрать образ (контекст сборки — корень репозитория, поэтому Dockerfile лежит в deploy/,
# а сама сборка идёт из deploy/ на уровень выше)
docker build -f Dockerfile -t kansoku:local ..
# 2. Сгенерировать 7 обязательных секретов (каждый — отдельный файл, ≥32 байт, без \n внутри)
mkdir -p secrets
for name in ingress_bearer read_bearer mutation_bearer csrf identity_hmac audit_hmac database_password; do
openssl rand -base64 32 > "secrets/$name"
chmod 600 "secrets/$name"
done
# 3. Зафиксировать тег образа в .env — без этого файла переменная не переживёт
# следующий отдельный вызов docker compose (интерполируется заново при каждом запуске)
echo "KANSOKU_IMAGE=kansoku:local" > .env
# Необязательно: дать Kansoku read-only доступ к inventory Codex.
# Укажите только существующие абсолютные пути; Compose монтирует их read-only.
cat >> .env <<EOF
KANSOKU_CODEX_HOME_PERSONAL=/absolute/path/to/.codex-home
KANSOKU_CODEX_HOME_CORPORATE=/absolute/path/to/.codex-tbank
KANSOKU_CODEX_USER_SKILLS=/absolute/path/to/user-skills
KANSOKU_CODEX_SYSTEM_SKILLS=/absolute/path/to/system-skills
EOF
# Необязательно: дать Kansoku read-only доступ к inventory Claude Code.
# KANSOKU_CLAUDE_HOME — каталог с settings.json (обычно ~/.claude).
cat >> .env <<EOF
KANSOKU_CLAUDE_HOME=/absolute/path/to/.claude
KANSOKU_CLAUDE_USER_SKILLS=/absolute/path/to/.claude/skills
KANSOKU_CLAUDE_REPOSITORY_SKILLS=/absolute/path/to/repo/.claude/skills
KANSOKU_CLAUDE_SYSTEM_SKILLS=/absolute/path/to/system-skills
KANSOKU_CLAUDE_PLUGIN_CACHE=/absolute/path/to/.claude/plugins/cache
EOF
# Если записи в skills-каталоге — симлинки на отдельную библиотеку (частый случай:
# ~/.claude/skills/<name> -> ~/Projects/<library>/skills/<name>), укажите корень
# библиотеки. Он монтируется read-only по тому же абсолютному пути внутрь контейнера,
# иначе абсолютные симлинки внутри контейнера не разрешаются и такие скиллы не видны.
# Указывайте максимально узкий каталог, содержащий цели симлинков — никогда $HOME и не /.
cat >> .env <<EOF
KANSOKU_AGENT_LINK_ROOT_1_PATH=/absolute/path/to/skills-library
EOF
# 4. Поднять стек
docker compose -f compose.yaml up -d
# 5. Проверить процессы и UI
docker compose -f compose.yaml ps
curl -s http://127.0.0.1:43100/ -o /dev/null -w '%{http_code}\n'
# Capacity/ingestion health требует read bearer и может честно вернуть
# warning/degraded/critical даже при работающем PostgreSQL.
read_token=$(<secrets/read_bearer)
curl -s -H "Authorization: Bearer ${read_token}" \
http://127.0.0.1:43100/api/v1/healthДашборд — http://127.0.0.1:43100. OTLP-приём (для агентов) — http://127.0.0.1:4318
(HTTP) и 127.0.0.1:4317 (gRPC), оба требуют ingress_bearer из secrets/ingress_bearer.
secrets/ и .env — локальные и в git не попадают (см. .gitignore). PostgreSQL должен стать
healthy. Kansoku становится healthy только при полном operational pass; недостаток Docker
disk, durability/backpressure или stale source намеренно оставляет контейнер unhealthy, хотя UI
и read API продолжают работать. source_state становится как минимум degraded при gap,
inactivity, неизвестном runtime state или source clock более чем на пять минут в будущем;
configured/not_observed и unsupported остаются отдельными exclusions. Первый healthcheck может
занять до 30 секунд после старта.
По умолчанию база имеет advisory soft budget 5 GiB с порогами 70/85/95%, а не hard cap и не preallocation. Перед длительной эксплуатацией рекомендуется минимум 25–30 GiB свободного Docker disk space для БД, индексов, WAL/rollback, backup и emergency spool. Не запускайте 5 GiB soak, если свободное место уже ниже 20%; Kansoku не меняет allocation Docker Desktop автоматически.
Возьмите ingress bearer:
cat deploy/secrets/ingress_bearerCodex — добавьте в config.toml профиля ($CODEX_HOME/config.toml; если вы используете
несколько профилей через разные CODEX_HOME, повторите для каждого):
[otel]
log_user_prompt = false
[otel.exporter.otlp-http]
endpoint = "http://127.0.0.1:4318/v1/logs"
protocol = "binary"
headers = { "Authorization" = "Bearer <ingress_bearer>" }Claude Code — добавьте в блок "env" файла ~/.claude/settings.json:
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://127.0.0.1:4318",
"OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer <ingress_bearer>"
}
}OTEL_EXPORTER_OTLP_HEADERS здесь обязателен: loopback OTLP аутентифицирован, а заголовок —
единственный механизм Claude Code передать bearer. Значение принадлежит оператору: Kansoku никогда
его не пишет, не ротирует и не читает из чужого конфига; в installer-preview он показывается как
disclosure, а не как ошибка. Запрещёнными для записи остаются OTEL_LOGS_EXPORTER_FILE и любой
remote endpoint.
Конфиг агенты читают один раз при старте — после правки нужна новая сессия/процесс агента. Проверка: откройте дашборд → Activity/Agents, там должны появиться события за последние минуты.
Скиллы Claude Code. Активации приходят как OTel-событие skill_activated по тому же каналу —
отдельная настройка не нужна. Но чтобы активация связалась с конкретным скиллом, он должен быть
в inventory, поэтому скилл-каталоги выше нужно смонтировать, включая корень библиотеки для
симлинков. Что не попадёт в inventory никогда:
- встроенные скиллы Claude Code (
dataviz,simplify,run,review, …) — они вкомпилированы в исполняемый файл,SKILL.mdна диске нет; их вызовы остаются вunresolved_identityкак явное исключение; - repository-скиллы более чем одного проекта с одинаковым именем — Claude не передаёт признак
проекта, такие имена разрешаются как
ambiguous.
У Claude Code нет источника exposure (списка скиллов, видимых модели), поэтому эта плоскость
объявлена unsupported — в UI это отдельное состояние, а не ноль. Cold-состояние скиллов Claude
считается по полноте inventory; Codex использует настоящие exposure-окна из App Server. Нечитаемая
или битая запись в skills-каталоге понижает snapshot до partial, чтобы неполный inventory не
выглядел уверенным нулём.
Codex App Server exact evidence — normal serve принимает явно направленный JSONL stream на
POST http://127.0.0.1:4318/v1/evidence-bridges/codex-app-server. Нужны тот же
ingress_bearer и заголовок X-Kansoku-Agent-Installation с opaque installation ID из inventory.
Request ограничен 1 MiB, отдельный stream получает отдельный JSON-RPC demux. Kansoku не запускает и
не перенастраивает Codex: настройка producer/tee остаётся явной внешней операцией. Этот endpoint не
является доказательством для обычной CLI-сессии, чей stream через него не проходил. Raw frames
разбираются только в памяти; сохраняются typed identity/mode/tier/lineage и redaction counters.
Значение заголовка должно совпадать с installation_id Codex target в
deploy/runtime-config.json: тот же ID используется read-only inventory и rollout watcher.
Если /api/v1/health показывает pending projection, оператор может выполнить только
preview/approval-gated retry; автоматического discard нет:
mutation_token=$(<deploy/secrets/mutation_bearer)
csrf_token=$(<deploy/secrets/csrf)
curl -sS -X POST \
-H "Authorization: Bearer ${mutation_token}" \
-H "X-Kansoku-CSRF: ${csrf_token}" \
-H "Origin: http://127.0.0.1:43100" \
-H "Content-Type: application/json" \
--data '{}' \
http://127.0.0.1:43100/api/v1/admin/projection-repair/previewИз ответа нужно вручную перенести request_id и parameters_sha256, сгенерировать новый
одноразовый approval_nonce и отправить их на
POST /api/v1/admin/projection-repair/apply с теми же auth/CSRF/origin headers. Один apply
выполняет bounded PostgreSQL projection pass, один spool replay и reconciliation; он не возвращает
сохранённый retry input и не удаляет неприменённые receipts.
Kansoku раз в пять минут сканирует только явно смонтированные read-only roots из .env.
Для Codex это профили CODEX_HOME, user/system skills, plugin-конфигурация и bounded
plugins/cache/<marketplace>/<plugin>/<version>/skills catalog. Cache сам по себе не означает
enabled: bundle ownership создаётся только для единственной однозначной версии настроенного
plugin@marketplace, а несколько версий остаются cache-only. В Postgres попадают только
нормализованные имена, scope, версия/её value state, enabled-state, HMAC-pseudonym пути,
fingerprint и lineage snapshot; содержимое SKILL.md, команды MCP, env и credentials не
сохраняются. Неполный scan отображается как coverage gap, а не как complete zero.
Overview и component observatories показывают независимые классы доказательств:
Installed/Enabled— текущее состояние из inventory snapshot;Exposed/Invoked/Loaded— только реальные lifecycle-события поддерживаемого источника;- terminal outcome появляется только у компонента с зарегистрированным terminal contract;
not_observedозначает, что текущий upstream такого события не прислал, а не нулевое использование.
На 2026-07-25 официальный Codex OTel не документирует стабильное skill/plugin activation
событие. Поэтому Kansoku не выводит executed или opportunity detected из prompt-текста,
tool name либо факта установки. Claude Code, напротив, документирует skill_activated,
plugin_loaded и plugin_installed; они учитываются только в совместимых версиях и при
прохождении privacy allowlist.
Plugin, найденный в конфигурации/каталоге, но не включённый, показывается как installed + disabled. Наличие plugin marketplace или cache само по себе не считается установкой. MCP показывается только после явной конфигурации; тестовый MCP или plugin не включается Kansoku автоматически.
MCP observatory дополнительно разделяет configuration/inventory, protocol connection и call
lifecycle. Configured не означает connected, isError=false не означает успех пользовательской
задачи, а ноль calls не называется unused без полного окна exposure. Аргументы, результаты,
ошибки, URL, команды, environment и resource URI не сохраняются.
Session 11 (ADR 0014, Gap B) добавила hook-installer таргеты codex.user_hook /
claude.user_hook в contracts/privacy/installer.yaml и реальные builders
(installer.BuildCodexHookPlan / installer.BuildClaudeHookPlan) в internal/installer, вместе
с новым закрытым capability id configuration.hook_install
(contracts/adapter-sdk/capabilities.yaml). PlanConfiguration в internal/codexadapter и
internal/claudeadapter строит для этого capability реальный ChangePlan, проходящий через ту
же Plan/Approval/SimulateApply/SimulateRollback/SimulateRemove/PlanSHA256 машину, что
и OTel-таргеты — без второго apply-механизма.
Ownership-изоляция (обязательное требование ADR 0014, п. 4): Codex-hook и Codex-OTel живут в
одном config.toml (разные таблицы), Claude-hook и Claude-OTel — в одном settings.json
(разные ключи). Каждый план владеет только своим набором ключей — buildTargetPlan в
internal/installer/protocol.go читает/пишет исключительно targetSpecs[id].required этого
таргета и сканирует только его собственный forbidden-список, поэтому применение или откат
hook-плана никогда не трогает уже применённые OTel-ключи (и наоборот) и не трогает никакой
другой существующий пользовательский контент файла. Это проверено round-trip тестом
(TestHookPlanOwnershipIsolationRoundTrip в internal/installer/protocol_test.go): применяем
OTel-план, применяем hook-план, откатываем hook-план — OTel-ключи и весь несвязанный контент
побайтово совпадают с состоянием до применения hook-плана.
Что именно пишет hook-план (только preview/simulate, см. ниже):
Codex (config.toml, таблица notify):
[notify]
command = "kansoku-codex-hook"
role = "collection_only"Claude Code (settings.json, ключи hooks.* для всех 7 задокументированных событий):
{
"hooks": {
"SessionStart": "kansoku-claude-hook",
"UserPromptSubmit": "kansoku-claude-hook",
"PreToolUse": "kansoku-claude-hook",
"PostToolUse": "kansoku-claude-hook",
"SubagentStart": "kansoku-claude-hook",
"SubagentStop": "kansoku-claude-hook",
"Stop": "kansoku-claude-hook"
}
}Оба hook-помощника (kansoku-codex-hook / kansoku-claude-hook) по контракту
(contracts/codex/hooks-and-otel.yaml / contracts/claude/hooks-and-otel.yaml) читают только
bounded stdin JSON, вычисляют prompt-фичи в памяти, никогда не пишут и не пересылают сырой
prompt/ответ/tool payload, и шлют уже санитизированное событие на тот же общий
/v1/hooks/{adapter}/{event} route, что и OTel-приёмник — codexHookHandler /
claudeHookHandler в internal/observability/routes.go (проверено
TestRealAdapterHookStdinPayloadsReachCodexAndClaudeHookRoutes синтетическим stdin-пейлоадом,
доходящим до реального handler'а).
Важно — это остаётся simulate-only, как и весь internal/installer (ADR 0002). В отличие от
раздела «Подключение реальных агентов» выше, здесь нет ручных шагов «впишите это в файл» — ADR
0008's известный пробел (нет kansoku doctor/configure CLI) означает, что PlanConfiguration
и SimulateApply/SimulateRollback для configuration.hook_install сегодня доступны только из
Go-кода (тесты и будущий CLI), а не из README-инструкции для реального пользователя.
AuthorizeRealWrite по-прежнему возвращает "not implemented" для любого таргета — ни один hook
или OTel план не пишет в реальный файл пользователя без будущей CLI-обвязки и явного
human-approval шага.
Если ты — AI-агент и тебе передали этот репозиторий с задачей «подними Kansoku и подключи себя к нему», порядок действий:
- Спроси явное подтверждение пользователя перед выполнением — дальнейшие шаги создают
локальные секреты и меняют файлы конфигурации самого пользователя (
config.toml/~/.claude/settings.json). - Выполни шаги из «Быстрый старт» выше (сборка образа, секреты,
.env,docker compose up, проверка healthy). - Прочитай
deploy/secrets/ingress_bearerи пропиши его в конфиг своего собственного рантайма по разделу «Подключение реальных агентов» — определи, Codex ты или Claude Code, и какой у тебяCODEX_HOME/ где твойsettings.json. - Сообщи пользователю, что нужно начать новую сессию/перезапустить процесс, чтобы конфиг
применился, и укажи, где смотреть результат (
http://127.0.0.1:43100).
- ARCHITECTURE.md — карта модулей репозитория (
internal/*,cmd/*,web/,contracts/*) для быстрой ориентации агента: что где лежит и какой документ ниже открывать дальше по конкретной области. - ROADMAP.md — история разработки и зависимости между этапами.
- Engineering Proposal — цели, альтернативы, продуктовые решения.
- Technical Design Document — контракты, схемы, алгоритмы, эксплуатационные требования.
- SOURCES.md — официальные интерфейсы агентов и инфраструктуры, на которых основан дизайн.
adr/— architecture decision records;reports/— verification/reconciliation отчёты по каждому этапу разработки.- AGENTS.md — правила работы над этим репозиторием для будущих сессий разработки.