Язык: Русский · English
Reverse-engineered спецификация harness Codex CLI (OpenAI) — механики агентского цикла, tools registry, компакции и управления контекстом. Извлечена из исходников репозитория и оформлена как навигируемый knowledge graph для тех, кто строит AI-агенты или пишет инструкции для них.
Компаньон к серии статей OpenAI «Unrolling the Codex agent loop» / «Harness engineering» / «Unlocking the Codex harness».
Автор инструкций обычно не знает, что harness применяет жёсткие числовые отсечки внутри собственной логики сборки prompt'а. Усечение происходит тихо — ни warning, ни ошибки. Ниже — пять мест, где это реально случается.
1. 5 000 байт — лимит на текст approved command prefixes. Когда вы описываете политику утверждения shell-команд через список разрешённых префиксов (git commit, npm install, и т.д.), harness рендерит их в developer-инструкции как блок текста. Как только этот текст превышает 5 000 байт — он обрезается до последнего корректного UTF-8 символа, и в конец добавляется маркер ...[Some commands were truncated]. Модель получит неполный список, но вы об этом не узнаете. Что делать: группируйте префиксы (git * вместо пяти отдельных git commit, git push…), либо уносите критичные правила в base_instructions текстом.
2. 100 штук — лимит на количество элементов в prefix list. Даже если байтов меньше 5 000, harness всё равно возьмёт максимум 100 префиксов после сортировки по (длина, суммарная длина, алфавит). Остальные отбрасываются без предупреждения. Что делать: если у вас больше 100 правил — это уже не список префиксов, а политика, и её следует выражать декларативно в base_instructions, а не перечислением.
3. 20 000 токенов — лимит на user-messages после компакции. Когда harness запускает авто-компакцию, он сохраняет только самые свежие user-сообщения — ровно столько, сколько укладывается в 20 000 токенов суммарно. Всё, что старше, растворяется в одном summary-абзаце. Если вы «раскрывали» правила последовательно через десяток user-сообщений — начало серии после компакции исчезнет. Что делать: каркас правил держите в base_instructions (они пересобираются заново на каждый turn), а пошаговое уточнение — понимайте, что оно живёт только до следующей компакции.
4. 90% от context window — порог авто-компакции. Harness сам запускает компакцию, когда суммарное потребление токенов превышает 9/10 размера окна модели. После компакции все developer-сообщения выбрасываются целиком — фильтр should_keep_compacted_history_item квалифицирует их как «stale/duplicated instructions». Это значит: правила, которые harness подложил через developer-инъекции для одного turn'а (approval policy, sandbox-инструкции, экранное окружение), перестанут существовать в истории после первой же компакции. Что делать: не полагайтесь на то, что developer-инструкция «помнится»; если правило важно — оно должно быть в base_instructions.
5. 1 MiB — жёсткий лимит на user-input. Любой user-input длиннее 1 048 576 символов будет отклонён harness'ом до отправки в модель. Для текстовых запросов это много, но если вы программно склеиваете большие куски (лог-файлы, диффы, выгрузки) — легко упереться. Что делать: предварительно усекайте большие вставки на своей стороне, не надейтесь что harness «что-нибудь придумает».
Для harness-инженера полезны не «81 тип событий», а значения, которые определяют контракт с вашим клиентом.
1. Канал submission — capacity 512. Harness принимает операции от клиента через канал с фиксированным размером 512. Когда канал заполнен — клиент блокируется (backpressure). Если вы строите свой оркестратор — аналогичный параметр надо выбирать осознанно: слишком маленький приводит к затыкам UX, слишком большой — маскирует медленную обработку. Codex выбрал 512 как компромисс между отзывчивостью и защитой от «захлёба» heavy-turn'ами.
2. Agent job concurrency — default 16, max 64. Когда harness запускает CSV-spawn (параллельные sub-agents по таблице), дефолт — 16 параллельных воркеров, жёсткий максимум — 64. Это ограничение не про технику, а про стоимость: каждый активный sub-agent держит свой turn с собственным потреблением токенов. Если в вашем harness нет аналогичного cap'а — клиент может непреднамеренно запустить сотни параллельных агентов и поймать billing shock.
3. Lock retry — 10 попыток по 100 ms. История сессии пишется в rollout-файл с блокировкой; при конфликте harness пытается захватить lock 10 раз с паузой 100 ms. Это дизайн-решение для одновременной работы нескольких процессов (например, CLI + VS Code extension в одной сессии). Если вы пишете свой persistence — учтите, что без retry аналогичная схема развалится на первом же конкурентном доступе.
4. Max scan files при resume — 10 000. Когда harness восстанавливает сессию из rollout-архива, он сканирует максимум 10 000 файлов. Это предел глубины истории, которую можно «откатить» через resume. Для harness-инженера аналогичный предел — это про ресурсы при старте, а не про functionality; сканирование без cap'а приведёт к минутам задержки на старте клиента.
5. Wait timeout — от 10 секунд до 1 часа. Для блокирующих tool-вызовов (wait-операций) harness нормирует timeout в диапазон 10s–3600s. Меньше 10s — отклоняется (защита от busy-loop'ов), больше часа — тоже (защита от зависания сессии). Если ваш tool registry принимает произвольные timeout от модели — вы рискуете получить либо DoS (модель попросит ждать вечно), либо «дребезг» (модель будет вызывать wait по секунде).
Вы пишете системные промпты, AGENTS.md, свод правил, skill-набор — и хотите знать, как harness на самом деле сложит это с историей и передаст модели. Спека отвечает на:
- какие инструкции переживают компакцию, а какие — нет;
- где физически окажутся ваши правила в финальном prompt;
- какие пороги молча срежут ваш текст до того, как модель его увидит;
- как skill-упоминания активируют инжекцию без раздувания контекста;
- почему именно ваши правила «забываются» после N turns.
Вы строите свой агентский цикл — turn loop, streaming, tool dispatch, session persistence — и хотите эталонную реализацию. Спека даёт:
- полную механику turn: Item lifecycle, TurnItem → legacy EventMsg mapping, TTFT/TTFM метрики;
- двухпутьевую компакцию (inline summarization vs
/responses/compactendpoint); - retry-политику с префиксным кэшем при
ContextWindowExceeded; - fork / resume / rollback семантику thread'ов.
18 SRC-модулей × 3 линзы:
| Линза | Что | Всего |
|---|---|---|
rules.json |
Инварианты, пороги, формулы, GWT-примеры (Given / When / Then) | 1 028 правил |
structural.json |
Сущности, поля, отношения, потоки данных | 588 структур |
use-case.json |
Сценарии: шаги, Cockburn-расширения, edge-кейсы, lifecycle | 325 use-cases |
| Итого | ≈ 1 941 композиция |
Диапазон покрытия: D1-protocol (типы, wire-форматы) → D2-state (сессии, треды, rollout) → D3-agent (ядро: spawn, turn loop, компакция) → D4-context (turn-context, initial context, env) → D5-tools (registry, dispatch, sub-agents).
Вне scope: sandbox, security, MCP-интеграция, hooks/plugins internals, auth, аналитика, network policy, провайдеры моделей, CLI / TUI / IDE порты.
Это не «термины из кода», а решения команды, по которым Codex отличается от типичной агентной практики. Для каждого — что сделано, что делают обычно, и что это даёт автору инструкций или harness-инженеру. Критерий отбора: (1) это решение с видимой альтернативой; (2) альтернатива типична в индустрии (LangChain / AutoGen / Assistants API делают иначе); (3) различие меняет поведение ЦА, а не просто внутренняя деталь.
Что сделал Codex. Разделил инструкции на пять семантических слоёв, каждый со своей моделью жизненного цикла: base_instructions (пересобираются каждый turn), initial_context (реинжектируются после компакции), skill injections (активируются @-упоминанием), developer messages (runtime policy), user messages (task-специфика).
Что делают обычно. В LangChain / AutoGen / Assistants API есть плоский system prompt + messages[], и один system prompt для всей жизни треда. Инструкции либо вшиты раз и навсегда, либо «размазаны» в user-сообщениях без структуры.
Что даёт ЦА. Автор инструкций получает ответ на вопрос «куда положить правило, чтобы оно работало всегда». Правило в base_instructions переживёт компакцию и не зависит от истории; правило в developer-message — волатильное, пропадёт при первой компакции; правило в skill-файле — активируется только когда нужно. Это даёт осознанное проектирование ruleset'а, а не надежду «модель это запомнит».
Что сделал Codex. Модульные наборы инструкций (skills) не попадают в prompt по умолчанию. Они подгружаются только когда пользователь явно упомянул скилл через @skill-name (collect_explicit_skill_mentions) или когда harness видел этот скилл в предыдущих turn'ах (implicit_invocation_seen_skills).
Что делают обычно. В типичном агенте все tool-описания и все правила загружаются в prompt сразу. Это работает для 5–10 tools, но ломается на 50 — модель начинает теряться, prompt раздувается до десятков тысяч токенов постоянной нагрузки.
Что даёт ЦА. Вы можете держать произвольно большой каталог правил, разбитый по темам (@testing-rules, @security-review, @refactor-style), и у каждого turn'а в контексте оказываются только те, что реально нужны. Базовый промпт остаётся маленьким — только мета-правила «когда какой skill звать». Это принципиально другая модель масштабирования инструкций.
Что сделал Codex. Когда environment не изменился между turn'ами, harness не отправляет его снова. Для этого хранится reference_context_item — снимок последнего отправленного контекста. На новом turn'е build_environment_update_item сравнивает текущее состояние с reference и эмитит user-сообщение только с изменёнными полями, обёрнутыми в <environment_context> маркер.
Что делают обычно. Классический подход — приклеивать полный system context к каждому запросу. Модель видит одни и те же CWD, git branch, файловую систему десятки раз подряд.
Что даёт ЦА. Экономия токенов на статичных правилах, и — что важнее — модель не «теряется» в повторах. Когда одно и то же env-сообщение пересылается каждый turn, модель начинает придавать ему лишний вес; diff-обновление делает контекст «шумом, который приходит только когда что-то реально случилось». Автор инструкций, который кладёт свои environment-сведения через стандартный <environment_context> фрагмент, автоматически получает эту экономию.
Что сделал Codex. Перед компакцией harness собирает ghost snapshots — слепки истории — и дописывает их в конец новой сжатой истории. Фильтр should_keep_compacted_history_item специально их сохраняет, даже когда удаляет всё остальное.
Что делают обычно. Компакция в большинстве систем — необратимая операция: старая история заменена на summary, и вернуться уже нельзя. Пользователь, начавший длинную сессию, теряет возможность «откатить» в момент, когда компакция уже была.
Что даёт ЦА. Для harness-инженера — паттерн дизайна compaction'а, при котором один инвариант (разумный размер prompt'а) не разрушает другой (возможность отката). Это нетривиальное решение, оно требует дополнительной бухгалтерии (снимки размечены флагом, фильтр их пропускает), но результат — безопасность длинных сессий, где пользователь не боится «переборщить» и потерять прогресс.
Что сделал Codex. Harness различает шесть видов «контекстных фрагментов», каждый со своим XML-маркером: <agents_md>, <environment_context>, <skill>, <user_shell_command>, <turn_aborted>, <subagent_notification>. Эти куски текста формально не считаются пользовательским вводом — они не считаются user_turn_boundary при rollback, обрабатываются отдельно при трим-проходе, и часть из них (AGENTS_MD, SKILL) исключается из memory generation.
Что делают обычно. Весь user-role текст трактуется одинаково: и реальная команда пользователя, и boilerplate-инструкции, и env-дамп. В результате rollback до «последнего user-сообщения» может вернуть не туда, потому что «последним user-сообщением» окажется системный env-фрагмент.
Что даёт ЦА. Автору инструкций — нельзя оборачивать свои правила в произвольный XML и ожидать, что harness их распознает. Если обернуть в <my_rules> — это останется обычным user-text'ом и будет обрезано при трим-проходе в первую очередь. Правильный путь: либо положить в base_instructions, либо воспользоваться стандартным <skill> через skill-инжекцию. Этот же контракт полезен harness-инженеру: если вы строите свой агент, разделение «пользовательский ввод vs служебные вставки» должно быть первоклассной концепцией, а не соглашением в комментариях.
Что сделал Codex. Когда запускается Guardian — специальный reviewer-подагент для утверждения shell-команд — он игнорирует exec-policy, унаследованную от родителя, и использует built-in safety checks (ExecPolicyManager::default). Это отдельный case в коде: правило guardian-reviewer-bypass-exec-policy.
Что делают обычно. Sub-agents наследуют политику от caller'а. Это интуитивно — если главный агент настроен доверять git *, пусть и sub-agent доверяет. Но в случае reviewer это опасно: caller может «самоодобрить» собственные команды через reviewer с caller-specific rules.
Что даёт ЦА. Harness-инженеру — паттерн «security-critical sub-agent должен быть архитектурно изолирован». Это редкое, но принципиальное различие: reviewer не может быть подкуплен контекстом caller'а. Если вы строите агентскую систему с self-review — конкретно эту часть нельзя делать «по-простому», иначе вся идея reviewer'а разрушается. Codex это прямо закодировал как инвариант.
Оба примера ниже — это демонстрация работы со спекой на живых запросах. Читатель приходит с произвольным тезисом и получает развёрнутый содержательный ответ, собранный из SRC-модулей. Никакой предварительной ориентации в файлах спеки не требуется.
Исходный запрос пользователя:
«И нужно сделать по спеке 2 примера из данных спеки — прямо показать как ты их создал: запрос и что получилось. 1 пример — запрос: объясни самую сложную и важную механику агента Codex. 2 пример — запрос: помоги решить проблему затухания бюджета внимания, когда инструкция содержит много правил. Эти запросы обрабатывай используя эту спеку.»
Уточнения:
«2 пример должен быть для разработчика инструкций. Из данных спек нужно делать ответы для примеров. И ещё напиши запросы, с помощью которых ответы получились — иначе пример плохой, он должен показать как использовать спеку. Перепиши примеры на обучающие: поменьше ссылок на спеку, побольше что там содержится, чтобы можно было не переходя по ссылкам суть понимать.»
Короткий ответ: самое сложное в Codex — это авто-компакция истории беседы. Она важна, потому что держит turn loop живым при исчерпании context window; сложна — потому что объединяет пять разнородных задач: обнаружение близости к лимиту, выбор реализации под провайдера, безопасный retry при переполнении, сохранение инвариантов истории и поддержку /undo.
Harness считает порог как 90% от context window модели, с возможностью ужесточить его в конфиге (меньшее значение выигрывает):
auto_compact_token_limit = min(config_limit, context_window × 9/10)Если оба значения не заданы — авто-компакция выключена. Срабатывает в трёх режимах:
- pre-turn — перед обработкой нового user-сообщения, если прошлое total usage уже за порогом;
- mid-turn — внутри активного turn, когда модель вот-вот упрётся в окно;
- manual — пользовательская команда
/compact.
Разница принципиальна: mid-turn оставляет «якорь» на текущий turn context, чтобы следующий turn шёл diff'ом. Manual и pre-turn не ставят якорь — следующий turn делает полную реинжекцию.
Harness сначала спрашивает провайдера: «умеешь удалённую компакцию?». Если да — вся история отправляется на серверный endpoint /responses/compact, который возвращает уже сжатый Vec<ResponseItem>. Если нет — harness делает inline summarization: подкладывает собственный SUMMARIZATION_PROMPT, гоняет обычный streaming turn и получает текст-summary.
Решение выбирается по флагу provider.supports_remote_compaction() и фиксируется на старте — в середине переключения не бывает.
Самая нетривиальная часть. Inline-компакция внутри себя делает streaming-запрос и может получить от модели ContextWindowExceeded — потому что prompt с историей + summarization-инструкциями сам не помещается. Harness реагирует так:
- если в истории больше одного item →
history.remove_first_item(),truncated_count++,retries = 0,continue. Жертвуем самым старым item'ом, чтобы сохранить префиксный кэш провайдера и последние сообщения (где обычно свежие user-инструкции); - если остался один item или меньше →
set_total_tokens_full, Error event, выход. Даже минимальный контекст не помещается — дальше уже не спасёт.
На другие ошибки (сеть, rate-limit) — retry с exponential backoff до provider.stream_max_retries(). Interrupted / TurnAborted — немедленный выход без retry. При pre-trim в UI эмитится:
"Trimmed N older thread item(s) before compacting..."
Harness строит build_compacted_history_with_limit:
- Берёт все user-messages кроме summary-сообщений (они узнаются по префиксу — тексту
SUMMARIZATION_PROMPT+\n). - Итерирует в reverse и набирает, пока суммарно не превысит
COMPACT_USER_MESSAGE_MAX_TOKENS = 20 000. - Собирает итоговый список:
initial_context+ набранные свежие user-messages +summary_user_messageпоследним.
Если summary_text пуст — подставляется "(no summary available)".
Модель Codex обучена видеть summary в последней позиции истории. Harness поддерживает этот инвариант:
insertion_index =
last_real_user_index // перед последним настоящим user message
?? last_user_or_summary_index // если real user не нашлось — перед summary
?? last_compaction_index // если и этого нет — перед последним Compaction
// иначе — append в конецGWT-пример:
- Given:
compacted_history = [compaction_item, summary_user_message],initial_context = [env_msg, dev_msg] - When: вставка
- Then:
last_real_user_index = None(summary не реальный),last_user_or_summary_index = 1, insertion = 1 →[compaction_item, env_msg, dev_msg, summary_user_message]
Summary остаётся хвостом — контракт сохранён.
Перед отправкой на remote компакцию harness оценивает estimate_token_count_with_base_instructions. Если прогноз превышает окно — режет хвост истории, но только пока последний item codex-generated:
FunctionCallOutput/ToolSearchOutput/CustomToolCallOutput— можно резать- developer Message — можно
- user / assistant Message — break, не трогаем границу
Инвариант: при удалении tool-output парный tool-call снимается через normalize::remove_corresponding_for, иначе модель получит «сиротский» call без ответа.
Перед компакцией harness собирает GhostSnapshot items — снимки для rollback'а. После сборки нового compacted_history они дописываются в конец и помечены фильтром should_keep_compacted_history_item как сохраняемые. Иначе /undo после компакции стал бы невозможен.
Remote endpoint может вернуть items любого вида — harness фильтрует:
Выбрасывается: developer messages (stale/duplicated instructions), user-role messages, не являющиеся UserMessage/HookPrompt (session-prefix wrappers), Reasoning, FunctionCall/Output, ToolSearchCall/Output, CustomToolCall/Output, LocalShellCall, WebSearchCall, ImageGenerationCall, GhostSnapshot, Other.
Сохраняется: assistant messages, Compaction items, user-role warnings и summary messages.
Практический вывод: всё, что автор инструкций заложил в «разовые» developer-инъекции, после компакции будет выкинуто.
Все события компакции эмитятся с захардкоженным strategy = CompactionStrategy::Memento — константа на стороне analytics, независимо от реальной реализации. Отправка gate'ится через Feature::GeneralAnalytics: флаг фиксируется в CompactionAnalyticsAttempt::begin и не перепроверяется в track(). Выключение аналитики посреди turn'а не отменит уже начатый event.
Finalizer переводит Result в CompactionStatus:
Ok→CompletedErr(Interrupted)/Err(TurnAborted)→Interrupted- прочие
Err→Failed
По завершении inline-компакции harness эмитит warning toast:
"Heads up: Long threads and multiple compactions can cause the model to be less accurate. Start a new thread when possible to keep threads small and targeted."
Это сигнал деградации: каждый новый раунд компакции отбрасывает дополнительный слой контекста, потому что developer-инструкции не переживают фильтр, а summary — это уже «пересказ пересказа». Отсюда правило: системные инструкции должны жить в base_instructions (пересобираются заново на каждый turn), а не в runtime developer-инъекциях.
Один путь исполнения пересекает шесть независимых инвариантов:
- Token arithmetic (estimate_tokens_with_base_instructions)
- Провайдер-детект (remote vs inline)
- Сетевой retry с backoff и префиксным кэшем
- History invariants (call/output pair, user/assistant boundary, summary last)
- Rollback (ghost snapshots)
- Feature-flags и analytics state machine
Ошибка в любом — либо OOM на контексте, либо silent-деградация качества модели.
Короткий ответ: harness уже решает задачу «много правил vs ограниченное окно», но не прощает авторам инструкций размещение правил в «волатильных» зонах. Если правила сложить не туда — модель получит усечённую версию молча. Ниже шесть практических правил, каждое с механикой и конкретными цифрами.
Harness автоматически запускает компакцию при used_tokens > context_window × 9/10. После компакции:
- сохраняются только user-messages последние 20 000 токенов суммарно (константа
COMPACT_USER_MESSAGE_MAX_TOKENS); - всё старше растворяется в summary;
- developer-сообщения (в том числе с вашими правилами) выбрасываются полностью как «stale/duplicated instructions».
Практика: если у вас окно 200k токенов — безопасная зона до 180k. Если вы «раскрываете» правила пошагово через десяток user-сообщений — начало серии исчезнет после первой же компакции.
Harness резолвит base_instructions по приоритету:
base_instructions =
config.base_instructions // явный override
?? conversation_history.get_base_instructions() // из rollout session_meta
?? model_info.get_model_instructions(personality) // model defaultКлючевое свойство: base_instructions пересобираются на каждый turn заново. Они не живут в истории — приходят как system-инструкции отдельным полем запроса. Поэтому переживают компакцию и не зависят от того, какая часть истории ещё в контексте.
Практика:
- неизменные правила поведения, стиль ответа, хард-инварианты →
base_instructions; - runtime policy (sandbox, approvals) → developer messages (harness положит сам);
- task-specific детали → user message (последние 20k переживут компакцию).
Если вы настраиваете политику утверждения shell-команд через список префиксов, harness рендерит их в developer instructions с двумя усечениями:
- байтовый лимит:
MAX_ALLOW_PREFIX_TEXT_BYTES = 5 000. При превышении — текст обрезается до последнего корректного UTF-8 char и добавляется маркер...[Some commands were truncated]. - штучный лимит:
MAX_RENDERED_PREFIXES = 100. Берутся первые 100 после сортировки по(len, combined_str_len, alphabetical). Остальные просто не попадают в prompt.
Если вы перечислили 200 разрешённых команд — модель увидит только 100. Какие именно — зависит от лексикографического порядка. Harness не предупреждает.
Приёмы обхода:
- группировать префиксы (
git *вместоgit commit,git push,git pullотдельно); - критичные запреты выносить в
base_instructionsтекстом, а не в exec policy.
Harness поддерживает lazy-инжекцию skill-инструкций. Последовательность внутри turn-а:
collect_explicit_skill_mentions(user_input)— находим@-упоминания skills в тексте пользователя;resolve_skill_dependencies_for_turn— проверяем env-переменные, которые нужны этим skills;build_skill_injections— собираем инструкции только для упомянутых skills;record_conversation_items— добавляем в историю turn-а.
У вас может быть десятки skills с детальными правилами, но в prompt попадают только те, что пользователь явно позвал. Это прямой способ держать большой ruleset вне постоянного контекста.
Практика: разбейте свод правил на модули по темам (@testing-rules, @security-review, @refactoring-style). Базовый промпт содержит только мета-правила «когда какой skill звать». Активный turn тянет детали по требованию.
Harness различает обычный user-текст и контекстные фрагменты — их шесть видов с жёсткими тегами-обёртками:
<agents_md>...</agents_md>(AGENTS_MD_FRAGMENT)<environment_context>...</environment_context><skill>...</skill>(SKILL_FRAGMENT)<user_shell_command>...</user_shell_command><turn_aborted>...</turn_aborted><subagent_notification>...</subagent_notification>
При нормализации истории и при pre-trim перед компакцией harness специально обрабатывает эти метки: видит их как «имеющие смысл» и иначе относится к их обрезке. Environment и subagent-notification фрагменты сохраняются в memory inputs.
Что произойдёт, если обернуть правила в свой XML-тег <my_rules>...? Harness разметит их как обычный user-text и при триме обрежет первыми — без различия, что там критичное. Хотите, чтобы правила выжили? Либо base_instructions, либо стандартный SKILL_FRAGMENT через skill-инжекцию.
После mid-turn компакции harness вставляет initial_context по цепочке приоритета:
- перед последним настоящим user message (не summary);
- если настоящих нет — перед последним user-like (включая summary);
- если и их нет — перед последним Compaction item;
- иначе — append в конец.
Итоговый порядок для модели — [..., initial_context, last_real_user, summary] или [..., initial_context, summary]. Summary всегда остаётся последним — это контракт с обученной моделью.
Практика: не пытайтесь положить что-то «после» последнего user message — harness всё равно переложит. Размещайте контекстные правила внутри initial_context блоков (env, agents.md), а не как trailing user-reminder в конце истории — после компакции их там не будет.
┌─────────────────────────────────────────────────────────────┐
│ base_instructions ← инварианты: стиль, безопасность, │
│ рамки поведения │
│ (пересобираются каждый turn) │
├─────────────────────────────────────────────────────────────┤
│ initial_context ← env, AGENTS.md, постоянные skill- │
│ metadata │
│ (реинжектируются после компакции) │
├─────────────────────────────────────────────────────────────┤
│ skill injections ← модульные детальные ruleset'ы, │
│ активируются @-упоминанием │
│ (не живут в постоянном контексте) │
├─────────────────────────────────────────────────────────────┤
│ developer messages ← runtime policy (approval/sandbox) │
│ (волатильные, лимит 5000 байт / │
│ 100 prefixes, усекаются молча, │
│ выбрасываются при компакции) │
├─────────────────────────────────────────────────────────────┤
│ user messages ← task-специфика │
│ (последние 20 000 токенов │
│ переживают компакцию) │
└─────────────────────────────────────────────────────────────┘- пережило компакцию → оно в
base_instructions, initial_context, или в последних 20k user-токенов; - не усечено silent-truncate'ом → developer-prefix-list ≤ 5000 байт и ≤ 100 штук;
- появляется при нужном контексте → завёрнуто в стандартный
SKILL_FRAGMENTи активируется упоминанием.
Если хотя бы одно не выполнено — модель читает урезанную версию ваших инструкций, и чаще всего об этом никто не узнаёт.
knowledge/
├── SRC-0001/ ... SRC-0018/ # 18 модулей, в каждом:
│ ├── rules.json # инварианты и формулы
│ ├── structural.json # сущности и отношения
│ └── use-case.json # сценарии
├── scaffold_index.json # плоский индекс composition ID по SRC
├── graph.json # рёбра triggers / depends_on / contains
└── README.mdКомпозиции связаны ссылками вида →triggers SRC-0011/uc.sub/auto-compact-inline — по ним можно переходить через scaffold_index.json и graph.json.
Методика запросов к спеке (grep + jq-рецепты): см. HOW-TO-QUERY.md.
English: openai codex harness · codex cli internals · codex agent loop · harness engineering · agent conversation turn lifecycle · tool registry · thread turn item · context compaction · auto-compact · responses compact endpoint · codex app server · prompt engineering reference · AI agent architecture spec · codex reverse engineering · base_instructions priority · initial context injection · SUMMARIZATION_PROMPT · CompactionStrategy::Memento · skill injection · prompt cache key · context window management
Русский: openai codex харнесс · codex cli внутреннее устройство · агентский цикл codex · harness engineering · реверс-инжиниринг codex · спецификация harness · жизненный цикл turn агента · tool registry codex · компакция контекста · автокомпакция · база инструкций агента · инструкции для AI-агентов · промпт-инжиниринг для агентов · управление контекстным окном · разработка AI-агентов · как работает codex · архитектура AI-агентов · harness для LLM-агентов · skill-инжекция · initial context инжекция
Reference specification for Codex harness (OpenAI Codex CLI) extracted as a knowledge graph: rules, use-cases, structural entities across 18 SRC modules covering protocol, session state, agent core, turn context, and tools registry. Companion to OpenAI's «Unrolling the Codex agent loop» series. Use cases: writing agent instructions, building your own agent harness, reverse-engineering compaction strategies, understanding turn lifecycle.
Спецификация harness Codex CLI (OpenAI), извлечённая как knowledge graph: 1 028 правил, 588 структур, 325 use-cases по 18 SRC-модулям — протокол, состояние сессии, ядро агента, управление контекстом, tools registry. Компаньон к серии статей OpenAI о harness-engineering. Для кого: авторы инструкций и промптов AI-агентов, разработчики собственных harness-систем, все, кто изучает архитектуру агентов-кодеров.
Если спека оказалась вам полезна — поставьте звезду репозиторию. Это помогает другим разработчикам агентов и авторам инструкций находить её в поиске GitHub.
Ваш фидбек и предложения по расширению покрытия (новые SRC-модули, уточнения формул, недостающие edge-кейсы) приветствуются в Issues.