Skip to content

Codex CLI Integration

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.

WorkflowIDNodesTriggerRole
Codex Auth WatchdogPaBIkK76OPcHQr535Schedule (6h)Watches auth.json freshness and alerts via Notification Hub
Codex Reauth FlowsLAIrqJDGRUE6Jmj5Execute WorkflowStarts a device-auth session and sends URL + code to Telegram
Codex Reauth Callback ActionsxpHr32uMtdEE0M3Q8Execute WorkflowHandles [Done] / [Cancel] callbacks after reauth
Codex Progress Handlerw8r9JcpArIElZxRe11Webhook /codex-progressBuffers Codex streaming and edits the Telegram message
EndpointMethodConsumer
/api/codex/auth/statusGETAuth Watchdog
/api/codex/reauthPOSTReauth Flow
/api/codex/reauth/{id}/statusGETCallback Actions ([Done])
/api/codex/reauth/{id}DELETECallback Actions ([Cancel])
/webhook/codex-progress (N8N)POSTCodex provider (streaming)

Codex Auth Watchdog · 5 nodes

HTTP GET /auth/status

HTTP POST /reauth

callback Done / Cancel

HTTP GET /reauth/id/status

HTTP DELETE /reauth/id

POST /webhook/codex-progress

Codex Progress Handler · 11 nodes

Webhook /codex-progress

Parse Body

DT Get Buffer

Code Decide

Edit Message

Send New Message

DT Update Buffer

Codex Reauth Callback Actions · 8 nodes

Execute Workflow Trigger

Answer Callback

Switch Action

Check Reauth Status

Cancel Reauth Session

Edit Original Message

Codex Reauth Flow · 5 nodes

Execute Workflow Trigger

Start Reauth Session

Format Reauth Message

Send Reauth Prompt

Return Reauth Started

Schedule 6h

Get Codex Auth Status

Evaluate Auth Health

IF Should Alert

Call Notification Hub

cli-ollama

FastAPI · /api/codex/*

Telegram bot

user chat


ProblemWithout the familyWith the family
Silent expirationEvery AI request fails with no signalWatchdog alerts on D-2 and D-0 before expiry
Manual SSH reauthVPS connection + docker exec + copy-paste the codeTelegram button + device-code pushed automatically
Out-of-container spawnCodex CLI launched on the host writes to the wrong ~/.codexIn-container spawn writes to /home/cli/.codex/auth.json
Vague typed errors”subprocess failed” non-actionableTyped auth_expired error detected in CLI Ollama
Lost Codex streamingLong run = Telegram radio silence for 30s+Edit-in-place via DT buffer
No way to cancelZombie device-auth session if abandoned[Cancel] kills the subprocess via DELETE /reauth/{id}

Why a Watchdog instead of alerting on first error?

Section titled “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:

ThresholdSeverityAction
auth.json missingcriticalImmediate alert with codex login --device-auth command
age > 8 dayscriticalReauth strongly recommended
age > 6 dayswarningMonitor, reauth soon
Unreadable last_refreshwarningCorrupted 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?

Section titled “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.

CommitImprovement
edfcf79Typed auth_expired error in CLI Ollama (detection instead of subprocess error)
9771a97In-container device-auth spawn + auth missing detection
ba0f7aeBump n8n-exports with reauth fixes
32c3282Streaming webhook /webhook/codex-progress on the provider side
7ee7dbdCodex chat edit-in-place + real-time Telegram streaming

WorkflowIDNodesRole
Codex Auth WatchdogPaBIkK76OPcHQr5356h cron, check /api/codex/auth/status, alert Hub
Codex Reauth FlowsLAIrqJDGRUE6Jmj5Spawn device-auth, push Telegram with URL + code
Codex Reauth Callback ActionsxpHr32uMtdEE0M3Q8Switch on callback, confirm or cancel the session
Codex Progress Handlerw8r9JcpArIElZxRe11DT buffer + edit-in-place of the Telegram message

Linear chain: Schedule 6hGet Codex Auth Status (HTTP GET) → Evaluate Auth Health (Code) → IF Should AlertCall Notification Hub (Execute Workflow).

The Evaluate Auth Health node applies two thresholds:

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 then delegates dedup, quiet hours and Telegram routing. The watchdog only cares about evaluation, never about transport.

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:

{
"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.

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

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:

{
"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.

SurfaceProtection
/api/codex/*Internal endpoint on the ai-internal network, not exposed through Caddy
/webhook/codex-progressInternal N8N webhook, blocked by Caddy from outside
codex login --device-auth spawnRun inside the cli-ollama container with ~/.codex isolated from host
Reauth session TTL600 seconds — beyond that the subprocess is killed automatically

LimitImpactMitigation
Single-instance watchdogOnly one Codex install supervisedSufficient for solo VPS usage
No automatic reauthUser still has to clickOAuth security: device-code mandates a human
Non-sharded DT bufferSingle active Codex conversation recommendedFor multi-user, partition by chatId + messageId
No Prometheus metricNo Grafana dashboard on Codex healthTODO: export codex_auth_age_seconds from CLI Ollama
Best-effort cancelIf the subprocess is blocked on stdin, SIGTERM may take secondsThe 600s TTL guarantees eventual release

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

  • Glossary — Device-code, Webhook, Buffer