Repository navigation
fix(chat): greet a fresh Codex started in a terminal - #1967
Conversation
Typing `codex` in a Herdr terminal and opening Chat before the first message said "Conversation unavailable", while a Codex started from New workspace, New tab or New worktree showed its greeting (#990). Codex writes no session before the first message, and herdr reports none, so nothing tied the pane to a transcript. Chat now greets one only when every fact says it has begun none, and keeps the terminal otherwise: - the screen is Codex's start screen with nothing said: under the last banner line ("> _ OpenAI Codex (v…)", not an answer that mentions it) the composer is the first prompt line, no prompt or answer, warning or error cell follows it, and none is above the banner either (a command's card, or a second session in the same terminal); - no `resume` or `fork` is on the command line of the pane's Codex processes; - the pane's own CODEX_HOME holds no interactive thread of its folders (the shell's and the foreground process's, as given or as they resolve) with a first message, begun or written since those processes started (a lower bound of their start, less a second). Codex 0.163 makes no store before the first message at all. A store that cannot be read, or a CODEX_HOME the server cannot place (a relative one), says no; - the pane is not working or blocked. The answer is a conversation not begun, as for an app launch, with a history id of the pane and its Codex processes (no time: a start read on macOS moves between reads), so the first message's transcript replaces it whole. Fixes #1191
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Codex start-screen recognition server/start-screen.ts, server/start-screen.test.ts |
Screen parsing validates the Codex banner, footer, and composer layout. A new predicate checks for prior conversation content, with tests for screen variations. |
Fresh-session detection server/codex.ts |
codexFreshSession checks the screen, process arguments and start times, and relevant Codex threads. It returns an unwritten identifier when the checks confirm a fresh session. |
Conversation response and validation server/conversation.ts, server/conversation.test.ts, changelog.d/codex-fresh-terminal-greeting.md |
When no session path exists, conversation handling checks for a fresh session and returns an unwritten conversation with screen metadata when confirmed. Tests cover qualifying and excluded cases. The changelog records the behavior. |
Priority:
Estimated code review effort: 3 (Moderate) | ~20 minutes
Change: Bug fix · Severity of issue fixed: Medium
Suggested reviewers: evanwy0223, yoonwoo-ha
Merge Risk: 
Minimal · up to 9cc35
-
The greeting is intended to appear only for confidently fresh sessions, with the unavailable-conversation fallback otherwise preserved. No confirmed issue prevents merging after normal checks.
Pre-merge checks: 
5
-
Full details: Linked Issues check
-
Explanation
Active direct issue
#1191requires a greeting for a reliably fresh terminal Codex session, support for the pane's selected CODEX_HOME, saved messages for resumed sessions, and the existing unavailable fallback for ambiguous sessions. The supplied PR evidence showscodexStartScreenUnused, rejection ofresumeandfork, pane-process timing and status checks, and recent interactive-thread checks in the pane's Codex store and relevant folders.conversation.tsuses this check only in the no-session fallback and preserves the existing lookup path otherwise. Tests cover fresh, resumed, ambiguous, store, folder, screen, and status cases. The reported 162/162 focused tests pass.
Full details: Out of Scope Changes check
-
Explanation
The changed implementation, tests, and changelog support
#1191. Thestart-screen.tschanges make the fresh-screen and model detection precise for this greeting. Theconversation.tsandcodex.tschanges implement the terminal no-session decision. No unrelated change is demonstrated. Closed issue#990supplies historical context only and does not add scope.
Full details: Docstring Coverage
-
Explanation
Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 5 files. (1 skipped: 1 unsupported.)
Full details: Description check
-
Explanation
The pull request description is complete and relevant. It explains the problem, resulting behavior, linked issue, implementation conditions, validation results, test coverage, and known limitations. It uses different headings from the template ("Problem"/"Fix"/"Verification" instead of "Change"/"Validation"), but it provides the required information.
-
Finishing Touches
-
📝 Generate docstrings
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
|
Merge pass review of 9cc35fa. The Astra gate (omo-native-gate-reviewer, gpt-6-astra) rejected it on one real blocker. What holds:
BLOCKER: a false greeting from the wrong store on macOS (
CI: Fast checks failed on this head. It is the known markdown timing flake #1901 (lane fix-1901 is on it), not this PR; it will be re-run. This PR touches |
The merge pass's gate found a false greeting on macOS: a pane whose Codex sets a relative CODEX_HOME had that value dropped, paneCodexHome fell back to the server's default store, and the Linux-only /proc guard did not refuse it, so a store with no conversation stood in for one that had a first message. codexFreshSession now places each Codex's store itself, on every platform (certainProcessCodexHome): the CODEX_HOME directory its environment names, ~/.codex when it names none, or no greeting. No greeting covers an environment that cannot be read (another user's process, a gone one, Windows), a CODEX_HOME that is relative or no directory, and on macOS a command line that spells CODEX_HOME= itself, which ps -E cannot tell from the environment, or a ps line that shows no environment. Every Codex of the pane must be placed; the first decides, as in paneCodexHome. An explicit server store (the codexHome option, which only tests set) still wins.
|
Thanks. Fixed in c1b4e8d (one new commit on top of 9cc35fa, so the re-review covers only that commit). Blocker B1 (false greeting from the wrong store on macOS):
Every Codex process of the pane must be placed, and the first decides, as in Test: "greets a terminal Codex only in the store its own environment places for certain" runs real child processes started with the CODEX_HOME under test, with the server's own default store isolated and empty:
Results:
CI: the earlier Fast checks failure on 9cc35fa was the #1901 markdown timing flake. This push starts a fresh run. |
|
Merge pass re-review of c1b4e8d (Astra gate). B1 is fixed, but this change surfaced two new findings. Fixed: Astra re-ran the original B1 reproduction. A simulated macOS pane whose HIGH: with no
MEDIUM: the new regression test races its child processes (
This PR touches |
The new store test failed in CI ("a CODEX_HOME that is no directory" was
greeted): it asked about each stand-in Codex right after Bun.spawn, and
until the child's exec the OS shows the environment it was forked with,
the test's own, whose CODEX_HOME is the empty fallback store. Locally it
failed 2 runs in 30.
Each stand-in now prints "ready" once it runs, and the test reads that
line before asking: 0 failures in 60 runs. A real Codex has run for
seconds before its pane is read, so the server is unchanged.
The merge pass's re-review found a false greeting: a Codex that names no CODEX_HOME had its store placed in this server's own home (homedir()), so one running with another HOME, whose .codex held a conversation begun since it started, was still greeted. Its store is now .codex in the HOME its own environment names, read like CODEX_HOME (/proc on Linux, ps -E on macOS). No HOME, a relative one, or on macOS a command line that spells HOME= itself means no greeting.
|
Thanks. Both findings are fixed in two new commits on top of c1b4e8d. HIGH: default store from the server's home (d12ff6d). When a Codex names no
New cases in the same test, each a real child process with no
Putting MEDIUM: test race (11d7b71). The cause was the one you found: read before the child's exec, the OS shows the environment the child was forked with, which is the test's own, whose Results on d12ff6d:
|
|
@coderabbitai review |
|
|
Merge pass review report. Overall: PASSED. This PR changes server behaviour: it decides which transcript a Chat binds to. Each round was reviewed by an Astra gate (omo-native-gate-reviewer, gpt-6-astra). It approved d12ff6d after three rounds. What it does: Chat greets a Codex started in a terminal only when every fact says it has begun nothing:
Otherwise the terminal fallback stays as before. Each of the three checks was mutated, and each mutation fails the regression. Findings, and how each was resolved:
Tests: the affected suites pass, 163 tests with 0 failures. Locally 238/238 pass, and typecheck is clean.
|
…r's model (#3265) <!-- See CONTRIBUTING.md for checks, translations, contract tests and the changelog (a file in changelog.d/, never CHANGELOG.md). --> ## Change Fixes #3263. Codex running a custom model provider writes the model in its footer as the provider names it (`DeepSeek4.1flash(OpenCode) low · …`, `gpt-6.1-terra high · …`). `codexLayout` read only `GPT-…` there, so a new terminal-started Codex on such a model was never taken for a start screen and its Chat showed "Conversation unavailable" until the first answer, instead of the new-chat greeting (#1967). - `codexLayout`: the footer's model is one word without spaces or `·`. The header, prompt line, effort word and hint row checks are unchanged, so a quoted picker, a draft or a popup still names no model. - `codexScreen`: `GPT-…` is lowercased to its id as before; another provider's name is kept as written, as `gjcScreen` keeps a model it has no id for. ## Validation On main d5b8333 (macOS 26.5, Bun 1.4.4): - `bun test server/start-screen.test.ts server/start-screen.contract.test.ts server/conventions.test.ts scripts/changelog-fold.test.ts`: 38 pass, 0 fail. The new test fails without the change (10 pass, 1 fail). - `bun test server/codex.test.ts server/conversation.test.ts server/codex-list-regression.test.ts server/codex-composer-regression.test.ts server/codex-linked-completion.test.ts server/codex-steering.test.ts server/prompt.test.ts`: pass, except three `Codex's store, read whether or not a Codex holds it (#2444)` cases that fail the same way on main without this change on this Mac. - `bun run typecheck`: pass. - Not run: `bun run check fast` / `full` as a whole. - Live, with the same change as a local patch on 0.4.22: a new Codex pane on a provider-named model opened on the empty new chat before its first message.
Problem
Typing
codexin a Herdr terminal and opening Chat before the first message said "Conversationunavailable", while a Codex started from New workspace, New tab or New worktree showed its greeting
(#990). Codex writes no session before the first message (0.163 makes no
state_5.sqliteat alluntil then), and herdr reports none, so nothing tied the pane to a transcript.
Fixes #1191
Fix
#990 left terminal launches out because they may resume a conversation. Chat now greets one only
when every fact says it has begun none, and otherwise keeps the terminal fallback as before
(
codexFreshSessioninserver/codex.ts, called from theno_session_pathfallback inpaneConversation):codexStartScreenUnused,server/start-screen.ts, sharing the footer rule the model is read by). Under the last bannerline (
>_ OpenAI Codex (v…), boxed or not, never an answer that only mentions it) the composeris the first prompt line, and no prompt, answer, warning or error cell follows it. None may sit
above the banner either: that would be a command's card or a second session in the same
terminal.
resumeorforkon the argv of the pane's Codex processes.and the foreground process's, as given and as they resolve), begun or written since those processes
started (a lower bound of their start, less a second), in the store the pane's Codex writes to. A
missing store holds none. That store must be placed for certain on every platform
(
certainProcessCodexHome): theCODEX_HOMEdirectory each Codex's environment names, or.codexin theHOMEits environment names when it names none (never the server's own home). An environment that cannot be read (another user's process, a goneone, Windows), a
CODEX_HOMEthat is relative or not a directory, and on macOS a command line thatspells
CODEX_HOME=orHOME=, noHOMEor a relative one, or aps -Eline with noenvironment all say no, as do a store or a start time
that cannot be read.
The answer is a conversation not begun, as for an app launch, with the model and effort the status
line states. Its history id names the pane and its Codex processes, with no time in it (a start
time read on macOS moves between reads), so the first message's transcript replaces it whole. A
resumed session still shows its saved messages through the existing lookup. Anything this cannot
identify keeps "Conversation unavailable". A launcher that picks another
CODEX_HOMEworks becausethe pane's own Codex home is the one checked.
Verification
server/conversation.test.ts,server/start-screen.test.ts): a Codex at its startscreen gets the greeting with no store, and with a store whose threads of the folder all ended
before it started. Each of these keeps "unavailable": a
resumeorforkcommand line, somethingsaid on screen, a pane at work, a thread of the folder (or of its resolved path, or of the
foreground folder) with a first message begun or written since, and an unreadable store. A thread
in another folder, a subagent's, a
codex execrun's, or one with no first message does not count.The screen cases cover a draft in the composer, an answer quoting the banner, a boxed banner and a
conversation above the banner. A second test starts real child processes with the
CODEX_HOMEunder test (server default store isolated): an absolute home greets; a relative one whose store holds
a conversation begun now, a non-directory, and a second Codex with a relative home do not. With no
CODEX_HOME, the store follows the child's ownHOME; with noHOMEthere is no greeting. Each childsays it runs before it is read, so the test does not race its exec (0 failures in 30 runs).
163/163 pass on Linux and on macOS 27 (the test MacBook Air, fresh clone). Restoring the
default-store fallback, or the server's
homedir(), fails the test on both.codex0.163.0 typed in a pane of the isolated test herdr session(throwaway
CODEX_HOME, closed provider), with Chat opened in headless Chrome:Medium chip, and the frame shows no "Conversation unavailable".
GET /api/pane/conversationanswers 200 withhistory_id: unwritten:codex:…, no turns, andmodel
gpt-6-sol/medium.while the turn runs.
bun run check faston d12ff6d: green (unit 7191 pass, 0 fail, 24 skip; typecheck, build, generated types and themes, workflow syntax ok).Reviews
foreground folder still matched) is fixed: the case now names the link as both folders, and dropping the
realpathSyncincodexFreshSessionfails it. LOWs left as follow-ups:unavailable", as on main: a warning counts as something said.
CODEX_HOMEguard on Linux only, and the fallback listing the pane'sCodex processes twice) went away with the merge-pass fix below, which places the store itself.
newer lookups (fix(chat): find a Codex session the picker resumed from another folder among the threads Codex has loaded #1941 loaded threads, fix(chat): offer the Codex thread its title names as a screen-match candidate #1790 title candidates, fix(codex): read the pane's Codex home as Codex does #1750 the pane's Codex home), which all run
before it. Two earlier rounds on the pre-rebase version found a HIGH (answer text taken for the banner) and
MEDIUMs (symlinked folder, relative
CODEX_HOME, macOS start time, foreground folder), all fixed.CODEX_HOMEfell back to theserver's default store, so a false greeting was possible. Fixed in c1b4e8d: the store is now placed for
certain on every platform, as described under Store. Its re-review of c1b4e8d found a HIGH (with no
CODEX_HOME, the store came from the server's home rather than the Codex's ownHOME) and a MEDIUM (thenew test raced its child's exec), both fixed in d12ff6d and 11d7b71.