{"slug": "codex-will-answer-its-own-question-if-you-re-not-looking-here-s-how-to-catch-it", "title": "Codex will answer its own question if you're not looking. Here's how to catch it", "summary": "A developer published a workaround for OpenAI Codex's Plan mode, where the agent proceeds with its own recommended option if a user doesn't answer a question quickly, an issue that has drawn 200+ upvotes on GitHub. The script tails Codex's JSONL session rollouts under ~/.codex/sessions and flags any request_user_input tool call lacking a matching function_call_output, firing a macOS notification (or an ntfy push) when the agent is blocked. The author notes that PermissionRequest hooks don't cover questions, that request_user_input_async calls should be skipped, and that log formats aren't a stable API.", "body_md": "If you use Codex in Plan mode, you've probably seen this: Codex stops to ask you something (\"Which folder should I refactor?\"), and if you don't answer quickly it goes ahead with its own recommended option. People have asked for a way to turn that off. The [issue](https://github.com/openai/codex/issues/28969) has 200+ 👍.\n\nUntil there's a setting, the practical fix is to **find out the moment Codex asks**, even when the terminal is behind three other windows or you're on the couch.\n\nCodex hooks cover `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PermissionRequest`, `PostToolUse`, `Stop` and a few others ([docs](https://developers.openai.com/codex/hooks)). `PermissionRequest` fires for approvals (shell escalation, network), **not** for questions. So a `notify`/hook setup that pings you on approvals stays silent when Codex asks a question.\n\nEvery Codex session writes a JSONL rollout under `~/.codex/sessions/YYYY/MM/DD/`. A question is a tool call named `request_user_input`:\n\n```\n{\"type\":\"response_item\",\"payload\":{\"type\":\"function_call\",\"name\":\"request_user_input\",\n \"arguments\":\"{\\\"questions\\\":[{\\\"header\\\":\\\"Scope\\\",\\\"question\\\":\\\"Which folder should I refactor?\\\"}],\\\"isBlocking\\\":true}\",\n \"call_id\":\"call_…\"}}\n```\n\nWhen you answer, a `function_call_output` with the same `call_id` follows. So **a `request_user_input` call with no output yet = Codex is waiting on you.**\n\nTwo caveats from checking my own logs:\n\n`request_user_input_async`. It gets `{\"accepted\":true}` back within a fraction of a second and Codex keeps working, so it isn't a blocking wait. Skip it.`protocol/src/request_user_input.rs`) and matches the envelope in my logs, but log formats aren't a stable API, so expect to adjust it someday.\n\n``` bash\n#!/usr/bin/env python3\n\"\"\"Notify (macOS) when Codex is blocked on a question you haven't answered yet.\"\"\"\nimport json, os, subprocess, time, glob\n\nROOT = os.path.expanduser(\"~/.codex/sessions\")\nseen = set()\n\ndef pending(path):\n    calls, done = {}, set()\n    with open(path, errors=\"ignore\") as f:\n        f.seek(max(0, os.path.getsize(path) - 256_000))   # the tail is enough\n        for line in f:\n            if '\"response_item\"' not in line:\n                continue\n            try:\n                p = json.loads(line)[\"payload\"]\n            except (ValueError, KeyError):\n                continue\n            if p.get(\"type\") == \"function_call_output\":\n                done.add(p.get(\"call_id\"))\n            elif p.get(\"type\") == \"function_call\" and p.get(\"name\") == \"request_user_input\":\n                try:\n                    q = json.loads(p.get(\"arguments\") or \"{}\")[\"questions\"][0]\n                    text = q.get(\"question\") or q.get(\"header\") or \"\"\n                except (ValueError, KeyError, IndexError):\n                    text = \"\"\n                calls[p.get(\"call_id\")] = text\n    return {c: t for c, t in calls.items() if c not in done}\n\ndef notify(text):\n    msg = (text or \"Codex is waiting for your answer\")[:180].replace('\"', \"'\")\n    subprocess.run([\"osascript\", \"-e\",\n        f'display notification \"{msg}\" with title \"Codex has a question\" sound name \"Glass\"'])\n\nwhile True:\n    for path in glob.glob(f\"{ROOT}/*/*/*/*.jsonl\"):\n        if time.time() - os.path.getmtime(path) > 1800:   # only live sessions\n            continue\n        for cid, text in pending(path).items():\n            if cid not in seen:\n                seen.add(cid)\n                notify(text)\n    time.sleep(3)\n```\n\nRun it in a spare terminal (`python3 codex-question-alert.py`). It only reads files that changed in the last 30 minutes and only the last 256 KB of each, so it's cheap. I tested it against a synthetic log (one unanswered question, one answered) and against a week of my real logs (no false alarms).\n\nTo get it on your phone, swap `notify()` for a `curl` to an [ntfy](https://ntfy.sh) topic.\n\nI build [Lidnight](https://lidnight.app/en/), a menu bar app that keeps a MacBook awake (lid closed, even on battery) while Claude Code and Codex work and lets it sleep when they're done. Version 1.7.68 does the check above on its own: when Codex is blocked on a question, you get a Mac notification and a phone push (if you've linked one) right away, with the question text. It can't answer for you. It just makes sure you see the question in time.\n\nLidnight is free (AI Auto mode) with a one-time Pro; launch price is 50% off through Oct 31. `brew install whereisdw/tap/lidnight`", "url": "https://wpnews.pro/news/codex-will-answer-its-own-question-if-you-re-not-looking-here-s-how-to-catch-it", "canonical_source": "https://dev.to/dawonlee/codex-will-answer-its-own-question-if-youre-not-looking-heres-how-to-catch-it-3gb8", "published_at": "2026-10-18 10:07:17+00:00", "updated_at": "2026-10-18 10:13:28.137318+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-products"], "entities": ["OpenAI", "Codex", "GitHub", "ntfy", "Lidnight"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/codex-will-answer-its-own-question-if-you-re-not-looking-here-s-how-to-catch-it", "markdown": "https://wpnews.pro/news/codex-will-answer-its-own-question-if-you-re-not-looking-here-s-how-to-catch-it.md", "text": "https://wpnews.pro/news/codex-will-answer-its-own-question-if-you-re-not-looking-here-s-how-to-catch-it.txt", "jsonld": "https://wpnews.pro/news/codex-will-answer-its-own-question-if-you-re-not-looking-here-s-how-to-catch-it.jsonld"}}