Skip to content

SessionEnd of one Claude session shuts down the shared workspace broker and aborts another session's running Codex job #803

Open

Description

@Drak0

Summary

SessionEnd shuts down the workspace's shared app-server broker unconditionally. If a second Claude Code session ends in the same working directory while another session's Codex job is running, that job's turn is aborted and the job stays running forever.

Reproduced on 1.0.5; handleSessionEnd in plugins/codex/scripts/session-lifecycle-hook.mjs is unchanged on 1.0.6 / main.

Cause

handleSessionEnd resolves the broker with loadBrokerSession(cwd) — broker state is keyed by workspace path, not by Claude session — then calls sendBrokerShutdown, teardownBrokerSession and clearBrokerSession(cwd) without checking whether the ending session started that broker or whether other sessions still have active jobs on it. cleanupSessionJobs does filter by sessionId, so the other session's job record is left untouched in running.

Reproduction

In any git workspace:

C=<plugin root>/scripts/codex-companion.mjs
node $C task --background "Run the shell command: sleep 80   -- then reply with exactly the word DONE."
# once the job log shows "Running command", end any other Claude Code session in the same cwd:
claude -p "Reply OK"
node $C status <job-id>

Observed: the job log stops at Running command: /bin/bash -lc 'sleep 80', the worker process is gone, the broker session directory is removed at the moment the second session exits, and status reports running indefinitely. The Codex rollout for the thread records turn_aborted with reason: interrupted. Even a claude -p invocation that fails immediately (for example with a usage error) triggers it, because SessionEnd still fires.

Control: the same sequence with the second session started with --settings '{"enabledPlugins":{"codex@openai-codex":false}}' leaves the job alone and it completes.

Where this bites in practice

A Codex task that itself runs a nested claude -p in the workspace (for example a cross-model check from inside the Codex turn) kills its own broker when that nested session exits. That is how we hit it: a 17-minute Codex turn was aborted the instant its nested Claude consult returned.

Expected

SessionEnd should only tear down a broker when no other session has queued or running jobs on it (or should track broker ownership per session), and should not leave another session's job in running.

Related but distinct: #743 (SessionEnd kills whatever pid broker.json names), #791, #377 (dead-worker reconciliation).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions