Skip to content

W7: reliability ports, notification fix, Workflow-native delegate - #1

Merged
doubleDrake merged 9 commits into
mainfrom
work/reliability-notify-workflow
Jun 15, 2026
Merged

doubleDrake merged 9 commits into
mainfrom
work/reliability-notify-workflow

Conversation

@doubleDrake

Copy link
Copy Markdown
Owner

Ports the strongest reliability/observability features from sibling forks (Robbyfuu/codex-plugin-cc, dragon84867/codex-plugin-cc; both Apache-2.0), fixes a notification bug that exists upstream too, and reframes Pattern A around the Claude Code Workflow tool.

Tests: 169 → 297, 0 fail. New-file-concentrated (doctor/telemetry/watchdog/workflow + tests); edits to existing files are small additive patches.

Fixed

  • notification "Codex Codex" duplication — the harness surfaces a job's internal title and prefixes "Codex", but the title already started with "Codex". Dropped the redundant prefix from companion job titles + review/adversarial/delegate Bash descriptions; result headers keep # Codex <title>. Present upstream too.
  • schema description yaml → json (impl parses JSON).

Added

  • completion signal-file <jobId>.done on terminal state. (dragon84867)
  • per-turn telemetry telemetry.jsonl + /codex:status p50/p95/stall/restart + watchdog.mjs module. (Robbyfuu)
  • BROKER_BUSY RPC retry — bounded; socket/exit errors not retried. (Robbyfuu)
  • /codex:doctor read-only health report + gated --fix/--clean with kill-gate + TOCTOU. (Robbyfuu)
  • broker item-flight self-heal — generation-guarded router + 2-stage idle guard + broker-telemetry.jsonl; coexists with existing W1 (idle shutdown / PID liveness / crashed). (Robbyfuu)

Changed

  • Workflow-native delegate workflows/codex-delegate.js (deterministic STATUS loop, isolation:"worktree", pipeline/parallel). codex-team-bridge/codex-pane-helper deprecated (kept for --pane).

Deferred

  • explicit broker/recover hard-cancel hook; companion-side capture-turn watchdog.

Notes

  • Notification volume is harness-owned (not plugin-throttleable): use /codex:setup --disable-review-gate and/or preferredNotifChannel.

INV-1 preserved (/codex:doctor is the 10th direct command). Attribution in README Credits + inline.

🤖 Generated with Claude Code

yong and others added 9 commits June 13, 2026 23:04
The Claude Code harness surfaces a job's internal title (and a background
Bash task description) in its desktop notification and then prefixes it
with "Codex", producing duplicated "Codex Codex Review completed"
notifications. Remove the redundant "Codex" prefix from companion job
titles (Review / Adversarial Review / Stop Gate Review / Task / Resume /
Delegate / Consult) and from the review/adversarial/delegate Bash
descriptions. Preserve the user-facing "# Codex <title>" result header in
render.mjs so plugin output is unchanged.

Also refresh the stale commands.test expected list (consult/delegate/do
were added upstream of this change without updating the test) — the suite
now passes 169/169.

This duplication exists in openai/codex-plugin-cc too; candidate for an
upstream PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Pre-work for the reliability ports: doctor (2a) and the broker watchdog
(2d) need a PID-liveness probe and a broker-endpoint readiness check that
were previously private. Promote job-control's checkProcessAlive into
process.mjs as exported isPidAlive (job-control re-imports it; de-dups,
no behavior change) and export isBrokerEndpointReady from broker-lifecycle.

No behavior change; suite stays 169/169.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Write a sibling `<jobsDir>/<jobId>.done` whenever a tracked job reaches a
terminal state, so a background watcher (Monitor, or `until [ -f ... ]`)
wakes the instant the job finishes instead of polling.

- writeCompletionSignalFile() in tracked-jobs.mjs (best-effort; never fails
  the job) is called on runTrackedJob success/failure paths.
- enrichJob() emits a "crashed" signal when it detects a dead worker PID,
  since that worker never wrote its own .done.
- state.mjs gains resolveJobSignalFile() (sibling of resolveJobFile/Log),
  and pruneJobs cleanup removes the .done alongside .json/.log so signal
  files don't accumulate past the 50-job cap.

5 new tests (tests/completion-signal.test.mjs); suite 169 -> 174.

Pattern adapted from dragon84867/codex-plugin-cc (Apache-2.0).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…dog module

Record one JSON line per finished turn (durationMs / exitReason / kind /
threadId / startedAt) to <stateDir>/telemetry.jsonl with a 5MB single-
generation roll, written best-effort from runTrackedJob so it never
disturbs the turn it observes. /codex:status now aggregates it into
p50/p95/max, stall rate and restart rate plus a tuning recommendation.

Also lands the pure watchdog.mjs hang-prevention module (timeout constants +
resolveTimeouts + createIdleWatchdog + createBrokerIdleGuard). telemetry
consumes the constants now; the guards are wired into the broker in 2d, so
they ship tested-but-not-yet-connected. Until 2d's broker event log exists,
restartRateSource is "interrupted" (the honest companion-side signal) and
the idle-stall/hard-stop buckets stay empty.

