Каждая команда, каждый файл и каждый предел. Cerberus — один статический бинарь, демон на сокете и TUI; всё остальное — файлы, которые вы можете править.
CLI и TUIskills · MCP · pluginsAndroid + Termux
Начало
После установки есть два входа: TUI для человека и cerberusd — демон, который держит сокет, состояние и провайдера. TUI не выполняет инструменты сам: он отправляет запрос демону и рисует поток событий.
первый запуск
cerberus # TUI
cerberus status # жив ли демон, какая модель, сколько ключей
cerberus version
Если демон ещё не поднят, TUI запускает его сам. В root-режиме сокет — /dev/socket/cerberus.sock; без root — файл в ~/.cerberus.
Первая задача. Напишите в TUI: посмотри, что занимает место в /data/local/tmp, и убери только старые логи. Агент вызовет shell, покажет команду и результат, а на изменении вне песочницы попросит [Y/n].
CLI
Один бинарь, восемь режимов. Флаг -config PATH принимает любая команда, кроме version.
cerberusтерминальный интерфейс; без аргументов — он же
cerberus daemonдемон на сокете; берёт flock, второй экземпляр не стартует
Одна колонка, 32–60 символов. Команды начинаются с /; всё остальное уходит модели.
/helpподсказка по командам
/modelвыбор модели из GEMINI_API_MODELS
/skillsкаталог скиллов и статус каждого
/mcpMCP-серверы: успешно, выключено, сон, ошибка
/fix <имя>новая сессия, в которой агент чинит скилл или MCP
/check_updateпроверка версии на сервере
/updateустановить патч и перезапуститься
/newновая сессия
/stopостановить текущий ход
/unlockснять SECURITY_LOCKDOWN с сессии
Клавиши
Enterотправить
Ctrl+Nновая сессия
Ctrl+Xостановить ход
Ctrl+Lснять бан сессии
Ctrl+Cвыйти из TUI
В статусной строке видны модель, позиция ключа и состояние демона. При переключении ключа в ленте появляется отдельная строка — работа при этом не прерывается.
Файлы и конфигурация
Демон живёт в /data/adb/cerberus (root) или ~/.cerberus (reduced). Пользовательская копия конфига — Documents/Cerberus/.conf.
vault.bin + vault.keyAES-256-GCM и ключ шифрования
workspace/рабочая папка агента по умолчанию
conf/.envключи и модели Gemini
conf/skills/скиллы
conf/mcp/MCP-серверы
conf/heads/плагины; в Documents не зеркалируются
Зеркало
conf/ и Documents/Cerberus/.conf — одна и та же папка с точки зрения работы. Демон слушает inotify в обе стороны: правка в Documents сразу меняет конфиг демона, правка демона появляется в Documents. Перезапуск не нужен.
Исключение — heads/: плагины остаются на стороне демона, потому что это исполняемый Starlark, а не текст для чтения.
max_steps — предел шагов агента на одну задачу. tool_timeout_sec — дедлайн одного вызова. allowed_uids расширяет список тех, кому разрешён сокет: root и shell разрешены всегда, uid Termux нужно добавить явно.
.env
Файл Documents/Cerberus/.conf/.env — авторитетный источник ключей и моделей. Он же приватная копия демона; демон перечитывает его на каждое изменение.
Documents/Cerberus/.conf/.env
# ключи через запятую; на 429/401 берётся следующий
GEMINI_API_KEYS=AIza...,AIza...
# это меню /model
GEMINI_API_MODELS=gemini-2.5-pro,gemini-2.5-flash,gemini-2.5-flash-lite,gemma-3-27b-it
# выбор по умолчанию; иначе первая из списка
GEMINI_MODEL=gemini-2.5-pro
# необязательно: свой сервер обновлений
CERBERUS_UPDATE_URL=https://cerberus.lain.ch
Правила
Ключи — через запятую, без кавычек, без пробелов вокруг. Пустые и дубликаты отбрасываются.
GEMINI_API_MODELS — единственный источник списка в /model. Добавили строку — модель появилась.
Gemma обрабатывается отдельно от Gemini: другой endpoint и другая форма запроса.
Ключи никогда не пишутся в config.json и не попадают в историю: в JSON они помечены json:"-".
CERBERUS_UPDATE_URL перекрывает update_url из конфига. Пустое значение выключает обновления.
Файл читается целиком. Любое значение из .env регистрируется в редакторе вывода: если оно вдруг появится в ответе модели или результате инструмента, оно будет заменено на [REDACTED:KEY].
Секреты и vault
Vault — AES-256-GCM файл vault.bin с ключом vault.key. Значения доступны только демону и только хосту: модель получает имена, но не содержимое.
команды
cerberus vault list
printf '%s' "$TOKEN" | cerberus vault set GITHUB_TOKEN
cerberus vault rm GITHUB_TOKEN
Подстановка в HTTP
В http_request и плагинах значение подставляется на хосте из шаблона {{secret:NAME}}. Модель пишет только имя:
Инструмент request_secrets просит человека ввести значения в TUI без эха. Введённое сразу уходит в vault, а модели возвращаются только имена и признак «сохранено». Так ключ не проходит через контекст модели.
Что редактируется
read_file на .env возвращает только метаданные: имена переменных и схему, без значений.
env_inspect показывает метаданные vault и схему .env.
Вывод инструментов проходит через редактор: любое известное секретное значение заменяется на [REDACTED:NAME].
Файлы vault закрыты для агента на уровне путей: чтение, запись и hard link — Deny или Block.
Периметр
Ни один вызов не доходит до ОС без вердикта chains. Скрипты разбираются парсером mvdan.cc/sh, плагины — парсером Starlark, файловые операции отображаются на зоны путей. На исполнении тот же классификатор применяется повторно к уже раскрытому argv.
AllowLevel 2: песочница, чтение, logcat, pm list, сборка в workspace — без вопросов
ConfirmLevel 1: пакеты, перезагрузка, запись вне песочницы, модуль — [Y/n] и бэкап
Denyотказ без бана: операция не проверяема или касается запечатанного vault
Порядок вердиктов: Allow < Confirm < Deny < Block. Итог — самый высокий из найденных. При Block сессия получает SECURITY_LOCKDOWN, перестаёт отвечать и требует /unlock или Ctrl+L от человека.
Что ловится до выполнения
Алиасы, подстановки, вложенные sh -c, su, eval и base64-пейлоады: проверяется уже раскрытая команда.
Блочные устройства и kernel memory: /dev/block, /dev/mmcblk, /proc/kcore, /dev/mem.
Самоодобрение: аргумент, ссылающийся на контрольный сокет, и запуск бинаря агента из агента.
Непрозрачные скрипты: файл, который гейт не может прочитать, требует подтверждения; декодированный код — бан.
Перезапись критических путей и rm -rf /.
Проверить вручную:echo '...' | cerberus gate печатает вердикт и причины, не выполняя команду. Это тот же гейт, что и в работе.
Скиллы
Скилл — это процедура словами. Агент читает её через skill_read до того, как изобретать шаги. Формат — Markdown, без схемы и без кода.
Куда класть
Documents/Cerberus/.conf/skills/. Два варианта: папка с SKILL.md или один файл <имя>.md.
Documents/Cerberus/.conf/skills/cleanup/SKILL.md
---
name: cleanup
---
# Очистка диска
Сначала покажи, что занимает место:
du -sh /data/local/tmp/* | sort -h
Удаляй только *.log старше семи дней.
Никогда не трогай /data/adb/modules и vault.bin.
В конце покажи освобождённый объём.
Описание в каталоге — первая строка после frontmatter. Папка без SKILL.md, пустой файл или нечитаемый файл получают статус ошибка; /fix <имя> открывает сессию, где агент это исправляет.
Как создать вручную
Создайте папку skills/<имя>/ и в ней SKILL.md.
Первая строка после заголовка — короткое описание, что делает скилл.
Пишите команды и запреты явно: агент следует тексту, а не догадывается.
Ничего перезапускать не нужно: каталог читается при каждом /skills и каждом skill_list.
Проверка: /skills в TUI. Статусы — успешно, выключено, сон, ошибка.
MCP
MCP-сервер — обычный stdio-процесс, который объявляет инструменты. Cerberus запускает его на первом вызове и гасит через 5 минут простоя: настроенный, но неиспользуемый сервер не занимает ни CPU, ни RSS.
argsаргументы; абсолютные пути надёжнее относительных
envдополнительные переменные окружения процесса
disabledtrue — сервер не запускается и виден как «выключено»
Агент видит серверы через mcp_list, вызывает через mcp_call. Вывод сервера считается недоверенным текстом и проходит через тот же редактор секретов.
Как создать вручную
Создайте mcp/<имя>/ и положите туда mcp.json и сам сервер.
Проверьте запуск вручную: python3 server.py должен отвечать на stdio JSON-RPC.
Откройте /mcp. успешно — сервер ответил; ошибка — причина видна рядом; сон — был запущен и уснул.
/fix <имя> создаёт сессию для починки конфига или сервера.
Плагины
Плагин — Starlark-программа в conf/heads/<имя>/. Она исполняется в эфемерной VM, без доступа к сети напрямую: только объявленные модули. Плагины не зеркалируются в Documents.
entry по умолчанию tool.star. timeout_sec — не больше 120. secrets — имена из vault, которые плагин имеет право читать; всё остальное env.get не отдаст.
Верхнеуровневые функции — это и есть API плагина. plugin_list показывает список функций и признак проверки; plugin_run вызывает функцию по имени, аргументы приходят одним словарём.
Модули
sys.exec(cmd, as_root?, timeout_sec?)shell под гейтом; as_root только для литералов из проверенного исходника
sys.time()unix-время
fs.read(path, offset?, limit?)чтение файла через зоны путей
fs.write(path, content)запись
fs.list(path)листинг
fs.remove(path)удаление
http.request(url, method?, headers?, body?)HTTP; возвращает status и body
env.get(name)секрет из vault, только объявленный в манифесте
env.keys()имена разрешённых секретов
json.encode(v) / json.decode(s)JSON без рефлексии
Проверка и запуск
Сначала plugin_verify: статический анализ показывает функции, root-команды и найденные риски; вердикт Confirm требует согласия человека, Block банит сессию. Только после этого plugin_run. Плагин анализируется заново на каждом запуске — отметка .verified это workflow, а не граница безопасности.
Root-команды.sys.exec(as_root=True) принимает только литеральную строку, которая была видна гейту при проверке. Строка, собранная во время исполнения, никогда не совпадёт с белым списком.
Обновления
Сервер отдаёт не второй бинарь, а патч между сборками: формат CBPD1, блочное сравнение с окном 16 байт. Типичная дельта — около 20%; если изменилась только строка версии, патч весит десятки или сотни байт.
Клиент сравнивает свою версию с /check?version=...&arch=....
Сервер отдаёт патч на ближайшую доступную версию; если патча нет — полный файл.
Клиент применяет патч, проверяет sha256 результата и заменяет бинарь.
Старый файл остаётся как cerberus.old.
Демон перезапускает себя, TUI делает re-exec уже на новый бинарь.
Сервер хранит последнюю версию и предыдущие пять, собирает патчи на каждую пару и отдаёт /latest.json, /download?arch=, /patch и /install.sh. Свой сервер задаётся через CERBERUS_UPDATE_URL.
Как это устроено
Один процесс cerberusd держит состояние; TUI — тонкий клиент. Связь — JSON-RPC по unix-сокету, поток событий вместо опроса.
Агентный цикл ограничен max_steps. Каждый шаг — ответ модели с вызовом инструмента, выполнение под гейтом и возврат результата. События шага уходят в TUI сразу, поэтому длинная команда не выглядит зависанием.
Сессии не смешиваются: /new создаёт новую, /stop отменяет текущий ход, SECURITY_LOCKDOWN помечает конкретную сессию и не даёт ей продолжаться до /unlock.
Ограничения
Shell работает в процессе через интерпретатор, а не через системный /system/bin/sh. Переменные и cd не сохраняются между вызовами: передавайте всё одной командой или пишите скрипт.
Плагины — Starlark, не Python и не Go. Библиотек нет, есть только модули выше.
MCP-серверы запускаются от имени демона. Если серверу нужен root, это нужно решать внутри сервера, а не конфигом.
В reduced-режиме нет системного shell, pm, settings, logcat и автозапуска. Песочница, файлы, HTTP, MCP, скиллы и плагины работают.
Обновления требуют доступ к cerberus.lain.ch или своему серверу. Без сети /check_update честно покажет ошибку.
Нашли ошибку? Опишите шаги и приложите вывод cerberus status и cerberus version — этого достаточно, чтобы воспроизвести почти всё.