Skip to content

Show Codex CLI activity in tab status#673

Open
ivnnv wants to merge 7 commits into
gnachman:masterfrom
ivnnv:codex-title-adaptor
Open

Show Codex CLI activity in tab status#673
ivnnv wants to merge 7 commits into
gnachman:masterfrom
ivnnv:codex-title-adaptor

Conversation

@ivnnv

@ivnnv ivnnv commented May 28, 2026

Copy link
Copy Markdown
Contributor

Codex doesnt emit OSC 21337, so iTerm2 currently cant show the usual AI-agent tab status for it. It does update the terminal title with a braille spinner while its working, so this PR uses that as a compatibility path for Codex only.

The shim watches title changes, verifies the foreground process is actually codex, and synthesizes the same Working/Idle status the existing OSC 21337 path produces. Real OSC 21337 status still wins, so this wont overwrite agents that already report status directly.

The synthesized status is tagged as shim-owned, so it only clears state it created, and its excluded from saved arrangements so restored windows dont come back with stale fake status. It re-derives from the next title or foreground-process update.

Matching is on the foreground process whose last path component is codex, so it works for both install layouts (brew native binary and the npm/npx Rust binary) and ignores lookalikes like codex-ish. Prerequisite for #670 (menu bar item counting working AI agents), which picks up Codex support for free once this lands.

Test plan

  • codex shows Working while the title spinner is active, Idle when it stops
  • exiting Codex clears the synthesized status
  • non-Codex commands with similar titles dont trigger it
  • real OSC 21337 status is preserved, including inside a Codex tab
  • restored windows dont persist synthesized status

ivnnv added 4 commits May 28, 2026 10:04
Codex (OpenAI) does not emit OSC 21337; it conveys working state by
prefixing the terminal title (OSC 0/1/2) with a braille-spinner glyph
while crunching and removing the prefix when idle or blocked on the
user. Sessions running Codex therefore got no tab indicator dot, no
subtitle, and no signal to any other consumer of iTermSessionTabStatus.

Add a compatibility shim that recognizes the title pattern, gates on
the foreground job ancestry containing codex (last-path-component
match so /opt/homebrew/bin/codex counts), and synthesizes the
equivalent Working/Idle status into iTermSessionTabStatus. The existing
tab indicator, tab subtitle, and notification paths render the same as
for OSC 21337-aware agents.

iTermSessionTabStatus gains a synthesizedStatusSource tag so the shim
only clears state it owns. A real OSC 21337 emitter that changes any
visible field claims authoritative ownership; the shim refuses to
overwrite a real emitter's status (text or dot-only). Synthesized
state is excluded from arrangementDictionary so it does not survive
window restoration as fake-real state; the shim re-derives status on
the next title or foreground-job update post-restore.

Pure decoding lives in CodexTitleStatusDecoder.swift and is covered by
unit tests for the spinner prefix, near misses, non-codex word matches,
and out-of-block scalars. The hook sites in PTYSession assert main
thread, matching the threading contract of screenSetTabStatus:.
# Conflicts:
#	iTerm2.xcodeproj/project.pbxproj
Empirically observed two install layouts:

- Brew: /opt/homebrew/bin/codex, single native binary, foreground argv0
  ends in codex. Adaptor matches.
- npm/npx: node ./node_modules/.bin/codex spawns the platform-specific
  Rust binary at .../codex-darwin-arm64/.../bin/codex with stdio inherited,
  so the Rust child is the deepest foreground job on the TTY. Its argv0
  ends in codex; foregroundJobAncestorNames lists it before node. Adaptor
  matches.

Tests cover both layouts plus the rejection cases that prove the gate is
doing real work: substring-only matches (codex-ish, not-codex), no codex
in ancestors, nil ancestors. Plus title-driven transitions and the
coexistence invariant: a real OSC 21337 emitter that wrote a visible
status before the shim runs is left alone.
# Conflicts:
#	iTerm2.xcodeproj/project.pbxproj
@ivnnv ivnnv changed the title Detect Codex CLI working state and surface it as tab status Show Codex CLI activity in tab status Jun 13, 2026
@ivnnv

