Skip to content

Codex coding session launches bare (no prompt) and writes deprecated config keys + unsupported async hooks #492

@dgershman

Description

@dgershman

Observed when a Codex coding session opens in Crow:

cd /Users/danny/Projects/devroot/rm/crow-491-reinstall-skill-button && /Users/danny/.nvm/versions/node/v22.22.2/bin/codex
⚠ `[features].codex_hooks` is deprecated. Use `[features].hooks` instead.
Enable it with `--enable hooks` or `[features].hooks` in config.toml.

╭───────────────────────────────────────────────────╮
│ >_ OpenAI Codex (v0.139.0)                        │
│ model:     gpt-5.5 medium   /model to change      │
│ directory: ~/…/rm/crow-491-reinstall-skill-button │
╰───────────────────────────────────────────────────╯

⚠ skipping async hook in /Users/danny/.codex/hooks.json: async hooks are not supported yet
⚠ skipping async hook in /Users/danny/.codex/hooks.json: async hooks are not supported yet

Two distinct bugs, one launch flow, both in Packages/CrowCodex/Sources/CrowCodex/OpenAICodexAgent.swift and its hook writer.


Bug 1: Codex launches with no prompt — agent sits idle waiting for the user to type

Root cause: OpenAICodexAgent.autoLaunchCommand(...) returns a bare "codex\n" (see the existing code path that I read in earlier diagnostics — function around line 47-64 in current HEAD). The inline comment even says "Bare codex launch — the user types their prompt into the TUI." That was an MVP choice when Codex support was first added — but it makes Codex coding sessions functionally non-autonomous: Crow opens the worktree, Codex starts, no prompt is delivered, the agent just waits at an empty TUI for the user to paste in the ticket context manually.

By comparison, the Claude Code launcher feeds the agent a prompt via claude --permission-mode plan "$(cat <prompt-file>)" (see crow-workspace/setup.sh and Claude's autoLaunchCommand). The Codex equivalent should send the same prompt content into Codex's CLI so the session starts already working.

Fix shape:

Confirm via codex --help which entry point accepts a non-interactive prompt — likely codex exec "<prompt>" (one-shot) or a positional/--message form for the interactive TUI. From the Codex docs, codex (interactive TUI) accepts an initial message as a positional argument: codex "your prompt here". Update OpenAICodexAgent.autoLaunchCommand to:

public func autoLaunchCommand(
    session: Session,
    worktreePath: String,
    ...
) -> String? {
    guard session.kind == .work else { return nil }
    // Read the same prompt file Claude's path uses — same content, same location.
    let promptPath = "\(devRoot)/.claude/prompts/crow-prompt-\(session.name).md"
    // Codex takes an initial positional message. Quote and escape so multi-line
    // content + shell metacharacters reach the CLI intact. Newline at the end
    // submits.
    return "codex \"$(cat \(posixQuote(promptPath)))\"\n"
}

If the positional doesn't accept the full prompt body cleanly (size limits, multiline), fall back to codex exec with the prompt file via stdin: codex exec < <prompt-file> (then the session runs the prompt non-interactively, completes the round, exits — not ideal for an interactive session but workable for one-shot work).

Acceptance for Bug 1:

  • Launching a Codex coding session against any ticket opens the Codex TUI with the ticket's prompt already submitted as the first message. Codex starts working without the user typing anything.
  • The prompt content matches what the Claude Code path would have sent (same crow-prompt-<session>.md source).
  • session.kind == .review still returns nil (review-on-Codex is still gated out, per the existing comment).

Bug 2: Crow writes deprecated [features].codex_hooks + async hooks Codex can't run

Symptoms (from the launch above):

  • ⚠ [features].codex_hooks is deprecated. Use [features].hooks instead. — Codex CLI evolved its config.toml feature-flag name; Crow's hook config writer still uses the old key.
  • ⚠ skipping async hook in /Users/danny/.codex/hooks.json: async hooks are not supported yet (×2) — Crow declares async hooks (probably to mirror Claude Code's hook pattern), but Codex's hook system is sync-only. The hooks Crow registered are being silently no-op'd every launch.

Root cause: OpenAICodexAgent.swift references a hookConfigWriter: any HookConfigWriter = CodexHookConfigWriter() (see line 16 area). That writer is what produces:

  • Whatever updates ~/.codex/config.toml for the feature flag.
  • ~/.codex/hooks.json with the hook definitions.

Both writes need updating to match current Codex CLI (v0.139.0):

  1. config.toml feature flag — change [features].codex_hooks to [features].hooks. If the writer is the source of that key, fix the key it writes. If the user wrote it manually (legacy from a previous Crow install), the writer should detect a codex_hooks = … value on read, migrate to hooks = …, and remove the legacy key.

  2. hooks.json async declarations — find the hook definitions Crow writes (likely in CodexHookConfigWriter.swift), drop the async: true (or whatever Crow flags those hooks with), or omit them entirely if they only make sense as async. If Crow's session-state plumbing relies on those hooks firing to detect activity/completion, those signals are silently lost today — the Codex session state from Crow's POV may be unreliable.

  3. Document why these hooks exist. The codex hooks Crow registers are presumably about detecting agent state for the same purposes ClaudeCodeAgent uses hooks (auto-respond, completion detection, the card-color update from Cursor sessions don't update card color on completion (status indicator stuck) #428). If the async hooks are being silently dropped today, those features are silently broken for Codex sessions even when the agent does run. Worth verifying alongside this fix.

Acceptance for Bug 2:

  • A fresh Crow launch with Codex configured produces no [features].codex_hooks is deprecated warning from Codex's startup.
  • No ⚠ skipping async hook ... warnings — either all Codex hooks are sync (and registered correctly), or the unsupported hooks are removed from hooks.json so Codex doesn't see them.
  • Whatever session-state signals Crow expects from Codex's hooks (state, agent-waiting events, completion) actually fire — verify the auto-respond and card-color flows work for a Codex session, not just for Claude Code.
  • Migrate legacy [features].codex_hooks entries in user config.toml: read, rename to hooks, log a one-line migration notice. Idempotent — running twice is a no-op the second time.

Critical files

Purpose Path
Agent launcher (Bug 1) Packages/CrowCodex/Sources/CrowCodex/OpenAICodexAgent.swift (autoLaunchCommand, ~lines 47-64 of current HEAD)
Hook config writer (Bug 2) Packages/CrowCodex/Sources/CrowCodex/CodexHookConfigWriter.swift (or wherever the conformer to HookConfigWriter lives for Codex)
Prompt-file convention to mirror Packages/CrowClaude/Sources/CrowClaude/ClaudeCodeAgent.swift + crow/skills/crow-workspace/setup.sh:572 for the crow-prompt-<session>.md path
Where codex --help confirms the CLI form Local — runtime check, no source path

Out of scope

Related

🐦‍⬛ Created with Crow via Claude Code

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions