--- title: Codex CLI Integration url: https://blog.guigpap.com/en/workflows/codex-cli-integration/ url_md: https://blog.guigpap.com/en/workflows/codex-cli-integration.md category: automation date: '2026-05-19' maturite: production techno: - n8n - telegram - claude application: - automation - operations --- # Codex CLI Integration > N8N workflow family that supervises Codex CLI authentication, drives device-code reauth and streams progress to Telegram ## 1. What? — Definition and context **Codex CLI Integration** is a family of four N8N workflows that industrialises usage of OpenAI's Codex CLI inside the `ai-stack/cli-ollama` stack. Codex became the default provider for CLI Ollama (commit `195d432`): without automation around its authentication and streaming, the AI tooling would break silently on the first OAuth session expiration. > **Note - Why a family of workflows?** > > Codex CLI authenticates via OAuth device-code. The session refreshes by reading `~/.codex/auth.json`, but expires after a few days of inactivity. A single silent expiration cuts off every Telegram agent, the IA Router, approval sub-workflows and the MCP chain. The family exists to detect, restart, confirm and stream Codex end-to-end. ### Scope | Workflow | ID | Nodes | Trigger | Role | |----------|----|-------|---------|------| | **Codex Auth Watchdog** | `PaBIkK76OPcHQr53` | 5 | Schedule (6h) | Watches `auth.json` freshness and alerts via Notification Hub | | **Codex Reauth Flow** | `sLAIrqJDGRUE6Jmj` | 5 | Execute Workflow | Starts a device-auth session and sends URL + code to Telegram | | **Codex Reauth Callback Actions** | `xpHr32uMtdEE0M3Q` | 8 | Execute Workflow | Handles `[Done]` / `[Cancel]` callbacks after reauth | | **Codex Progress Handler** | `w8r9JcpArIElZxRe` | 11 | Webhook `/codex-progress` | Buffers Codex streaming and edits the Telegram message | ### CLI Ollama endpoints consumed | Endpoint | Method | Consumer | |----------|--------|----------| | `/api/codex/auth/status` | GET | Auth Watchdog | | `/api/codex/reauth` | POST | Reauth Flow | | `/api/codex/reauth/{id}/status` | GET | Callback Actions ([Done]) | | `/api/codex/reauth/{id}` | DELETE | Callback Actions ([Cancel]) | | `/webhook/codex-progress` (N8N) | POST | Codex provider (streaming) | ### Visual architecture ```mermaid flowchart TD subgraph Watch["Codex Auth Watchdog · 5 nodes"] direction TB Sched["Schedule 6h"] Fetch["Get Codex Auth Status"] Eval["Evaluate Auth Health"] IfAlert["IF Should Alert"] Hub["Call Notification Hub"] end subgraph Reauth["Codex Reauth Flow · 5 nodes"] direction TB RTrig["Execute Workflow Trigger"] Start["Start Reauth Session"] Fmt["Format Reauth Message"] Send["Send Reauth Prompt"] Done["Return Reauth Started"] end subgraph CB["Codex Reauth Callback Actions · 8 nodes"] direction TB CTrig["Execute Workflow Trigger"] Ack["Answer Callback"] SwAct["Switch Action"] CheckS["Check Reauth Status"] Cancel["Cancel Reauth Session"] Edit["Edit Original Message"] end subgraph Prog["Codex Progress Handler · 11 nodes"] direction TB PHook["Webhook /codex-progress"] Parse["Parse Body"] Buf["DT Get Buffer"] Decide["Code Decide"] EditMsg["Edit Message"] NewMsg["Send New Message"] Upd["DT Update Buffer"] end CLI["cli-ollama
FastAPI · /api/codex/*"] TG["Telegram bot
user chat"] Watch --> Hub --> TG Watch -.->|HTTP GET /auth/status| CLI Reauth -->|HTTP POST /reauth| CLI Reauth --> TG TG -->|callback Done / Cancel| CB CB -->|HTTP GET /reauth/id/status| CLI CB -->|HTTP DELETE /reauth/id| CLI CB --> TG CLI -->|POST /webhook/codex-progress| Prog Prog --> TG ``` --- ## 2. Why? — Stakes and motivations ### Problems solved | Problem | Without the family | With the family | |---------|--------------------|------------------| | **Silent expiration** | Every AI request fails with no signal | Watchdog alerts on D-2 and D-0 before expiry | | **Manual SSH reauth** | VPS connection + `docker exec` + copy-paste the code | Telegram button + device-code pushed automatically | | **Out-of-container spawn** | Codex CLI launched on the host writes to the wrong `~/.codex` | In-container spawn writes to `/home/cli/.codex/auth.json` | | **Vague typed errors** | "subprocess failed" non-actionable | Typed `auth_expired` error detected in CLI Ollama | | **Lost Codex streaming** | Long run = Telegram radio silence for 30s+ | Edit-in-place via DT buffer | | **No way to cancel** | Zombie device-auth session if abandoned | `[Cancel]` kills the subprocess via `DELETE /reauth/{id}` | ### Why a Watchdog instead of alerting on first error? Discovering expiration at the moment of a user call degrades UX: the Telegram message returns a cryptic error and the user must dig into documentation. The Watchdog runs every 6 hours and anticipates: | Threshold | Severity | Action | |-----------|----------|--------| | `auth.json` missing | `critical` | Immediate alert with `codex login --device-auth` command | | `age > 8 days` | `critical` | Reauth strongly recommended | | `age > 6 days` | `warning` | Monitor, reauth soon | | Unreadable `last_refresh` | `warning` | Corrupted file to inspect | The 6/8 day thresholds provide a comfortable ~48h window between first alert and actual failure. ### Why extract the Callback Handler from the Reauth Flow? Reauth Flow sends the Telegram message, but the `[Done]` / `[Cancel]` callback is asynchronous: the user may click 10 minutes later. Splitting it into a dedicated sub-workflow (8 nodes) follows the same logic as `NH Callback Handler` (#276): early routing through the Telegram Orchestrator, dedup bypass, no shared state. ### Recent evolutions | Commit | Improvement | |--------|-------------| | `edfcf79` | Typed `auth_expired` error in CLI Ollama (detection instead of subprocess error) | | `9771a97` | In-container device-auth spawn + `auth missing` detection | | `ba0f7ae` | Bump n8n-exports with reauth fixes | | `32c3282` | Streaming webhook `/webhook/codex-progress` on the provider side | | `7ee7dbd` | Codex chat edit-in-place + real-time Telegram streaming | --- ## 3. How? — Technical implementation ### Components | Workflow | ID | Nodes | Role | |----------|----|-------|------| | Codex Auth Watchdog | `PaBIkK76OPcHQr53` | 5 | 6h cron, check `/api/codex/auth/status`, alert Hub | | Codex Reauth Flow | `sLAIrqJDGRUE6Jmj` | 5 | Spawn device-auth, push Telegram with URL + code | | Codex Reauth Callback Actions | `xpHr32uMtdEE0M3Q` | 8 | Switch on callback, confirm or cancel the session | | Codex Progress Handler | `w8r9JcpArIElZxRe` | 11 | DT buffer + edit-in-place of the Telegram message | ### Codex Auth Watchdog (5 nodes) Linear chain: `Schedule 6h` → `Get Codex Auth Status` (HTTP GET) → `Evaluate Auth Health` (Code) → `IF Should Alert` → `Call Notification Hub` (Execute Workflow). The `Evaluate Auth Health` node applies two thresholds: ```javascript var WARNING_AGE = 6 * 86400; // 6 days var CRITICAL_AGE = 8 * 86400; // 8 days if (!s.exists) { severity = 'critical'; title = 'Codex auth missing'; } else if (age > CRITICAL_AGE) { severity = 'critical'; } else if (age > WARNING_AGE) { severity = 'warning'; } ``` The call to the [Notification Hub](/en/workflows/notification-hub/) then delegates dedup, quiet hours and Telegram routing. The watchdog only cares about evaluation, never about transport. > **Tip - Schedule trigger at 6 hours** > > A 6-hour cron yields 4 checks per day. Combined with the 6-day threshold, the user receives at least 8 `warning` alerts before `auth.json` hits 8 days and escalates to `critical` — leaving ~48h of headroom to grab a terminal. ### Codex Reauth Flow (5 nodes) Triggered via Execute Workflow (from a conversational agent or a `/codex-reauth` command). The `Start Reauth Session` node sends a `POST http://cli-ollama:11434/api/codex/reauth`: ```json { "reauth_id": "rau_xxx", "device_url": "https://auth.openai.com/device", "user_code": "ABCD-EFGH", "host_command": "docker exec -it cli-ollama codex login --device-auth", "ttl_seconds": 600 } ``` The `Format Reauth Message` node builds a Telegram message with the inline keyboard `[Open URL]` `[Done]` `[Cancel]`. `Send Reauth Prompt` sends the message, `Return Reauth Started` returns the `reauth_id` to the calling workflow so it can correlate the upcoming callback. ### Codex Reauth Callback Actions (8 nodes) Routed from the Telegram Orchestrator whenever `callback_data` starts with `codex_reauth_`. Chain: 1. `Execute Workflow Trigger` — receives `chatId`, `messageId`, `callbackData`, `reauthId`. 2. `Answer Callback` — closes the Telegram spinner immediately. 3. `Switch Action` — `done` vs `cancel`. 4. `done` branch → `Check Reauth Status` (GET `/api/codex/reauth/{id}/status`) → `Format Done Result`. 5. `cancel` branch → `Cancel Reauth Session` (DELETE `/api/codex/reauth/{id}`) → `Format Cancel Result`. 6. Both converge on `Edit Original Message` (Telegram edit) which replaces the prompt with the result. > **Caution - Cancel idempotency** > > `DELETE /api/codex/reauth/{id}` kills the Codex CLI subprocess. If the user taps `[Done]` after tapping `[Cancel]`, the `GET /status` returns `404 reauth_session_not_found`. The `Format Done Result` node must handle this case to avoid re-throwing. ### Codex Progress Handler (11 nodes) When the Codex provider (`cli-ollama/app/services/providers/codex.py`) emits a progress event, it POSTs to `http://n8n:5678/webhook/codex-progress` with: ```json { "chatId": "5883063462", "messageId": 12345, "sessionId": "tg_xxx", "progressText": "Reading 3 files...", "isFinal": false } ``` Handler chain: 1. `Webhook Trigger` (path `codex-progress`). 2. `Parse Body` — extracts `chatId`, `messageId`, `progressText`. 3. `DT Get Buffer` — Data Table keyed by `messageId` (edit state). 4. `IF Buffer Exists` — first progress event or continuation? 5. `Code Decide` — decides between `edit` (append to buffer), `split` (new message if Telegram limit exceeded) or `skip`. 6. `IF Should Edit` / `IF Need Split` — routing by decision. 7. `Edit Message` (Telegram) or `Send New Message`. 8. `Prep DT Update` + `DT Update Buffer` — persists the new state for the next progress event. The buffer avoids back-to-back Telegram edits hitting rate limits and produces a "live" effect without saturating the API. ### Security | Surface | Protection | |---------|------------| | `/api/codex/*` | Internal endpoint on the `ai-internal` network, not exposed through Caddy | | `/webhook/codex-progress` | Internal N8N webhook, blocked by Caddy from outside | | `codex login --device-auth` spawn | Run inside the `cli-ollama` container with `~/.codex` isolated from host | | Reauth session TTL | 600 seconds — beyond that the subprocess is killed automatically | --- ## 4. What if? — Outlook and limits ### Current limits | Limit | Impact | Mitigation | |-------|--------|------------| | **Single-instance watchdog** | Only one Codex install supervised | Sufficient for solo VPS usage | | **No automatic reauth** | User still has to click | OAuth security: device-code mandates a human | | **Non-sharded DT buffer** | Single active Codex conversation recommended | For multi-user, partition by `chatId + messageId` | | **No Prometheus metric** | No Grafana dashboard on Codex health | TODO: export `codex_auth_age_seconds` from CLI Ollama | | **Best-effort cancel** | If the subprocess is blocked on stdin, SIGTERM may take seconds | The 600s TTL guarantees eventual release | ### Evolution scenarios **If multiple providers must be supervised**: - Generalise the Watchdog into `AI Auth Watchdog` with a `provider=codex|gemini|claude` parameter - Unified endpoints `/api/auth/status?provider=...` - A single cron for every provider **If proactive pre-auth is wanted**: - A D-1 cron task that starts the device-auth session early and pushes the code in advance - The user prepares the reauth without pressure **If the progress volume explodes**: - Throttle at the provider (at most one update every 2s) - Redis aggregation (key `progress:{messageId}`) then periodic flush - Alternate `ntfy` output for long background runs **If multi-user**: - A `codex_sessions` Data Table keyed by `chatId` - Each user gets their own `auth.json` (not possible with the current CLI) - Workaround: a shared Codex account + session_id traceability in Redis --- ## Related pages ### Infrastructure - [N8N in queue mode](/en/infrastructure/n8n-queue-mode/) — Backend that runs the family - [Notify Stack](/en/infrastructure/notify-stack/) — DIUN and ntfy downstream of the Watchdog ### Workflows - [Notification Hub](/en/workflows/notification-hub/) — Target of watchdog alerts - [Telegram Orchestrator](/en/workflows/telegram-orchestrator/) — Routes `codex_reauth_*` callbacks - [Conversational system](/en/workflows/systeme-conversationnel/) — Main consumer of the Codex provider - [Question Hub](/en/workflows/question-hub/) — Asynchronous Telegram interaction pattern ### Reference - [Glossary](/en/reference/glossary/) — Device-code, Webhook, Buffer ## Metadonnees agent - Cet article est issu du blog GuiGPaP Lab. - Contexte global du blog: https://blog.guigpap.com/llms.txt - Contact auteur: https://odoo.guigpap.com/mon-cv - Licence: CC-BY-SA 4.0