Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions plugins/codex/agents/codex-rescue.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ Forwarding rules:
- Return the stdout of the `codex-companion` command exactly as-is.
- If the Bash call fails or Codex cannot be invoked, return nothing.

Prompt assembly and background handling:

- Pass the task prompt inline as positional arguments to `task`. Do not write prompt files to disk using `node`, `fs`, shell heredocs, or any other interpreter in order to consume them with `--prompt-file`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Insert -- before inline prompt arguments

For a read-only request whose task text mentions a supported option, such as “diagnose why --write changes the sandbox,” following this instruction with task "<prompt>" can silently enable writes and remove that token from the prompt. normalizeArgv splits a sole quoted argument and parseArgs recognizes options anywhere before a -- delimiter, so the inline-prompt contract must require task [runtime options] -- "<prompt>" to keep task text from becoming runtime control flags.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in f9862c5 — the contract now requires task [runtime options] -- "<prompt>" in both agents/codex-rescue.md and skills/codex-cli-runtime/SKILL.md.

Confirmed the mechanism: with a sole quoted argument normalizeArgv runs it through splitRawArgumentString, and parseArgs treats any --write / --model token before a -- delimiter as a runtime option, so it both flips the flag and drops the token from the positionals that readTaskPrompt joins into the prompt. With the delimiter, parseArgs sets passthrough and every remaining token is preserved verbatim as prompt text.

- Do not poll, `pgrep`, `watch`, `tail` logs, or run wait loops for a background task. If the task is run with `--background`, or if the Bash harness moves the call to the background after the timeout, return the printed job ID and the suggested `/codex:status <id>` command exactly as output and stop.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not advertise a companion ID after Bash auto-backgrounding

When the Bash harness backgrounds a foreground task call after its timeout, the companion never executes its explicit options.background branch, which is the only path that renders the task-* job ID and /codex:status suggestion. The harness ID is not a companion job ID, so this instruction either asks the subagent to return output that does not exist or produces a status command that cannot resolve the job; this fallback should explicitly launch task --background or avoid promising a companion ID.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right — fixed in f9862c5. Only the options.background branch in handleTask reaches renderQueuedTaskLaunch, so a foreground call that the Bash harness backgrounds after its timeout never prints a task-* ID, and the harness shell ID does not resolve in /codex:status.

The job-ID/status instruction is now scoped to --background runs only, and a separate rule states that a harness-backgrounded foreground call has no companion job ID: return the harness output as-is, do not invent an ID or suggest a /codex:status command for it.


Response style:

- Do not add commentary before or after the forwarded `codex-companion` output.
6 changes: 5 additions & 1 deletion plugins/codex/skills/codex-cli-runtime/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,12 @@ Command selection:
- `--effort`: accepted values are `none`, `minimal`, `low`, `medium`, `high`, `xhigh`.
- `task --resume-last`: internal helper for "keep going", "resume", "apply the top fix", or "dig deeper" after a previous rescue run.

Prompt and background handling:
- Pass the prompt inline as positional arguments to `task`. Do not write prompt files to disk with `node`, `fs`, shell heredocs, or any other interpreter in order to consume them with `--prompt-file`.
- Do not poll, `pgrep`, `watch`, `tail` logs, or run wait loops for a background task. If `task` is invoked with `--background`, or if the Bash harness moves the call to the background, return the job ID and suggested `/codex:status <id>` command exactly as output and stop.

Safety rules:
- Default to write-capable Codex work in `codex:codex-rescue` unless the user explicitly asks for read-only behavior.
- Default to write-capable Codex work in `codex:codex-rescue` unless the user explicitly asks for read-only behavior or only wants review, diagnosis, or research without edits.
- Preserve the user's task text as-is apart from stripping routing flags.
- Do not inspect the repository, read files, grep, monitor progress, poll status, fetch results, cancel jobs, summarize output, or do any follow-up work of your own.
- Return the stdout of the `task` command exactly as-is.
Expand Down
13 changes: 13 additions & 0 deletions tests/commands.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,19 @@ test("transfer, result, and cancel commands are exposed as deterministic runtime
assert.match(resultHandling, /if Codex was never successfully invoked, do not generate a substitute answer at all/i);
});

test("rescue agent forbids node-based prompt writes and pgrep background wait loops", () => {
const agent = read("agents/codex-rescue.md");
const runtimeSkill = read("skills/codex-cli-runtime/SKILL.md");

assert.match(agent, /Do not write prompt files to disk/i);
assert.match(agent, /node[^\n]*fs/i);
assert.match(agent, /Do not poll.*pgrep/i);
assert.match(agent, /return the printed job ID/i);
assert.match(runtimeSkill, /Do not write prompt files to disk/i);
assert.match(runtimeSkill, /Do not poll.*pgrep/i);
assert.match(runtimeSkill, /return the job ID and suggested/i);
});

test("internal docs use task terminology for rescue runs", () => {
const runtimeSkill = read("skills/codex-cli-runtime/SKILL.md");
const promptingSkill = read("skills/gpt-5-4-prompting/SKILL.md");
Expand Down