Skip to content

Codex, phases 8 to 10b and the 10b review: Bibo's codex.rs, the repair asks Codex, steps, diagnosis and guard per agent, the screens, all hidden while Codex is closed - #57

Draft
undistracted2cha wants to merge 38 commits into
masterfrom
feat/codex-bibo
Draft

undistracted2cha wants to merge 38 commits into
masterfrom
feat/codex-bibo

Conversation

@undistracted2cha

@undistracted2cha undistracted2cha commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Phases 8 to 10b of the Codex plan (docs/proposals/codex.md, §2.4, §4 and §6): Bibo's phases, all on this branch. Codex stays closed on every system: in production an agents.json that lists Codex is not trusted, so the repair (phase 9) asks no one and the screens (10b) do not show it, and Bibo without Codex behaves exactly as on master.

app/src-tauri/src/codex.rs

The Rust copy of the kit's launcher without tools (engine/hooks/_headless_codex.py), for Bibo:

  • Finding Codex (find): the official installer's place first (~/.local/bin/codex, %LOCALAPPDATA%\Programs\OpenAI\Codex\bin\codex.exe), then the PATH and Homebrew's folders; on Windows an .exe only (npm's codex.cmd goes through cmd.exe).
  • The ChatGPT login, without a billed key (login, §4.3): chatgpt, billed, managed, logged_out or unknown. auth.json is read for its mode, its plan and whether a refresh token is there, nothing else. Then codex login status, run as a question would run it (same allow-list environment, same -c), is compared to fixed lines and never copied: its stderr shows part of an API key. No key ever reaches Codex; Bibo never logs anyone out.
  • The contract without tools (check, ask): the launcher's checks before a question, in its order (Windows %ProgramData%\OpenAI\Codex, version and exec --help, .env, managed layers, auth.json and plan, login status, features list with the user's and an empty CODEX_HOME, MCP servers), the same -c, the same refusals and pauses (kind, reason and words), the same private folder, the same reading of the stream, the prompt on stdin only, --ephemeral. « Arrêter » is honoured between the probes and before the question.
  • sys::run_isolated_pipes: each line with its pipe (Codex says its login on stderr), and once Codex exits, what it left in its group is killed, as the launcher does on macOS and Linux. run_isolated (Claude's repair) is unchanged.

Where the two differ, the app is stricter (said at the top of codex.rs): a stream line that opens an object and is not JSON ends the run (Python reads NaN), an id_token with a character outside base64url is unreadable, a profile that is not a regular file counts as unreadable.

Parity: one test that fails when the two diverge

engine/tests/codex_contract.py describes the scenarios (114 on macOS, 109 on Linux and Windows): a home, a CODEX_HOME, managed layers, an environment and fake_codex.py's settings each. The Rust test the_app_and_the_launcher_answer_alike plays each one twice, in a world of its own, through codex.rs and through _headless_codex.py, and compares:

  • the answer or the refusal, with its words;
  • everything the fake Codex was given: each probe and the call, argv and -c in order, environment, folder, stdin, schema;
  • the work folder empty afterwards, what Codex started gone;
  • no token or key in what either side writes.

Scenarios include the order of the checks (two faults at once: the first check says why) and, on Windows, a %ProgramData%\OpenAI\Codex that appears after the probes. A second test compares the decision on Windows access lists (47,580 cases, on all three systems) and SIDs. Without Python both fail: no skip.

Found: codex-features.json was installed nowhere

The installed launcher (~/.claude/hooks/brain/_headless_codex.py) looks for codex-features.json next to itself: neither installer put it there, so Codex would have stayed paused for everyone once opened. Tests and codex-mock ran the launcher from the repository, where the file is one folder up. install.sh and install.ps1 now place it in their Codex section only (Claude alone: nothing changes); Bibo reads it at the same place. test-hooks.sh §16 and the windows job check the installed file and that the installed launcher reads it.

Not hollow

27 protections taken out one at a time, 25 in codex.rs and sys.rs and 2 in the launcher (a -c, the order of the checks, features list with an empty CODEX_HOME, auth.json, a caller's key passed on, a billed login line, login status's line copied, a tool item taken as an answer, --ephemeral, the group sweep, the cage left behind, the login shown, access lists, SIDs, the strict schema, the prompt as an argument, the MCP re-read, the removed stage, the minimum version, the repr of the words, the .env "CA" rule, the Team plan, an unreadable profile, an MCP server named in a comment; in the launcher notify=[] and the login status line). Each turns at least one test red; two did not at first and got their scenario (a .env setting LOCALAPPDATA, a profile that is a folder). Without install.sh's new line, test-hooks.sh is 220/221.

Checked locally (macOS)

cargo test (169), cargo clippy --all-targets -D warnings for macOS and for the Windows target (compile only, resource compiler stubbed), rustfmt on codex.rs only (the repository's style; sys.rs's deviations are master's), Python unit tests (649; the launcher's and the contract also under Python 3.9.6), test-hooks.sh 221/221, shellcheck, actionlint, bash -n, py_compile, node --check. No pwsh on this machine: install.ps1's line and the windows job are checked in CI only.

CI


Phase 9: the repair with Codex

Bibo's repair asks Codex when agents.json lists it (docs/proposals/codex.md, §2.4, §4.4; section « Étape 9 — fait et écarts »). Codex stays closed on every system: in production an agents.json that lists Codex is not trusted (ferme), and the repair then asks no one.

  • The choice, read by the kit (agents.rs): _agents.py lire (new subcommand, one ASCII JSON line of what lire() says), run with the kit's Python, the installed copy next to the hooks first, else the one of the sources Bibo installed. The gate and the file's checks stay in _agents.py. Without the file: Claude alone, and nothing is run to know it. A file the kit cannot trust, or one Bibo cannot have read (no Python, no _agents.py): no AI is asked (new state agents).
  • The same question: the same dossier on stdin (what « Voir exactement ce que j'envoie » shows), the same instructions, the same schema of the same closed lists, effort medium then high, the same validate(). Codex through codex.rs (ask_heard: told when the question leaves, and each stream line, kept masked in codex-stream.jsonl). Catalogue unchanged.
  • The fallback is the kit's (_headless.py): the preferred engine, then the other one only when listed, after start, unsupported, auth, quota, api; after a timeout only towards Claude; never after init, invalid or « Arrêter ». An engine found unavailable before (not logged in, paused, offline) is never run. When none answers, the first one run says why; the others go to the journal (echecs) and the report.
  • Claude in Terminal (plan B) stays Claude's, and only when Claude is listed: terminal_fallback, the last screen's button, and open_terminal refuses otherwise.
  • The screens: the repair texts come from a name (ai()); Rust names the engine (engine in the status and the plan, stages asking_codex / asking_claude) only when Codex is listed. Codex's ChatGPT login button is phase 10b.

Claude alone, exactly as master

  • Without agents.json nothing is run to read it; the status, the plan and the asking stage are master's JSON (no engine); the journal entry has master's keys, one by one; the report names no engine; every earlier repair.rs test passes unchanged.
  • The screens: master's app.js with master's mock, and the branch's with the branch's, run in a small DOM under Node on 29 Claude-alone repair scenarios (Mac, Windows, Linux words; fixed, user action, low confidence, two rounds, failed down to Terminal, regression, quota, re-login, suspect, offline, Terminal, login put off, each error, each state, « Arrêter »): every screen has the same text, order and buttons. Control: one word changed in a note makes them differ. (No browser: Playwright is phase 10b's.)

Not hollow

33 protections taken out one at a time (the fallback rule, Terminal only when Claude is chosen, what the window is offered, Codex's refusals and what counts, the same schema, instructions and effort, the names in the journal and report, agents.rs's reading): each turns at least one test red. One did not at first (a reader that fails) and got its test.

Checked locally (macOS)

cargo test (187), cargo clippy --all-targets -D warnings for macOS and the Windows target (compile only), rustfmt in the repository's style on agents.rs and codex.rs (repair.rs: nothing beyond master's deviations), Python unit tests, test-hooks.sh 221/221, actionlint, node --check, py_compile.

CI


Phase 10a: Bibo's brain, steps, diagnosis and configuration guard per agent

Bibo's back end follows the agents agents.json lists, read through _agents.py lire (phase 9) (docs/proposals/codex.md, §4.2, §4.5; section « Étape 10a — fait et écarts »). Codex stays closed on every system: in production an agents.json that lists Codex is not trusted, and nothing below shows for Claude alone.

  • The brain's state per agent (detect.rs): the vault and the memory, then each listed agent's part. Claude's as before (hooks in settings.json, skills). Codex's: the kit's hook in its hooks.json, the kit's block in the instructions Codex reads (AGENTS.override.md when it has text, else AGENTS.md), the skills in ~/.agents/skills. Complete for each agent listed; the brain step runs again when a chosen agent is not wired. A choice the kit cannot trust is never complete.
  • The Codex step (steps.rs): where Claude Code's stands, the preferred one first (steps::order). It runs the official installer of the rust-v0.162.1 release, checked against the SHA-256 install.sh and install.ps1 pin (a test holds the three equal), as they run it: CODEX_RELEASE, CODEX_NON_INTERACTIVE=1, the CODEX_HOME of agents.json, no VOYAGE_API_KEY nor the installer's own settings, Windows' tar first on the PATH. A Codex already there is kept; an older one is said, not replaced (as install.sh). A script that is not the pinned one never runs. The app job runs the step for real on each system (codex_real).
  • The diagnosis per agent (diagnose.rs): Codex (version), its login (codex::login: ChatGPT account ok; an API key "would be billed: I don't use it"; a workspace account or imposed settings; not logged in), its hooks (and whether Codex runs them: new _agents.py hooks-muets, Bibo works nothing out itself), instructions and skills; each agent's site in the network check (claude.ai, chatgpt.com). Codex alone runs nothing of Claude's. An untrusted agents.json gives a red « Ton choix d'IA » line, and the brain step stops before downloading anything (the installers would stop anyway).
  • The configuration guard (config_guard.rs): ~/.codex always (a Codex of the user's own, Claude alone included) and the CODEX_HOME of agents.json, wherever it is. hooks.json as settings.json; config.toml: only [hooks.state."<key>"] tables added at its end, one hash each, each naming one of the kit's hooks in that folder's hooks.json (group without a matcher, every command the same kit hook), and in a table of the kit's its hash and comment (another Python); nothing else (no setting, no approval of the user's hook or another hooks.json's, no hash slipped into the user's last table). AGENTS.md appended to; rules and ~/.agents/skills as hooks and skills. Checked against the installers' own wire.py: nothing to put back.
  • remedies.rs: .codex and .agents in the catalogue test's NEVER list.

Claude alone, exactly as master

  • Tests: every check word for word (network text, the brain's ids and order, missing parts and their order), the steps' order, nothing run without agents.json.
  • Local comparison, master (e6b8be0) and the branch, --diagnose in four homes (empty, Claude's brain, agents.json ["claude"], a Codex of the user's own without a choice): identical JSON (free space aside). The only difference, by design: an agents.json listing Codex (closed) gives the red « Ton choix d'IA » line.
  • The guard: the real install.sh, Claude alone, next to a ~/.codex of the user's: untouched.

Not hollow

41 protections taken out one at a time: 40 turn at least one test red. Seven did not at first and got their test (approval keys of the tests named another folder's hooks.json; a hash appended right after the file's end read as a change in place; the guard's own record already made the kit's skill "ours"; completeness ignored the instructions). The 41st, .codex/.agents in NEVER, only guards against a future remedy.

Checked locally (macOS)

cargo test (205; the real Codex install, ignored, runs in CI), cargo clippy --all-targets -D warnings for macOS and the Windows target (compile only), rustfmt in the repository's style on the phase's lines only, Python unit tests (651; _agents.py's also under Python 3.9.6), test-hooks.sh 221/221, actionlint.

CI


Phase 10b: Bibo's screens for Codex (the choice, Codex's step, its ChatGPT login, the onboarding), hidden while the gate is closed

docs/proposals/codex.md, §4.1, §4.3, §4.4; section « Étape 10b — fait et écarts ». Codex stays closed on every system: as shipped the app asks nothing and every screen is master's.

  • The gate, read in the kit (agents::codex_open): the CODEX_OUVERT line of the _agents.py that reads agents.json (installed, else the sources'), else, before any kit is on disk, the app's own copy of that file (include_str!). Read without Python (a fresh Mac or PC has none): only the line as the kit writes it; anything else is closed. A test plays every form against _agents.py ouvert. release.yml, test.yml's app job and the terrain's preview freshness follow _agents.py: the PR that opens a system publishes an app that offers it.
  • The choice (§4.1), before the diagnosis, whose checks and steps follow it: the welcome names no AI and leads to « Avec quelle IA veux-tu travailler ? » (Claude, Codex, both; for both, who writes the evening summary, said both ways). Rust holds it for the session (choose_agents, agents::current); the brain step hands it to install.sh / install.ps1 (BIAB_AGENTS, BIAB_PREFERE), which alone write agents.json. Preselection: the choice made, else Claude alone on an install of before the choice, else what is installed.
  • Codex's ChatGPT login (§4.3): codex -c cli_auth_credentials_store="file" login in Terminal / PowerShell, without OPENAI_API_KEY, CODEX_API_KEY, CODEX_ACCESS_TOKEN, OPENAI_BASE_URL; the window polls codex::login, never Codex's output. An API key or a workspace account is said and not used; Bibo never logs anyone out; « Plus tard ». The repair gets the same button.
  • Onboarding and the assistant's name (§4.4): the preferred agent, opened in the vault (codex "<prompt>"); ONBOARDING.md speaks to Claude Code or Codex; the end names the agents chosen.
  • Mock app/dev/mock.html: &porte=1, &choix=, &resume=, &codex=billed|managed|unknown; checked on screen with Playwright (Mac, Windows, Linux words).
  • terrain_app, path app-codex on the three systems (terrain.yml matrix): the robot opens Codex in its own copy of the kit (the tested sources, gate open, as the other benches do), handed to the app and put in ~/.brain-in-a-box/src before its first start; it clicks « Choisir mon IA », « Codex », skips the Voyage key and the ChatGPT login. Codex's step must be seen, Claude's never; then terrain.check_codex: agents.json, codex --version, the six hooks with --agent codex approved, the kit's correction-detector run as Codex runs it, Codex's AGENTS.md and the vault's, the skills in ~/.agents/skills, nothing of Claude Code's.

Claude alone, exactly as master

  • Closed as shipped: nothing is offered or looked for (offer), choose refuses Codex, no choice is pending, the installer gets what it got; 10a's tests of the diagnosis, steps and guard pass unchanged.
  • Screens: master's app.js with master's mock and the branch's with the branch's, in a small DOM under Node, on 41 Claude-alone scenarios (fresh install on Mac, Windows, Linux, Voyage key, already installed, keywords, blocked, early login, failures, and phase 9's 29 repair scenarios): 39 give the same screens in the same order; the 2 clock-driven loops give the same screens in an order that varies from run to run, on master too. The only difference: the welcome comes after the gate is read, with the same words. Control: one word changed makes them differ.
  • terrain_app's path app (Claude alone, real window) is unchanged, except that a Codex screen there now fails.

Not hollow

33 protections taken out one at a time (17 in the app, 16 in the robot): 32 turn at least one test red; five of the robot's did not at first and got their test; the 33rd (an unreadable _agents.py read as empty text) is equivalent: no gate line, closed.

Checked locally (macOS)

cargo test (211, 5 ignored), cargo clippy --all-targets -D warnings for macOS and the Windows target, rustfmt on the phase's lines, Python unit tests (661), test-hooks.sh 221/221, actionlint, the mock on screen (Playwright).

CI

Phase 10b review: fourteen findings, twelve fixed

docs/proposals/codex.md, section « Étape 10b — relecture et corrections ». Every fix has a test that was red before it. Codex stays closed; with Claude alone every screen is master's, now held in CI word for word.

Security

  • Codex's onboarding on an API key (findings 1 and 9): Codex preferred and logged in with a key (or not at all), « Plus tard » at the ChatGPT screen, then « Personnaliser mon cerveau » ran a 15-minute codex session billed on the key in auth.json. Now start_onboarding asks codex::login and opens nothing but on a personal ChatGPT login, with -c cli_auth_credentials_store="file"; the end offers « Connecter Codex à mon compte ChatGPT » instead, with a note per state.
  • CODEX_HOME from the shell profile (2): the login and onboarding windows unset it when agents.json records ~/.codex.
  • A stream line with no end (3): sys::pump reads at most the cap of a line and drops the rest, as the launcher's _pump (Codex only; Claude's repair unchanged).
  • The current folder on Windows (4, before this PR): find_codex (launcher) and codex::which (app) look in absolute PATH folders only. _headless_claude.find_claude has the same flaw on master: left to a PR of its own (Claude's path).

Non-regression

  • agents.json ["claude"] with no kit on disk or no Python (5): the app runs its own copy of _agents.py; with no Python at all, Claude alone where the gate keeps Codex closed (master's behaviour).
  • The guard for Claude alone (6): ~/.codex and ~/.agents/skills are guarded only when Codex is listed; master never looked there.
  • Claude-alone screens in CI (7): app/dev/screens.mjs runs app.js and the mock in a small DOM on a clock of its own (deterministic), 43 scenarios compared screen by screen with app/dev/screens-claude.txt, written from master's app.js and mock (e6b8be0); run by the app job. Plus terrain_app: « pour Claude » in the welcome, « Claude retient » at the end.
  • Plan figures (8): corrected in both copies.

Codex's screens (gate open in the mock): a workspace account or Windows' system settings end the login's wait and say why (codex::Login::System split from Managed); not_yet in the repair before the brain step; « Changer d'IA » on the diagnosis and the accounts' screens; one account rule (« un abonnement ChatGPT personnel (pas un compte d'entreprise) », « Il te faut les deux comptes »); the API key's screen asks for the button, no command. Nine mock scenarios check them in the same script; terrain_app's app-codex expects the ChatGPT login at the end, never the onboarding.

Checked locally (macOS): cargo test (217 + 1, 5 ignored), clippy for macOS and the Windows target, rustfmt on the lines touched, Python tests (664, 7 skipped; test_headless_codex under 3.9.6 too), test-hooks.sh 221/221, actionlint, node app/dev/screens.mjs, the new screens on Playwright.

CI: tests https://github.com/BrainInBox/brain-in-a-box/actions/runs/39044551159 (087405d), all 13 jobs green (parity on the three systems, the screens' check in the app job, app-windows-install, codex-mock). terrain.yml by hand on the branch: https://github.com/BrainInBox/brain-in-a-box/actions/runs/39043712047 (d373d3e, the same app), all green, including app and app-codex on macOS, Windows and Linux. The run before (https://github.com/BrainInBox/brain-in-a-box/actions/runs/39043712739) failed on Windows' app job only: a Windows-only test still expected the prompt right after codex.exe, before the store's -c (fixed in 087405d, nothing in the app).

…eaves behind goes with it

sys::run_isolated_pipes gives each line with the pipe it came from (Codex says its
login on stderr, its stream is stdout alone) and, once the program has exited, kills
what it left in its group, as the kit's launcher does on macOS and Linux.
run_isolated, which Claude's repair uses, does exactly what it did (test, both ways).
… key, the launcher's contract in Rust (phase 8)

app/src-tauri/src/codex.rs is the Rust copy of engine/hooks/_headless_codex.py:
find() looks where OpenAI's installer puts Codex, then the PATH (an .exe only on
Windows); login() says chatgpt, billed, managed, logged_out or unknown from auth.json's
mode, plan and refresh token and from `codex login status` compared to fixed lines,
never copied; check() and ask() run the launcher's checks in its order, with the same
-c, refusals, pauses and words, the same private folder and stream rules, the prompt on
stdin only. Nothing calls it yet (repair: phase 9, screens: 10b); Codex stays closed.

engine/tests/codex_contract.py holds the scenarios (114 on macOS, 109 on Linux and
Windows). The test the_app_and_the_launcher_answer_alike plays each through codex.rs
and through the launcher, each in a world of its own, and compares the outcome with its
words and everything the fake Codex was given (probes, call, -c in order, environment,
folder, stdin, schema), the work folder left empty, Codex's children gone, no token in
either record. Another compares the Windows access-list decision (47,580 cases) and SIDs.
Without Python both fail. fake_codex.py can plant a %ProgramData% folder at the last
probe. plist (macOS) was already in the build through tauri.
… is chosen

The installed launcher (~/.claude/hooks/brain/_headless_codex.py) reads
codex-features.json next to itself, and neither installer put it there: once Codex
opened, it would have stayed paused for everyone. Tests ran the launcher from the
repository, where the file is one folder up. install.sh and install.ps1 now place it in
their Codex section only; Claude alone installs exactly what it did. test-hooks.sh §16
(220/221 without the fix) and the windows job check the installed file and that the
installed launcher reads it.
codex.rs and its parity with the launcher, where the app is stricter, « Arrêter », the group swept, login next to check, codex-features.json installed nowhere until now; local checks.
The windows job's check imported ~\.claude\hooks\brain\_headless_codex.py, and Python
wrote its __pycache__ there: the step's comparison of Claude's install then saw new
files ("Claude's install changed"). Both checks (test-hooks.sh §16 too) now run
python -I -B.
Tests and terrain green on the branch; the first windows run's bench defect (__pycache__) and its fix.
One ASCII JSON line (etat, agents, prefere, codex_home), exit code 0: Bibo reads
agents.json through the kit's own reader and gate instead of judging the file itself.
… the kit does (phase 9)

agents.rs reads the choice through _agents.py lire (none of it without the file:
Claude alone, nothing run; an untrusted or unreadable one: no AI asked). repair.rs
asks the preferred engine, then the other one listed after the errors _headless.py
falls back on: the same dossier on stdin, the same instructions, the same schema of
the same closed lists, the same checks of the answer. Codex goes through codex.rs
(ask_heard: told when the question leaves and each stream line). Claude in Terminal
only when Claude is listed. With Claude alone, the status, plan, stages, journal and
report are what they were: nothing names an engine.
The repair texts come from the AI's name (Claude's words unchanged), from what
repair_status, the plan and the stages name; Codex's ChatGPT login button waits for
phase 10b. The mock gets &agents=, &secours=1 and &repair=agents.
The repair with Codex: agents.json through _agents.py lire, the same question, the
kit's fallback; what differs from the plan, the proof for Claude alone, local checks.
… its instructions byte for byte

agents.rs dropped a codex_home that is not absolute on Windows ("/c") instead of
refusing the line. fake_codex.py wrote the instructions it was given in text mode,
so on Windows their line ends came back as CRLF.
Tests and terrain green on the branch; the two Windows-only test defects of the first
run and their fix; codex-mock's known sign-of-life race seen once on macOS.
@undistracted2cha undistracted2cha changed the title Codex, phase 8: Bibo's codex.rs, Codex found, its ChatGPT login, the launcher's contract in Rust (Codex closed on every system) Codex, phases 8 and 9: Bibo's codex.rs, and the repair asks Codex when agents.json lists it (Codex closed on every system) Oct 17, 2026
hooks_muets() of the CODEX_HOME a trusted agents.json records ("non" without one that
lists Codex): Bibo's diagnosis says it without working it out again.
…odex's checks, Claude's only when listed (phase 10a)

- detect.rs: the brain's state per agent. Claude's part as before; Codex's: the kit's hook
  in its hooks.json, the kit's block in the instructions Codex reads, the skills in
  ~/.agents/skills. Complete for each agent listed; a choice the kit cannot trust is never
  complete.
- steps.rs: the agents' steps where Claude Code's stands, the preferred one first. The Codex
  step runs the official installer of the pinned release, checked against the SHA-256
  install.sh and install.ps1 pin (a test holds them equal), as they run it. The brain step
  stops on an untrusted choice before downloading anything.
- diagnose.rs: Codex, its ChatGPT login (codex::login), its hooks (and whether Codex runs
  them, _agents.py hooks-muets), instructions and skills; each agent's site in the network
  check; a red line for an untrusted choice. Codex alone runs nothing of Claude's.
- test.yml: the Codex step for real in the app job, on each system.

Without agents.json, or with Claude alone, every check, text, step and order is master's.
…oml, only the kit's approvals may appear

~/.codex always (a Codex of the user's own, Claude alone included) and the CODEX_HOME
agents.json records: hooks.json as Claude's settings.json; config.toml takes only
[hooks.state."<key>"] tables added at its end, one hash each, each naming one of the kit's
hooks in that folder's hooks.json (and, in a table of the kit's, its hash and comment);
AGENTS.md appended to; the rules and ~/.agents/skills as hooks and skills. Checked against
the installers' own wire.py. .codex and .agents join the remedies' NEVER list.
Bibo's brain state, steps, diagnosis and configuration guard per agent: what differs from
the plan (the pinned Codex installer, an untrusted choice blocks, the guard wider and
config.toml stricter), the proof for Claude alone, the mutations, local checks.
snapshot_of() keeps the system's separator: on Windows ".codex\hooks.json" missed the arm
that lets hooks.json gain the kit's hooks, so both tests failed there. The guard itself was
right (the other Codex tests passed on Windows).
- test_agents: `_agents.py hooks-muets` prints its word with print(), CRLF on Windows (the
  app trims it); the test compares the word.
- codex_real: the test gave the official installer a CODEX_HOME in Windows' \\?\ form
  (fs::canonicalize of the temporary folder), which its Join-Path refuses. agents.json
  records a plain path: the test now gives one.
Tests and terrain green on the branch, the real Codex step on each system; the three
Windows-only test defects of the first runs and their fix.
@undistracted2cha undistracted2cha changed the title Codex, phases 8 and 9: Bibo's codex.rs, and the repair asks Codex when agents.json lists it (Codex closed on every system) Codex, phases 8, 9 and 10a: Bibo's codex.rs, the repair asks Codex, and Bibo's steps, diagnosis and guard per agent (Codex closed on every system) Oct 17, 2026
…, and holds the choice until the installer records it (phase 10b)

- agents.rs: codex_open() reads the gate in the kit's _agents.py, the copy that reads agents.json
  (installed, else the sources'), else, before any kit is on disk, the app's own copy of that file
  (include_str!). Read without Python, which a fresh Mac or PC lacks: only the gate's line as the kit
  writes it; anything else is closed. A test plays every form of the line against `_agents.py ouvert`.
- choose() holds the window's pick for the session, for its home; current() is that pick while
  agents.json does not record it (etat "choix"), else agents.json. Codex's folder is the one
  agents.json records, else the one the installer will record ($CODEX_HOME, else ~/.codex, as
  _agents.codex_home() reads it; a test compares the two). offer(): the gate and the preselection
  (the choice made, Claude alone on an install of before the choice, else what is installed).
- The diagnosis, the steps, the repair and the configuration guard follow current(). A pending
  choice keeps the brain incomplete and shows « Ton choix d'IA : je le note en installant ton
  cerveau », and the brain step hands it to install.sh and install.ps1 (BIAB_AGENTS, BIAB_PREFERE);
  without one nothing is added: the installer runs as before.
- steps.rs: Codex's ChatGPT login (`codex -c cli_auth_credentials_store="file" login`, in Terminal or
  PowerShell) and the onboarding by the preferred agent (`codex "<prompt>"` in the brain); no key of
  the user's shell reaches Codex there, CODEX_HOME only when it is not Codex's default.
- lib.rs: agents_offer, choose_agents, codex_login, open_codex_login.

As shipped Codex is closed everywhere: nothing is offered, and Claude alone goes as on master.
…, the onboarding by the preferred AI

Only where the kit lets Codex be chosen (agents_offer): the welcome names no AI and leads to « Avec
quelle IA veux-tu travailler ? » (Claude, Codex, les deux; for both, who writes the evening summary,
said both ways), asked before the diagnosis, whose checks and steps follow it. Codex has its step
(« J'installe Codex. »), its login (« Dernière étape : ton compte ChatGPT », the billed key and the
workspace account said, never logged out), the end names the agents chosen and the onboarding the
preferred one. The repair gets Codex's ChatGPT button. Closed, as shipped: no choice is asked and every
screen is master's (the mock's 42 scenarios of Claude alone compared with master's, screen by screen).

app/dev/mock.html: &porte=1 (implied by an agents.json that lists Codex), &choix=, &resume=, &codex=.
ONBOARDING.md speaks to Claude Code or Codex: the kit's block is in CLAUDE.md or in Codex's AGENTS.md.
…p and runs its tests

Before any kit is on disk, the app reads the gate in its own copy of engine/hooks/_agents.py: the PR
that opens Codex on a system must publish an app that offers it. release.yml builds on that file too,
test.yml's app job runs when it changes, and terrain_app's freshness check of the preview counts it
(PUBLIE, next commit). test_release_workflow holds the three together.
…he three systems (app-codex)

Each app job of terrain.yml runs two paths (matrix): "app", Claude alone, as before and as users get
the app (a choice screen there fails: the app as shipped keeps Codex closed), and "app-codex". There
the robot opens Codex in its own copy of the kit, as the other benches do: the tested commit's
sources with _agents.py's gate open (zip entries and modes otherwise as git archive gives them), handed
to the app (BIAB_ARCHIVE, on master too) and put in ~/.brain-in-a-box/src, where the app reads the
gate before installing; the marker stays out, so it still proves the app installed from the archive.
The robot clicks « Choisir mon IA », « Codex », skips the Voyage key and the ChatGPT login; Codex's
step must be seen, Claude's never, and the end must name Codex. terrain.check_codex: agents.json says
Codex alone, Codex answers, its hooks.json runs the six hooks with --agent codex (Windows: the
PowerShell form, on winget's Python), the kit approved them, the kit's correction-detector run as Codex
runs it leaves its sign of life, Codex's AGENTS.md and the vault's, the skills in ~/.agents/skills, and
nothing of Claude Code's. The report expects macos-app-codex, windows-app-codex, linux-app-codex.
…8), not the console's code page

agents::tests::codexs_folder_is_the_one_the_installer_records compared the app's Codex folder with
_agents.codex_home() printed by Windows' Python, which writes an accented path in the console's
code page: from_utf8 failed on « Données é ». The app is unchanged.
…Git Bash, Codex looked for where the driven system puts it

- check_git: Claude Code's Git Bash check (git-bash) runs on the path of Claude alone only. With Codex
  chosen alone there is no Claude Code to ask, and Codex runs its commands through PowerShell:
  gbq.cmd is check_rest's. The run on the branch stopped there (« Claude Code n'est pas installé »).
  The path of Claude alone checks the same, in the same order, and says the same.
- Codex's place comes from the pilot (Pilote.codex_installe: ~/.local/bin on a Mac or Linux,
  LOCALAPPDATA on Windows), not from the system the harness runs on: test_terrain_app's fake Mac,
  run on the Windows runner, looked under LOCALAPPDATA.
… red

Each 10b protection of the harness was taken out alone; five left every test green, and now have one:
Claude's login screen on the path of Codex alone, the choice asked again at the second start, the
robot's marker kept out of the sources planted before the app's first start, agents.json written by
the installer of this system (pose_par), and the kit's files checked against the robot's copy (gate
open) with codex-features.json.
@undistracted2cha undistracted2cha changed the title Codex, phases 8, 9 and 10a: Bibo's codex.rs, the repair asks Codex, and Bibo's steps, diagnosis and guard per agent (Codex closed on every system) Codex, phases 8 to 10b: Bibo's codex.rs, the repair asks Codex, steps, diagnosis and guard per agent, and the screens (choice, ChatGPT login, onboarding), all hidden while Codex is closed Oct 17, 2026
…eld whole

sys::pump reads at most the cap (plus one byte) of a line at a time when run_isolated_pipes
is given one, and drops the rest of a longer line up to its newline, as the launcher's _pump
does with readline(LINE_CAP + 1). Before, a Codex printing without a newline was held in
memory whole until it was killed (150 s, or 60 s for a probe). Claude's repair (run_isolated)
reads as before.
…and by the launcher

shutil.which puts the current folder first on Windows, even with path= (_win_path_needs_curdir):
a codex.exe in the folder a session runs `controle` from would have been run by the night's
launcher, Codex being out of its official place. An empty or relative PATH entry is a folder of
wherever the task runs from too. _headless_codex.find_codex now looks only in absolute folders,
and codex::which (the app) drops relative entries as well as empty ones. Tests: a codex in the
current folder and under a relative entry is never found, an absolute one still is.

_headless_claude.find_claude has the same flaw on master; it is left to a PR of its own (Claude's
path is out of this one).
…e, as on master

An install made from a terminal with --agents claude (or BIAB_AGENTS=claude) has agents.json and
no sources in ~/.brain-in-a-box/src. Once ~/.claude/hooks/brain is gone (Claude Code reinstalled
over ~/.claude), the app had no _agents.py to read the file and gave no agent: a red, blocking
« Ton choix d'IA » line, the brain step and the onboarding refused, no Claude in Terminal. Master
never read the file and would have reinstalled.

- No _agents.py on disk: the app runs its own copy (the one codex_open already falls back on),
  from a private folder of its own, with the kit's Python. _agents.py stays the only reader.
- No Python at all: where the kit's gate keeps Codex closed, Claude alone (the kit trusts no file
  that lists Codex there, and the installer reads the file itself once Python is in); where Codex
  can be chosen, no agent, as before (the window asks the choice again anyway).
… the agents

With Claude alone the guard watched ~/.codex and ~/.agents/skills too, which master never did: the
user's own Codex writing there during the brain step or a repair (a folder trusted, /hooks, a skill)
made the step fail (« L'installation touchait à des fichiers à toi ») and was put back. install.sh
and install.ps1 do not write there for Claude alone (test-hooks.sh §16, same-as-master.ps1, and
the_real_install_sh_cannot_damage_the_users_files, which now compares Codex's files without the
guard). When Codex is listed (agents.json, or a choice the installer is about to record), ~/.codex,
the CODEX_HOME agents.json records and ~/.agents/skills are guarded as before.
…ell's CODEX_HOME; « not yet » before the brain

- start_onboarding (Codex preferred) asks codex::login first and opens nothing unless Codex is
  logged in with a personal ChatGPT plan: an API key in auth.json billed the whole 15-minute
  session (taking keys out of the environment does nothing for a key in the file), and a Codex not
  logged in offered « Provide your own API key » on its first screen. The onboarding's codex runs
  with -c cli_auth_credentials_store="file", the store codex::login read.
- The login and onboarding windows unset CODEX_HOME (Remove-Item on Windows) when agents.json
  records ~/.codex: Terminal and PowerShell run the user's profile first, whose CODEX_HOME would
  have sent the login and the session to another folder.
- codex::Login::System: Windows' %ProgramData%\OpenAI\Codex open to other accounts, apart from a
  workspace account (Managed). No login fixes it; the diagnosis says so, and Managed now says a
  workspace account only (« l'administrateur de ce Mac » matched no case). The API key's line asks
  for the login button, which rewrites auth.json with the ChatGPT account, not codex logout.
- Repair, Codex before the brain step installed codex-features.json: state not_yet (« Codex pourra
  m'aider une fois ton cerveau installé ») instead of « too old or not supported », nothing run.
app/dev/screens.mjs runs app.js and the mock's fake backend in a small DOM on a clock of its own
(each timer in order, nothing waits, the same screens every run) through 43 scenarios with Claude
alone: a fresh install on each system, a Voyage key, already installed and the end's two buttons,
keywords, blocked, an early login, failures, the repair with Claude, its errors and its states. It
compares every screen (title, text, notes, buttons) with app/dev/screens-claude.txt, written from
master's app.js and mock.html (e6b8be0): the branch shows the same. A word changed in any of them
turns the app job red; --write rewrites the file for a change made on purpose. Before, only a local
script compared them, and the job only parsed app.js.
… account says so, change of AI, one account rule

Shown only where the kit lets Codex be chosen; with Claude alone every screen is master's
(app/dev/screens.mjs). Checked by nine scenarios of the mock, Codex open as the tests open it,
each red before this change:
- The end, Codex preferred and not logged in with ChatGPT (login put off, an API key, a workspace
  account): « Connecter Codex à mon compte ChatGPT » instead of « Personnaliser mon cerveau », a
  note per state (an API key would be billed, its login replaces it; logged out: pick « Sign in
  with ChatGPT », never a key), the onboarding after the login. Claude preferred: Claude's
  onboarding, the note says Codex's state.
- The login's wait ends when Codex logs in a way the kit does not use (a workspace account, a key,
  Windows' system settings): the screen says why instead of « J'attends » for ever. A workspace
  account keeps the button (« ton espace personnel »); the system's settings have none, only
  « Plus tard ». The same in the repair's login.
- An API key: « Clique sur le bouton et connecte-toi avec ChatGPT : ta connexion remplacera la
  clé », no command to type.
- Repair state not_yet: « Codex pourra m'aider une fois ton cerveau installé ».
- « Changer d'IA » on the diagnosis and the accounts' screens: back to the choice.
- One account rule on the welcome, the choice and the login: « un abonnement ChatGPT personnel (pas
  un compte d'entreprise) », and « Il te faut les deux comptes » for both.
The mock learns &after=, &codex=system, a list for &choix=, and not_yet before the brain step.
…'s path names Claude in the welcome and the end

- app-codex: the robot puts the ChatGPT login off, so the end must offer « Connecter Codex à mon
  compte ChatGPT » and « Ouvrir mon cerveau dans Obsidian », never « Personnaliser mon cerveau »,
  and say to pick « Sign in with ChatGPT ».
- app (Claude alone): « pour Claude » in the welcome and « Claude retient » at the end, as the
  Codex path already checked its own end. Every word of these screens is app/dev/screens.mjs's.
- The screens of a Codex logged in otherwise: « Codex est connecté avec un compte ChatGPT
  d'entreprise », « Codex suit des réglages de ce … », never on either path.
Each check turned red first in test_terrain_app.
…fits the system's settings

Seen in the mock: « Pas d'autre ordinateur sous la main ? » read oddly under the screen of
Windows' system settings; « Pour avancer sans Codex, change d'IA. » there, the account question on
the other accounts' screens.
…mes before the prompt

The Windows-only test still looked for « codex.exe' 'Read … » right after the program, which the
store's -c now separates (run 39043712739, job app on Windows); the two checks are one.
@undistracted2cha undistracted2cha changed the title Codex, phases 8 to 10b: Bibo's codex.rs, the repair asks Codex, steps, diagnosis and guard per agent, and the screens (choice, ChatGPT login, onboarding), all hidden while Codex is closed Codex, phases 8 to 10b and the 10b review: Bibo's codex.rs, the repair asks Codex, steps, diagnosis and guard per agent, the screens, all hidden while Codex is closed Oct 17, 2026

This branch has not been deployed

No deployments
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