---
doc_id: API-CK8S-0001
type: api-contract
title: "kodex — API Contract Overview"
status: active
owner_role: SA
created_at: 2026-02-06
updated_at: 2026-03-16
related_issues: [1, 19, 100, 154, 155, 175, 247, 248, 249, 274, 500, 514]
related_prs: []
approvals:
  required: ["Owner"]
  status: approved
  request_id: "owner-2026-02-19-full-docset"
  approved_by: "ai-da-stas"
  approved_at: 2026-02-19
---

# API Contract Overview: kodex

## TL;DR
- Тип API: REST (public webhook + staff/private), internal gRPC между edge и control-plane.
- Для agent runtime добавлен internal MCP StreamableHTTP endpoint в `control-plane` с run-bound bearer auth.
- Аутентификация: GitHub OAuth login + short-lived JWT в API gateway + project RBAC.
- Версионирование: `/api/v1/...`.
- Основные операции текущего среза: webhook ingest (public) + staff/private operations для auth, project/repository/user/run/learning-mode.
- Для external/staff транспорта в S2 Day1 внедрён contract-first OpenAPI (validation + backend/frontend codegen).
- В MVP completion (S2 Day6 + S3) добавляются API-контракты для runtime debug observability и MCP control tools orchestration.
- Для multi-repo режима (Issue #100, design) планируются staff/private контракты composition preview и docs sources resolve.

## Спецификации (source of truth)
- OpenAPI (api-gateway): `services/external/api-gateway/api/server/api.yaml`
- gRPC proto: `proto/kodex/controlplane/v1/controlplane.proto`
- AsyncAPI (если есть): `services/external/api-gateway/api/server/asyncapi.yaml` (webhook/event payloads)

## Состояние MCP после S2 Day6 / S3 target
- В `control-plane` поднят MCP StreamableHTTP endpoint: `/mcp`.
- Аутентификация MCP: short-lived run-bound bearer token.
- Внутренний gRPC контракт расширен RPC `IssueRunMCPToken` для выдачи MCP токена worker-у перед запуском run pod.
- MCP-слой в текущем MVP baseline покрывает:
  - label-операции (`github_labels_*`);
  - прогресс-статусы агента (`run_status_report`, короткий статус до 100 символов);
  - `secret.sync.k8s` (deterministic secret sync в Kubernetes);
  - `database.lifecycle` (`create/delete/describe`);
  - `owner.feedback.request` (options + custom answer).
- Для внешних approver/executor адаптеров и built-in user interactions активированы callback endpoint'ы:
  - `POST /api/v1/mcp/approver/callback`;
  - `POST /api/v1/mcp/executor/callback`.
  - `POST /api/v1/mcp/interactions/callback`.
- Базовые MCP label-инструменты:
  - `github_labels_list`;
  - `github_labels_add`;
  - `github_labels_remove`;
  - `github_labels_transition` (remove+add).
- Базовый MCP инструмент обратной связи по прогрессу:
  - `run_status_report` (агент публикует текущий короткий статус выполнения в выбранной locale).
  - последние 3 дедуплицированные группы `run_status_report` выводятся в run service-comment в GitHub в компактном inline-виде с временем.
- Остальные GitHub/Kubernetes runtime-операции выполняются напрямую из agent pod через `gh`/`kubectl` в рамках RBAC/policy.

## Модель доступа GitHub для агентного pod (S2 Day4)
- Агентный pod получает отдельный `KODEX_GIT_BOT_TOKEN`.
- Токен используется напрямую через `gh` и `git`:
  - clone/fetch/commit/push в рабочую ветку;
  - issue/PR/review/comments операции.
- Минимально необходимые scopes для bot-token:
  - Read: metadata;
  - Read/Write: code, commit statuses, discussions, issues, pages, pull requests.
- Через MCP выполняются label transitions и control tools, требующие governance approvals и единый audit контур.

## Модель доступа Kubernetes для агентного pod (S2 Day4)
- Для `full-env` runner формирует `~/.kube/config` из namespaced ServiceAccount и экспортирует `KUBECONFIG`.
- Агент может выполнять через `kubectl` почти все namespaced операции runtime-диагностики и дебага.
- Исключение: прямой доступ к `secrets` (read/write) запрещён RBAC.
- Управление секретами через MCP/control-plane является частью MVP completion scope.

## Internal agent callbacks (S2 Day4)
- Для agent-runner добавлены внутренние gRPC callback RPC в `control-plane`:
  - `UpsertAgentSession` — CAS-like upsert session snapshot c `snapshot_version`/`snapshot_checksum` и защитой от replay/data loss;
  - `GetLatestAgentSession` — latest session by `(repository_full_name, branch_name, agent_key)` вместе с version/checksum metadata;
  - `InsertRunFlowEvent` — append Day4 run events.
- Авторизация callback'ов: run-bound MCP bearer token в gRPC metadata (`authorization: Bearer ...`), проверка через `VerifyRunToken`.
- Для `api-gateway -> control-plane` interaction ingress добавлен отдельный internal RPC `SubmitInteractionCallback`;
  callback bearer token также прокидывается в gRPC metadata и валидируется по `token subject == mcp-interaction-callback:<interaction_id>`,
  токен живёт deadline-aware и сохраняет post-deadline grace для deterministic `duplicate|expired` classification,
  чтобы thin-edge не держал локальную interaction state/policy.
- Эти RPC внутренние (service-to-service), не входят в public/staff OpenAPI контракт.

## Состояние OpenAPI после S2 Day1
- OpenAPI-спека (`services/external/api-gateway/api/server/api.yaml`) покрывает все активные external/staff endpoint'ы текущего среза.
- В `api-gateway` включена runtime валидация request/response по OpenAPI (через `kin-openapi`) для `/api/*`.
- Включён backend codegen:
  - `make gen-openapi-go`
  - output: `services/external/api-gateway/internal/transport/http/generated/openapi.gen.go`
- Включён frontend codegen:
  - `make gen-openapi-ts`
  - output: `services/staff/web-console/src/shared/api/generated/**`
- В CI добавлена проверка консистентности codegen:
  - `deploy/base/kodex/codegen-check-job.yaml.tpl` (`make gen-openapi` + `git diff --exit-code`).

## Endpoints / Methods (текущий и MVP target срез)
| Operation | Method | Path | Auth | Notes |
|---|---|---|---|---|
| Ingest GitHub webhook | POST | `/api/v1/webhooks/github` | webhook signature | idempotency по `X-GitHub-Delivery`, response status: `accepted|duplicate|ignored` |
| MCP approver callback | POST | `/api/v1/mcp/approver/callback` | callback token | external approver decision (`approved|denied|expired|failed|applied`) |
| MCP executor callback | POST | `/api/v1/mcp/executor/callback` | callback token | external executor decision (`approved|denied|expired|failed|applied`) |
| MCP interaction callback | POST | `/api/v1/mcp/interactions/callback` | callback bearer token | built-in user interaction callback (`applied|duplicate|stale|expired|invalid`) |
| Start GitHub OAuth | GET | `/api/v1/auth/github/login` | public | redirect |
| Complete GitHub OAuth callback | GET | `/api/v1/auth/github/callback` | public | set auth cookie |
| Logout | POST | `/api/v1/auth/logout` | staff JWT | clears auth cookies |
| Get current principal | GET | `/api/v1/auth/me` | staff JWT | staff/private |
| List projects | GET | `/api/v1/staff/projects` | staff JWT | RBAC filtered |
| Upsert project | POST | `/api/v1/staff/projects` | staff JWT + admin | create/update by slug |
| Get project | GET | `/api/v1/staff/projects/{project_id}` | staff JWT | details |
| Delete project | DELETE | `/api/v1/staff/projects/{project_id}` | staff JWT + admin | hard delete |
| List runs | GET | `/api/v1/staff/runs` | staff JWT | run list |
| Get run | GET | `/api/v1/staff/runs/{run_id}` | staff JWT | run details |
| Cancel run | POST | `/api/v1/staff/runs/{run_id}/cancel` | staff JWT + project write access | idempotent run-level cancel; stops active runtime artifacts, clears wait/resume linkage and writes `run.canceled` flow event |
| List run events | GET | `/api/v1/staff/runs/{run_id}/events` | staff JWT | flow events |
| Run realtime stream | GET | `/api/v1/staff/runs/{run_id}/realtime` | staff JWT | WebSocket upgrade; server sends `snapshot|run|events|logs|error` envelopes |
| List pending approvals | GET | `/api/v1/staff/approvals` | staff JWT | MCP approval queue for privileged actions |
| Resolve approval decision | POST | `/api/v1/staff/approvals/{approval_request_id}/decision` | staff JWT | approve/deny/expire/fail action request |
| List system settings | GET | `/api/v1/staff/system-settings` | staff JWT + admin | typed platform settings catalog with effective values |
| Get system setting | GET | `/api/v1/staff/system-settings/{setting_key}` | staff JWT + admin | one typed platform setting |
| Update boolean system setting | PUT | `/api/v1/staff/system-settings/{setting_key}` | staff JWT + admin | update persisted runtime switch value |
| Reset system setting to default | POST | `/api/v1/staff/system-settings/{setting_key}/reset` | staff JWT + admin | restore catalog default and bump version |
| System settings realtime stream | GET | `/api/v1/staff/system-settings/realtime` | staff JWT + admin | WebSocket snapshots for staff configuration UI |
| List run learning feedback | GET | `/api/v1/staff/runs/{run_id}/learning-feedback` | staff JWT | educational feedback |
| Stream run logs | GET | `/api/v1/staff/runs/{run_id}/logs/stream` | staff JWT | live tail (SSE/WebSocket) |
| List run log snapshots | GET | `/api/v1/staff/runs/{run_id}/logs` | staff JWT | historical logs |
| List wait queue | GET | `/api/v1/staff/runs/waits` | staff JWT | `waiting_mcp`/`waiting_owner_review` with reasons |
| List users | GET | `/api/v1/staff/users` | staff JWT | allowed users |
| Create user | POST | `/api/v1/staff/users` | staff JWT + admin | allowlist entry |
| Delete user | DELETE | `/api/v1/staff/users/{user_id}` | staff JWT + admin | remove allowlist entry |
| List project members | GET | `/api/v1/staff/projects/{project_id}/members` | staff JWT | members and roles |
| Upsert project member | POST | `/api/v1/staff/projects/{project_id}/members` | staff JWT + admin | by `user_id` or `email` |
| Delete project member | DELETE | `/api/v1/staff/projects/{project_id}/members/{user_id}` | staff JWT + admin | remove member |
| Set member learning mode override | PUT | `/api/v1/staff/projects/{project_id}/members/{user_id}/learning-mode` | staff JWT + admin | true/false/null |
| List project repositories | GET | `/api/v1/staff/projects/{project_id}/repositories` | staff JWT | repository bindings |
| Upsert project repository | POST | `/api/v1/staff/projects/{project_id}/repositories` | staff JWT + admin | token encrypted in backend |
| Delete project repository | DELETE | `/api/v1/staff/projects/{project_id}/repositories/{repository_id}` | staff JWT + admin | unbind repository |
| Get project composition | GET | `/api/v1/staff/projects/{project_id}/composition` | staff JWT | planned: resolved topology/root/imports |
| Preview project composition | POST | `/api/v1/staff/projects/{project_id}/composition/preview` | staff JWT + admin | planned: dry-run resolve + validation/errors |
| List project docs sources | GET | `/api/v1/staff/projects/{project_id}/docs/sources` | staff JWT | planned: effective role-aware docs graph |

Примечание:
- маршруты staff runtime debug (`/runs/{run_id}/logs*`, `/runs/waits`) относятся к MVP target и вводятся в Sprint S3.
- `POST /api/v1/staff/runs/{run_id}/cancel` закрывает run-level остановку end-to-end: control-plane переводит run в terminal `canceled`, останавливает активный runtime path и гасит поздние auto-resume/interaction continuation path идемпотентно.
- Product/runtime switches, которые должны применяться без правки deployment env, публикуются через typed staff/private contract `system-settings`; source of truth для effective values находится в `control-plane` и PostgreSQL, а не в runtime manifests.
- будущие маршруты сверх MVP (`docs search/edit`, advanced policy management UI и т.д.) вводятся отдельными эпиками post-MVP.
- маршруты `composition*` и `/docs/sources` относятся к design backlog по Issue #100 и реализуются отдельным `run:dev` циклом.

## Public API boundary (MVP)
- Публично (outside/stable): только `POST /api/v1/webhooks/github`.
- Остальные endpoint'ы — staff/private API, не объявляются как public contract на первой поставке.

## Модель ошибок
- Error codes: `invalid_argument`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `failed_precondition`, `internal`.
- Retries: webhook ingestion safe retry по `delivery_id`/`correlation_id`.
- Rate limits: на external webhook ingress и user API.

## Контракты данных (DTO)
- Основные сущности: user, project, project_member, repository, agent, agent_run, slot, flow_event, document.
- Валидация: schema validation + domain validation.

### Multi-repo DTO extensions (design)
- `repository` DTO расширяется полями:
  - `alias`,
  - `role` (`orchestrator|service|docs|mixed`),
  - `default_ref`,
  - `docs_root_path`.
- `composition preview` response возвращает строго типизированные блоки:
  - `root_repository`,
  - `imports[]` (`repository`, `path`, `ref`, `resolved_commit`),
  - `validation_errors[]`,
  - `effective_services_manifest_hash`.
- `docs sources` response возвращает:
  - `sources[]` (`repository`, `path`, `roles[]`, `optional`, `priority`, `resolved_commit`).

## Learning mode behavior
- Если learning mode активен, для user-initiated задач в prompt/context добавляется mandatory block:
  - объяснить, почему изменение сделано именно здесь;
  - какие преимущества даёт выбранный путь;
  - какие альтернативы рассмотрены и почему хуже в данном контексте.
- После создания/обновления PR worker запускает образовательный post-processing:
  - формирует комментарии по ключевым файлам и (опционально) строкам;
  - сохраняет объяснения в `learning_feedback`;
  - публикует агрегированный PR comment и, при необходимости, line-level comments.
- При выключенном learning mode pipeline работает без образовательных вставок.

## Label and stage policy behavior
- Поддерживаются классы лейблов: `run:*`, `state:*`, `need:*`.
- S2 baseline: активны `run:dev` и `run:dev:revise`.
- S3 target: активируется полный stage-контур `run:intake..run:ops` и `run:self-improve`.
- Trigger/deploy label, инициированный агентом, проходит owner approval до применения.
- `state:*` и `need:*` могут применяться автоматически в рамках project policy.
- Исключение для PR review-flow: webhook `pull_request` с `action=labeled` и label `need:reviewer` запускает reviewer-run в контексте PR.
- Любая операция с label фиксируется в `flow_events` и связывается с `agent_sessions`/`links`.

### Profile-driven next-step action matrix (S5 Day1, Issues #154/#155)
- Source of truth:
  - `docs/product/requirements_machine_driven.md` (FR-053, FR-054);
  - `docs/product/labels_and_trigger_policy.md`;
  - `docs/product/stage_process_model.md`;
  - `docs/architecture/adr/ADR-0008-profile-driven-stage-launch-and-next-step-contract.md`.
- Внутренний ownership:
  - `services/internal/control-plane` владеет profile resolver, stage-path logic, ambiguity-gate и вычислением next-step матрицы;
  - `services/external/api-gateway` и `services/staff/web-console` остаются thin adapters (валидация/RBAC/UX), без доменных правил stage transition.
- Публичный GitHub/service-message контракт публикует не raw resolver state, а список typed действий:
  - `action_kind` (`issue_stage_transition`, `pull_request_label_add`);
  - `target_label`;
  - `display_variant`;
  - `url` (deep-link на `/` с query для confirm-модалки).
- Staff API для этого UX:
  - `POST /api/v1/staff/github/next-step-actions/preview`
  - `POST /api/v1/staff/github/next-step-actions/execute`
- Staff preview/execute response возвращает typed diff:
  - `thread_kind`, `thread_number`, `thread_url`;
  - `removed_labels[]`, `added_labels[]`, `final_labels[]`.
- Ownership сервисных границ:
- Правила детерминизма:
  - внешний action-list формируется только для однозначного `(current_stage, resolver_state, PR context)`;
  - при ambiguity (`0` или `>1` trigger labels) transition блокируется, публикуется remediation и ставится `need:input`;
  - `display_variant` определяет UX-подпись действия, но не заменяет `target_label`.
- Policy/Audit требования:
  - любой transition фиксирует `correlation_id`, actor и `source` (`ui` или `fallback`) в `flow_events`;
  - прямые GitHub label mutations из frontend запрещены;
  - review gate после формирования PR синхронизирует `state:in-review` на PR и на Issue.
- Runtime impact для handover в `run:dev`:
  - расширить typed payload service-message списком next-step действий;
  - добавить preview/execute endpoints и frontend confirm-modal на `/`;
  - сохранить resolver/escalation и ambiguity-stop в `control-plane`.

## MCP approver/executor contract behavior
- Approver/executor интеграции и built-in interaction adapters подключаются по HTTP-контрактам через MCP-слой.
- Telegram (`github.com/codex-k8s/telegram-approver`, `github.com/codex-k8s/telegram-executor`) рассматривается как первый адаптер контракта, но не как единственный канал.
- Контракт должен поддерживать async callbacks и единый `correlation_id` для аудита.
- Для built-in interaction callbacks edge остаётся thin adapter:
  `api-gateway` выполняет bearer auth, schema validation, per-interaction rate limit и typed gRPC bridge,
  а `control-plane` один владеет replay/expired/invalid classification и wait-state/resume semantics.
- Для control tools обязателен `approval_required` режим по policy matrix.
- Для `run:self-improve` в MCP включены read-only diagnostic ручки:
  - `self_improve_runs_list` (page/limit, newest-first),
  - `self_improve_run_lookup` (поиск run по Issue/PR),
  - `self_improve_session_get` (извлечение `codex-cli` session JSON + target path в `/tmp/codex-sessions/...`).
- MCP tools экспонируются как run-scoped каталог:
  - `tools/list` возвращает только ручки, разрешённые для текущего профиля запуска;
  - `tools/call` отклоняет вызовы ручек вне разрешённого профиля.

## Session resume and timeout behavior
- run/session поддерживает paused states `waiting_owner_review` и `waiting_mcp`.
- При `waiting_mcp` timeout-kill не применяется; таймер возобновляется после ответа MCP.
- Для resume используется сохранённый `codex-cli` session snapshot из `agent_sessions`.
- Перезапись snapshot идёт через `snapshot_version`/`snapshot_checksum`: одинаковый replay не теряет данные,
  а stale write получает conflict c `actual_snapshot_version`.

## Prompt locale behavior
- В текущем MVP locale prompt templates берется из platform default `KODEX_AGENT_DEFAULT_LOCALE`.
- Если значение пустое, worker использует `ru`.
- При рендере `agent-runner` нормализует locale к поддержанным значениям:
  - `ru*` -> `ru`
  - `en*` -> `en`
  - все остальное -> `en`
- Для системных агентов baseline включает как минимум `ru` и `en` seed-версии шаблонов.
- Язык, выбранный для prompt locale, обязателен для user-facing коммуникации агента:
  - PR title/body/comments;
  - issue/PR ответы;
  - вызовы feedback-инструментов, включая `run_status_report`.

## Backward compatibility
- Что гарантируем: стабильность `/api/v1` и мягкие additive changes.
- Как деплоим изменения: production deploy -> ручные тесты -> production gate.

## Наблюдаемость
- Логи: structured + correlation_id.
- Метрики: webhook throughput, run latency, slot usage, label approval latency, error rates.
- Трейсы: ingress -> domain -> db/provider/k8s.

## Решения Owner
- Для staff UI/API используется short-lived JWT через API gateway.
- Минимум public API в первой поставке: только webhook ingress.

## Апрув
- request_id: owner-2026-02-06-mvp
- Решение: approved
- Комментарий: API границы и auth-модель MVP утверждены.