ivnnv commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

@gnachman friendly ping, did you get a chance to look at this? 🙇🏽 (I have been using this myself for a while now)
Its useful when working with the typical Claude/Codex combo, and opens the door to more CLI adapters later (like OpenCode)

@gnachman

Copy link
Copy Markdown
Owner

This could be done but it's probably not a great idea because it is so tightly bound to the current behavior of Codex. The best way is for codex itself to send OSC 21337. If that is off the table, the second-best way is to add a new category of triggers that run on title change and make it part of a formal Codex integration. That way they can be updated if Codex changes its behavior in the future.

ivnnv added 2 commits June 20, 2026 19:13
Per review, move Codex working/idle detection off the hardcoded screenSetWindowTitle hook and into the trigger system. Adds a new event-trigger category, Title Changed (iTermTriggerMatchTypeEventTitleChanged), fired on OSC 0/1/2 title changes with an optional titleRegex filter, selectable and configurable like the other event triggers.

Codex now rides that event via an always-on built-in trigger seeded by EventTriggerEvaluator. Its action reuses the existing decoder/adaptor through a new triggerSession side-effect that applies synthesized tab status, so source-ownership and arrangement-exclusion guarantees are preserved. Foreground-job changes re-evaluate the shim directly so working clears when codex exits without a fresh title.

Covered by new EventTriggerEvaluatorTitleChangedTests plus the existing Codex decoder/adaptor tests.
# Conflicts:
#	iTerm2.xcodeproj/project.pbxproj
#	sources/Settings/Profiles/ITAddressBookMgr.h
#	sources/Triggers/iTermEventTriggerParameterView.swift
@ivnnv

ivnnv commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

thanks @gnachman! makes sense.

Reworked it the way you suggested: added a Title Changed event-trigger category, and Codex rides it as a built-in trigger now instead of the hardcoded hook in screenSetWindowTitle. the detection itself (spinner decode + Working/Idle mapping) stays in CodexTitleStatusDecoder/Adaptor, just reused from the trigger action, so same behavior but title handling is part of the trigger system now and updatable if Codex changes it.

Synced with master and resolved the conflicts.

@gnachman

Copy link
Copy Markdown
Owner

The PRs I sent OpenAI has been making some progress and that is a much cleaner solution. Let's hold off on this and see if gets landed. You can find them from the issue: openai/codex#25879

carvalhoviniciusluiz added a commit to carvalhoviniciusluiz/it2agent that referenced this pull request Jul 22, 2026
Bring in upstream "Show Codex CLI activity in tab status": Codex (OpenAI)
does not emit OSC 21337; it signals working/idle by prefixing the OSC
0/1/2 terminal title with a braille-spinner glyph. A pure decoder
(CodexTitleStatusDecoder) plus a foreground-job-gated adaptor
(CodexTitleStatusAdaptor) synthesize the equivalent iTermSessionTabStatus,
driven by a new always-on built-in "Codex Status" trigger riding a new
"Title Changed" event-trigger category.

Gated behind a new per-user spawnTerm feature flag `spawnterm.codex_status`
(default OFF), toggled in Settings > General > AI > spawnTerm. The gate is
enforced at the single choke point -[PTYSession
screenApplyCodexTitleStatusWithTitle:]: when OFF, no synthesized Codex tab
status is applied and behavior is stock. Flag added in all three synced
places (spawnterm-flag, spawnterm_flag.py, iTermSpawnTermCapabilities.m)
plus feature-flags.md; shell/python parity tests stay green.

PTYSession.m merge preserves our prior #51 (user-var sidecar) and #49
(writeTask:completion: threading) changes; the gnachman#673 hooks are purely
additive. New Trigger.h delegate method, VT100Screen side-effect plumbing,
and the Title Changed event UI are included.

Adapted from upstream gnachman#673

Co-authored-by: carvalhoviniciusluiz <carvalhoviniciusluiz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
carvalhoviniciusluiz added a commit to carvalhoviniciusluiz/it2agent that referenced this pull request Jul 22, 2026
…an#670/gnachman#673) + 3 new AI flags + agent guide

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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