Skip to content

feat: add task --thread <id> to resume a specific Codex thread - #719

Open
y-cruce wants to merge 2 commits into
openai:mainfrom
y-cruce:feat/task-thread
Open

feat: add task --thread <id> to resume a specific Codex thread#719
y-cruce wants to merge 2 commits into
openai:mainfrom
y-cruce:feat/task-thread

Conversation

@y-cruce

@y-cruce y-cruce commented Sep 3, 2026

Copy link
Copy Markdown

Summary

task --resume-last can only continue the newest finished task thread of the current Claude session in the repo. When a caller drives several Codex threads in one session (for example one thread per problem, or a review that ran as a task in between), the older threads become unreachable even though the app-server can resume them by id.

This adds task --thread <id> to resume a specific thread through the same path --resume-last uses.

Changes

  • plugins/codex/scripts/codex-companion.mjs: parse --thread, validate it (non-empty, not flag-like, mutually exclusive with --resume/--resume-last/--fresh), pass resumeThreadId through buildTaskRequest/executeTaskRun in both foreground and --background modes. The thread id is not pre-written into the job record; it is stored by the existing Thread ready progress handling after a successful resume, so a failed resume of an unknown id does not pollute the next --resume-last.
  • tests/runtime.test.mjs: resume by id (foreground and background), flag not leaked into the prompt, conflicting and invalid values rejected, failed resume does not pre-write the id.
  • tests/commands.test.mjs, README.md, plugins/codex/commands/rescue.md, plugins/codex/agents/codex-rescue.md, plugins/codex/skills/codex-cli-runtime/SKILL.md: document the flag and its routing.

No changes under lib/; --resume-last, --resume, and --fresh behave as before. Version not bumped.

Verification

  • npm test: the new tests pass; no new failures relative to the clean tree on the same machine (the remaining failures there are environment-related setup/status/result/resolveStateDir cases that fail identically without this change).
  • Manual: with a shared app-server running and a newer thread being the task-resume-candidate, task --thread <older-id> "..." resumed the older thread (Thread ready (<older-id>)) and Codex answered from that thread's context.

Notes

--thread intentionally bypasses the current-session filter used by --resume-last. It does not check repository ownership of the thread; the resume request carries the current cwd.

@y-cruce
y-cruce requested a review from a team September 3, 2026 03:37
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T12:00:17.168034Z 8ecb158 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@sylvesterkaczmarek sylvesterkaczmarek left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

--thread accepts any known thread ID without checking the thread’s repository. That can resume context from repo A while executing with repo B’s current cwd, which risks cross-repo context leakage and wrong-repo edits. Please verify the saved thread cwd/repository before resuming, with an explicit override only if cross-repo resume is intended.

@y-cruce

y-cruce commented Sep 3, 2026

Copy link
Copy Markdown
Author

Good catch, thanks. --resume-last is implicitly scoped to the current workspace through the job records, and --thread skipped that.

Added in the latest commit: before resuming, the thread id must appear in the current workspace's tracked task jobs (any Claude session). Otherwise the run fails before any resume request is sent, with an error pointing to --allow-other-repo, which is the explicit override for an intentional cross-repo resume. The check runs in executeTaskRun, so foreground and --background behave the same, and a rejected run leaves the job failed without a threadId.

Threads created outside the plugin (plain codex CLI) are not tracked and therefore also need the override; the error text and the docs say so.

Tests cover: tracked thread from another Claude session resumes; untracked thread rejected in foreground and background; --allow-other-repo resumes an untracked thread; --allow-other-repo with an unknown id still fails at Codex without pre-writing the id.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ecb158f7b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +359 to +360
if (listJobs(workspaceRoot).some((job) => job.threadId === threadId)) {
return;

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 Preserve foreign-thread provenance after an override

When a thread from repo A is first resumed in repo B with --allow-other-repo, the successful run records that thread ID in repo B's job state. On a later invocation this predicate therefore accepts task --thread <id> without the required override, even though the thread still contains repo A's history. Track whether a thread was admitted through the override, or verify its original workspace, rather than treating every local job record as proof of repository ownership.

Useful? React with 👍 / 👎.

Comment on lines +474 to +475
if (request.resumeThreadId && !request.allowOtherRepo) {
requireTrackedThreadForWorkspace(workspaceRoot, request.resumeThreadId);

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 Validate the tracked thread before inserting the new job

When the state already contains the maximum 50 jobs and the requested thread appears only in the oldest record, runTrackedJob (or the background enqueue path) inserts the new job before this validation runs. saveState then prunes that oldest record via pruneJobs(...).slice(0, MAX_JOBS), so this check rejects a thread that was tracked when the command started and incorrectly demands --allow-other-repo. Validate against the pre-insertion state or preserve thread ownership separately from the bounded job history.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants