TL-Agent: control plane для ИИ-агентов на нотариальных квитанциях
Инженерная записка — что такое TL-Agent, как он работает и два способа его развернуть: стандартный локальный bundle и air-gapped режим с USB-носителем. Написано так, чтобы любой разработчик ИИ-агентов понял суть и мог применить.
Содержание
1. Что такое TL-Agent — и чем он не является
TL-Agent — это control plane и неподделываемая история действий для ИИ-агентов, построенные на нотариальных квитанциях сети TimeLayer. Простыми словами: прежде чем агент что-то сделает — прочитает файл, вызовет API, отправит сообщение — у него должна быть квитанция, которую он не мог выписать себе сам. Нет валидной квитанции — действие не выполняется. Точка.
Слово «нотариальная» здесь точное. Квитанция — не лог-запись, которую написал ваш сервер. Это криптографическое удостоверение, подписанное кворумом независимых операторов сети TimeLayer — операторов, каждый из которых хранит независимые приватные ключи — ни один оператор не может сфабриковать квитанцию в одиночку, а сама квитанция проверяется офлайн, без доверия к нашей инфраструктуре.
TL-Agent имеет два слоя, которые всегда строго разделены:
cert.tlcert+bundle.tlbundle— сама нотариальная квитанция, пара файлов, выданная сетью: подписанный сертификат и bundle для гейта, которые верификатор проверяет вместе. Никогда не изменяется, никогда не переписывается. Это источник истины.envelope.json— агентская обёртка: action_id, scope, допустимые следующие действия, ссылка на топологию. Указывает на файлы квитанции. Не заменяет их.
Вместе они образуют Receipt Action Unit — одно разрешённое действие, криптографически зафиксированное.
Чем TL-Agent НЕ является
Не система памяти — квитанции не хранят содержимое и не делают смысловой поиск (это провенанс, а не знание). Не песочница, физически останавливающая злонамеренный код — гейт работает для кооперативного агента, честно использующего SDK. Не замена debug-логам — они остаются эфемерным инструментом разработчика; TL-Agent покрывает значимые действия, а не каждый вызов функции.
2. Какую проблему решает
Вы строите ИИ-агента, который делает настоящие вещи в реальном мире: читает файлы, вызывает API, публикует данные, принимает решения. Три проблемы, которые не исчезают сами по себе, как бы аккуратно вы ни писали код:
Без TL-Agent
Агент может «разрешить» себе действие — установив флаг, который сам и проверяет. Тот же код, что решает что делать, решает и разрешено ли это.
История действий живёт в логе вашего сервера. Вы контролируете лог. Третья сторона не может независимо его проверить — придётся верить вам на слово.
Нет машинно-проверяемой границы между «что агенту позволено» и «что он заявляет, что сделал».
С TL-Agent
Разрешения — нотариальные квитанции. Агент их не выдавал — их выдала сеть до начала сессии. Агент не может разрешить себе что-либо (INV-01).
История — квитанции. Ни агент, ни вы не можете их переписать. Третья сторона с открытым верификатором может проверить любую квитанцию офлайн без обращения к вашим серверам.
Гейт — 6-шаговый алгоритм fail-closed. Любой пробел — нет квитанции, невалидная подпись, неверный переход — останавливает агента и требует участия человека.
3. Главный принцип
НЕТ КВИТАНЦИИ — НЕТ ДЕЙСТВИЯ
Каждое действие в топологии агента должно иметь квитанцию, прежде чем может быть выполнено. Не флаг. Не запись в логе. Квитанцию от сети, которую агент не мог сфабриковать. Одно это правило, применяемое без исключений, и отделяет TL-Agent от любого самоконтролируемого подхода.
4. Два режима работы
TL-Agent имеет режим по умолчанию, работающий на любой машине, и опциональный air-gapped режим для сред, где важна физическая изоляция разрешений.
Режим 1 — Локальный bundle
Bundle (разрешения + топология + квитанции) лежит как папка на хост-машине. Агент загружает его при старте, все проверки гейта выполняются локально, никаких сетевых вызовов во время работы.
- Работает на любой машине с бинарником
tl-agent - Вся верификация — офлайн (интернет не нужен во время гейт-проверок)
- Bundle создаётся один раз через Конструктор агента в кабинете
- Вы храните копию bundle вне среды агента (INV-08)
Режим 2 — Air-gapped USB
Для отраслей, где нужна физическая изоляция разрешений: юридическая, медицинская, финансовый аудит, режимные задачи. Два строго раздельных носителя:
- Read-only съёмный носитель — хранит bundle разрешений (
cert.tlcert+bundle.tlbundle, топологию, политики). Агент монтирует, читает, проверяет, действует. Сюда никогда не пишет. - Отдельный append-only носитель — принимает сырые результаты (что сделано + хеш). Заверение результатов происходит вне среды агента, чтобы агент не мог сфабриковать result-квитанцию.
Почему два отдельных носителя в air-gapped режиме
Если разрешения и результаты находятся в одном месте с возможностью записи, агент может перезаписать свои разрешения или подсунуть фальшивый результат. Разделение на read-only разрешения и append-only результаты исключает это — принуждает к соблюдению INV-01 (агент не выдаёт квитанции) и INV-02 (агент не изменяет bundle) на аппаратном уровне.
Честные ограничения air-gapped режима
Air-gap защищает от агента, но не от взломанной ОС хоста. Скомпрометированная операционная система может перехватить чтение с носителя в момент чтения. Аппаратная защита от записи на USB — настоящая защита; программное «только чтение» агент с правами обойдёт. И ещё: проверять квитанции и читать разрешения можно офлайн, но выдать новую нотариальную квитанцию (подпись сети) всё равно требует момента связи с кворумом.
5. Алгоритм гейта — 6 шагов, fail-closed
Каждый раз, когда агент хочет выполнить действие, он вызывает bundle.check_action(action_id). SDK выполняет эту последовательность — fail-closed на каждом шаге:
Любая проверка, которая не прошла → немедленный STOP. Причина останова возвращается вызывающей стороне. Политика остановки требует участия человека перед продолжением. Нет «мягкого отказа» или «предупреди и продолжи».
match bundle.check_action("action_read_files") { CheckResult::Allow(receipt) => { // receipt — нотариальное доказательство — выполняем действие } CheckResult::Stop { reason, message, .. } => { // reason: NO_RECEIPT | REVOKED | TOPOLOGY_DENIED // | TLSIG_INVALID | TRANSITION_DENIED // остановиться и сообщить человеку — не продолжать молча } }
Exit-коды для CLI: 0 = ALLOW, 1 = STOP. Это позволяет легко встроить в любой shell-скрипт или CI-пайплайн.
6. Структура bundle
Bundle — это папка. Вы создаёте её один раз через Конструктор агента и передаёте агенту. Агент читает её; никогда в неё не пишет.
agent-bundle/ manifest.json ← ID bundle, владелец, кол-во квитанций, флаги topology.json ← граф допустимых переходов между действиями policies/ agent_policy.json ← что агенту запрещено делать tool_policy.json ← какие инструменты разрешены stop_policy.json ← когда агент обязан остановиться receipts/ <action_id>/ envelope.json ← метаданные действия + allowed_next_actions cert.tlcert ← нотариальный сертификат — НИКОГДА не изменяется bundle.tlbundle ← bundle для гейта, проверяется вместе с cert — НИКОГДА не изменяется
Ключевое правило: cert.tlcert и bundle.tlbundle не трогаются после того, как помещены сюда. envelope.json только ссылается на них — не заменяет их. Эти два файла проверяются вместе офлайн, без реестра и внешних обращений. В manifest.json явно прописано "agent_can_write": false и "agent_can_issue_receipts": false.
Что определяет topology.json
Топология — это граф: какие действия разрешены и в каком порядке они могут следовать друг за другом. Если агент попытается перейти с action_read_files на action_send_email, а топология допускает только action_summarize — это STOP. Агент не может менять порядок своего собственного рабочего процесса.
7. Типы квитанций
У каждого действия в bundle есть квитанция с типом, описывающим её роль в рабочем процессе:
| Тип | Назначение |
|---|---|
| permission_receipt | Разрешение на выполнение действия — обязательно для каждого действия (INV-03) |
| identity_receipt | Кто создал задачу (устанавливает принципала-человека) |
| task_receipt | Фиксирует определение задачи — что делает агент и зачем |
| scope_receipt | Определяет границы: какие пути, read-only или read-write, доступ к сети |
| tool_receipt | Авторизует конкретный инструмент для использования |
| execution_receipt | Фиксирует факт выполнения действия (с хешем результата) |
| result_receipt | Удостоверяет результат действия |
| validation_receipt | Подтверждает, что результат прошёл валидацию (требуется, если задано в stop_policy) |
| stop_receipt | Авторизует команду остановки |
| revoke_receipt | Отзывает ранее выданное разрешение |
| final_receipt | Отмечает конечное состояние рабочего процесса |
8. 10 инвариантов
Это правила, которые нельзя нарушать. Если какая-то фича нарушает любой из них — фича неправильная, а не инвариант. Инварианты — это и есть продукт.
| ID | Правило |
|---|---|
| INV-01 | Агент не выпускает валидные квитанции сам — их выдаёт сеть |
| INV-02 | Агент не изменяет bundle пользователя |
| INV-03 | Каждое действие требует permission_receipt |
| INV-04 | Каждый переход проверяется по topology.json |
| INV-05 | Любой конфликт → STOP (не soft-fail, не «предупреди и продолжи») |
| INV-06 | Текст модели не является доказательством чего-либо |
| INV-07 | PASS невозможен без validation_receipt, если это требует политика |
| INV-08 | Пользователь хранит bundle вне среды агента (офлайн-копия) |
| INV-09 | Квитанция (cert.tlcert + bundle.tlbundle) не изменяется никогда после выдачи |
| INV-10 | envelope.json только ссылается на файлы квитанции — не заменяет их |
9. Как пользоваться: от bundle до работающего агента
Шаг 1 — Собрать bundle в Конструкторе агента
Зайдите на cabinet.timelayer-os.com/agent. Задайте действия и топологию визуально. Каждое действие получает квитанцию, нотаризованную сетью. Скачайте ZIP. Распакуйте — это ваш bundle.
Шаг 2 — Гейт-проверка перед каждым действием
# В shell-скрипте или CI-пайплайне: tl-agent check ./agent-bundle action_read_files # exit 0 = ALLOW, exit 1 = STOP # Посмотреть, какие действия разрешены следующими: tl-agent next ./agent-bundle action_read_files # Аудит всего bundle: tl-agent audit ./agent-bundle
Шаг 3 — В Rust-агенте
let bundle = AgentBundle::load("./agent-bundle")?; loop { let action = agent.decide_next_action(); match bundle.check_action(&action) { CheckResult::Allow(receipt) => { agent.run_action(&action, &receipt); bundle.record_execution(&action, &result_hash)?; } CheckResult::Stop { reason, .. } => { // сообщить причину человеку — не продолжать цикл break; } } }
Шаг 4 (air-gapped) — USB-носитель вместо локальной папки
Смонтируйте read-only USB-носитель при старте. Передайте точку монтирования как путь к bundle. Результаты направьте на отдельный append-only носитель. Всё остальное — идентично. SDK не знает и не требует, чтобы bundle был папкой на диске или смонтированным носителем.
# Монтируем read-only носитель с разрешениями mount -o ro /dev/sdb1 /mnt/permits # Запускаем агента с bundle на носителе tl-agent check /mnt/permits/agent-bundle action_read_files
10. Честная рамка: что TL-Agent не делает
- Не память. Квитанции не хранят содержимое. Они не запоминают, что агент сказал или нашёл. Они фиксируют, что было разрешено и что было выполнено (провенанс), а не то, что агент знает (recall).
- Не песочница против взломанного хоста. Если операционная система скомпрометирована, достаточно привилегированный процесс может перехватить или подменить чтения из bundle. TL-Agent является гейтом для кооперативного агента. Air-gapped режим сужает, но не устраняет эту поверхность.
- Не замена наблюдаемости. Debug-логи, трейсы и метрики остаются вашими инструментами разработчика. TL-Agent покрывает значимые внешне-верифицируемые действия — не каждый внутренний вызов функции.
- Заверение требует связи. Проверять существующие квитанции — полностью офлайн. Выдать новую квитанцию — получить кворумную подпись сети — требует момента связи. Планируйте рабочий процесс соответственно.
- Не гарантия правильности агента. Агент с валидной квитанцией всё равно может выдать неправильный результат. TL-Agent доказывает, что было разрешено и что было предпринято — человек, читающий аудиторский след, по-прежнему оценивает, был ли результат хорошим.
Суть в одной строке
TL-Agent даёт агенту разрешения, которые он не мог выдать себе сам, и историю, которую он не может переписать — под правилом НЕТ КВИТАНЦИИ → НЕТ ДЕЙСТВИЯ. Не память, не песочница от хоста, не наблюдаемость. Это неподделываемый control plane для кооперативного агента.
TimeLayer