---
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