Skip to content

Skill(codex:rescue) infinite-recurses when invoked programmatically from main agent #234

@lwbvv

Description

@lwbvv

Summary

Calling Skill(codex:rescue) programmatically from the main Claude Code
agent (not via the user-typed /codex:rescue slash command) triggers an
infinite recursion that hangs the session until manual cancellation. The
Codex CLI is never invoked.

Confirmed on plugin versions 1.0.2 and 1.0.3.

Repro

From the main agent (not the user's slash-command path):

Skill(codex:rescue, args: "<any rescue task>")

Observed behavior

  • UI appears frozen; no Codex job is created.
  • No entry under ~/.claude/plugins/data/codex-openai-codex/state/<project>/state.json.
  • No log file under ~/.claude/plugins/data/codex-openai-codex/state/<project>/jobs/.
  • After ~3+ minutes, user must cancel manually.

Root cause (from subagent fork log)

Timeline from ~/.claude/projects/<project>/<session>/subagents/agent-*.jsonl
(agentType: "general-purpose"):

T+0s    fork subagent starts, loads rescue.md instructions + raw user request
T+2s    "I'll check for a resumable rescue thread first"
T+3s    Bash: codex-companion.mjs task-resume-candidate -> available: false ✓
T+15s   ❌ Skill(codex:codex-rescue) attempted -> "Unknown skill: codex:codex-rescue"
T+20s   ❌ recovery attempt: Skill(codex:rescue) called again (recurses into self)
T+217s  hang; user cancels

Why:

  1. commands/rescue.md frontmatter sets context: fork, so invocation
    forks a general-purpose subagent and loads rescue.md body as its
    instructions.
  2. The body instructs: "Route this request to the codex:codex-rescue
    subagent."
  3. codex:codex-rescue is an agent (Agent tool's subagent_type),
    not a skill (Skill tool).
  4. The forked general-purpose agent resolves the ambiguous wording by
    trying Skill(codex:codex-rescue)Unknown skill error.
  5. As a fallback, it re-invokes Skill(codex:rescue) — which forks
    itself again → infinite recursion → hang.

Why the slash command works but programmatic call doesn't

When the user types /codex:rescue, Claude Code's slash-command router
handles dispatch and does not fall into the "route to subagent" prose
resolution path. When the main agent calls Skill(codex:rescue), the
fork sees only the rescue.md body and has to interpret it — hence the
ambiguity.

Suggested fix

Change commands/rescue.md to name the transport explicitly, instead of
"route to subagent" prose. For example:

  • Replace "Route this request to the codex:codex-rescue subagent" with
    an explicit instruction to use the Agent tool with
    subagent_type: codex:codex-rescue, or
  • Restrict allowed-tools in rescue.md frontmatter to Agent only
    (exclude Skill), which makes the recursive path impossible.

Workaround

Main agent calls the subagent directly:

Agent(subagent_type="codex:codex-rescue", prompt="...")

This skips the fork/resume-candidate check and invokes
node codex-companion.mjs task ... immediately. Users may see a
one-time permission prompt if Agent(codex:codex-rescue) is not in
their settings allow list.

Environment

  • Claude Code on macOS (Darwin 25.2.0)
  • Plugin versions tested: 1.0.2, 1.0.3
  • Model: Claude Opus 4.6

Metadata

Metadata

Assignees

No one assigned

    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