state.mjs gains resolveTelemetryFile. New tests: telemetry, watchdog,
broker-idle-guard, renderStatusReport stats section, and runTrackedJob
telemetry round-trip. Suite 174 -> 226.

Pattern adapted from Robbyfuu/codex-plugin-cc (Apache-2.0).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The broker returns BROKER_BUSY (-32001) when an exclusive stream is already
active: it refuses before the request reaches the child, so the request
never executed. Retry it (bounded, backoff) instead of surfacing a hard
failure to the caller. Socket/exit errors carry no rpcCode and are NOT
retried, so a mid-turn connection drop can never double-submit a turn.

AppServerClientBase.request is now retry-aware (dispatchRequest holds the
single-attempt logic); the class is exported for unit testing. 3 new tests.
Suite 226 -> 229.

Pattern adapted from Robbyfuu/codex-plugin-cc (Apache-2.0).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Read-only diagnosis of the codex runtime: classifies the broker
(healthy/orphaned/wedged/none) via endpoint readiness + PID liveness,
and flags stale job artifacts, orphan pane markers, and oversized
telemetry. --fix tears down orphaned brokers and removes orphan markers;
--clean removes stale logs and rolls oversized telemetry. A wedged broker
is NEVER killed while an active job exists (kill-gate), with a TOCTOU
re-check of the live active-job set at execute time.

buildDoctorReport is strictly read-only (derives telemetry paths via
resolveStateDir, which does not mkdir, unlike resolveTelemetryFile).
broker-telemetry.jsonl is read optionally (it lands with the broker
self-heal phase), degrading to 0 bytes when absent.

New: lib/doctor.mjs, lib/doctor-fs.mjs, commands/doctor.md,
renderDoctorReport, handleDoctor + switch wiring. 40 new tests
(doctor / doctor-fs / render-doctor). Suite 229 -> 269. doctor is the
10th direct command; INV-1 preserved.

Pattern adapted from Robbyfuu/codex-plugin-cc (Apache-2.0).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…m-bridge/pane-helper

Add plugins/codex/workflows/codex-delegate.js, the Workflow-native A+
delegate: for each task description it runs the Codex STATUS ping-pong as a
deterministic JS while loop (agent({ agentType: "codex:codex-delegate",
isolation: "worktree", schema }) until STATUS: DONE or a 5-turn cap),
fanning multiple tasks out concurrently with pipeline()/parallel(), each in
its own auto-managed git worktree. This expresses the team-bridge ping-pong
and per-job worktree isolation natively (the latter also covers dragon's
worktree feature for the orchestrated case).

commands/delegate.md gains an "Execution models" section: (a) the unchanged
default subagent path (INV-1), (b) the new Workflow path for parallel /
worktree-isolated delegation. --pane stays as the Agent-Teams opt-in for an
interactive live teammate (the one case a Workflow cannot do).

codex-team-bridge and codex-pane-helper get deprecation notices (superseded
for orchestration; kept for --pane; to be removed in a future release). No
code or skill body deleted: conservative add-only change. Suite stays 269/0.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…/notifications/credits)

- codex-tool-calls.schema.json: description said "fenced yaml" but the
  implementation parses JSON; corrected to json.
- CHANGELOG: W7 section (notification dedup fix, completion signal-file,
  per-turn telemetry + watchdog module, RPC retry, /codex:doctor,
  Workflow-native delegate, deferred broker self-heal, notification-noise note).
- README: /codex:doctor subsection, /codex:status telemetry line, Notifications
  FAQ entry, Credits/Attribution (Robbyfuu + dragon84867, Apache-2.0).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…neration guard

Add broker mid-turn self-heal on top of the existing W1 safety nets (preserved):
the broker routes notifications through a generation-guarded router (drops
notifications from a superseded child after a restart) with item-flight
tracking, and runs a two-stage idle guard — stage 1 interrupts the active turn,
stage 2 runs performBrokerRecovery (close child, reconnect, bump generation,
rebind handler). The guard never fires while an item is in flight, so a slow
command/reasoning block is never mistaken for a wedge.

The two idle concepts COEXIST independently: the W1 connection-count
auto-shutdown (sockets.size===0 -> exit, CODEX_BROKER_IDLE_MS) + clearBrokerSession
still fire; the new item-flight guard only self-heals a genuinely silent+wedged
active stream. BROKER_BUSY single-flight, unix-socket/named-pipe transport, and
SessionEnd shutdown are intact.

Broker lifecycle events are recorded to broker-telemetry.jsonl; /codex:status
feeds them to aggregateTelemetry so restart rate uses the real "broker" source
instead of the "interrupted" inference, and /codex:doctor's optional
broker-telemetry read now finds the file.

New: broker-routing.mjs, broker-telemetry.mjs, state.resolveBrokerTelemetryFile.
28 new tests. broker-endpoint + runtime (the rewritten loop) stay green.
Suite 269 -> 297. Deferred: the explicit broker/recover hard-cancel hook and the
companion-side capture-turn watchdog (separate features).

Pattern adapted from Robbyfuu/codex-plugin-cc (Apache-2.0).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@doubleDrake
doubleDrake merged commit 69c6d33 into main Jun 15, 2026
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.

1 participant