Repository navigation
Commit e6b8be0
authored
Codex, phases 6 and 7: install.sh and install.ps1 wire Codex when it is chosen (Codex closed on every system) (#56)
* codex phase 6: the night check says when Codex's hooks never run
_agents.py gains what install.sh needs to wire Codex: `ouvert` (can Codex be chosen on this
system), `codex-home` (the CODEX_HOME agents.json records, when it lists Codex and is trusted;
written as bytes, whatever the locale) and `pose-hooks`, which notes when the installer wired the
kit's hooks in Codex's hooks.json (~/.brain-in-a-box/codex-hooks-poses.json, 0600, written in one
step as the sign of life is). The line `choisir` prints is unchanged: install.ps1 reads it.
hooks_muets() reads that record against the sign of life of phase 5: Codex kept a session
(a rollout, compressed or not, regular files only) since the install, and none of the kit's hooks
has run since. The vault's report then says, in orange: "Les hooks Codex ne tournent pas : ouvre
Codex, tape /hooks et approuve-les." Only when agents.json lists Codex: Claude alone reads as
before, and Codex is still closed on every system.
* codex phase 6: install.sh wires Codex when it is chosen (Codex still closed)
When agents.json lists Codex, install.sh now:
- installs Codex if it is missing, from OpenAI's official installer as published with the
rust-v0.162.1 release, checked against a SHA-256 pinned in install.sh before it runs (it then
checks the binary's own digest), with the user's PATH and without VOYAGE_API_KEY;
- appends the kit's block to the global AGENTS.md Codex reads (AGENTS.override.md when that one has
text), drawn from CLAUDE.global.template.md, which stays as it is for install.ps1;
- merges the six hooks into Codex's hooks.json (--agent codex, a group of the kit's own at the end,
previous version kept in 0600; one that does not parse stops the install at preflight);
- approves them for the user and says so: new [hooks.state."..."] tables in config.toml, never a
table rewritten, refused over hooks in any other form, checked by `codex features list` before
and after (put back as it was otherwise);
- allows gbq query and gbq search without asking in a rules file of its own, with host_executable:
without it Codex matches any program named gbq, ./gbq included, which a session can write;
- places an AGENTS.md in the vault when it has none, installs the skills in ~/.agents/skills, says
`codex login`, and opens the preferred agent for the onboarding.
A new install at a terminal asks which AI only where Codex can be chosen: never while it is closed.
An agent no longer chosen keeps the kit's files, and the installer says how to remove them.
Claude alone is unchanged: compared with master (same stand-ins, nothing chosen, --agents claude,
a Codex of the user's own beside it), the output, the calls and install.log are the same, and
nothing is written in ~/.codex or ~/.agents. test-hooks.sh §15bis tests each function against
stand-ins; §16 runs install.sh end to end with Codex open in a copy of the kit (alone, both, both
then Claude then both, a config.toml it will not add to, at a terminal).
SECURITY.md says that the installer approves the kit's Codex hooks and allows gbq's two reads.
* CI: codex-mock runs install.sh with Codex chosen, and the real Codex runs the hooks it approved
On macOS and Linux, codex_mock.py runs install.sh --agents codex from a copy of the kit where Codex
is open, in a home of its own, with stand-ins for what would schedule jobs or reach gbrain: Codex
comes from its pinned installer, for real. The real Codex then runs, in the vault, the six hooks
from the hooks.json install.sh wrote, approved by the tables it wrote, no trust bypassed (control:
without them, none runs), and reads the kit's block in the global AGENTS.md, the vault's AGENTS.md
and the skills in ~/.agents/skills. `codex execpolicy check` shows gbq's rules allow the kit's gbq
only (control: without host_executable, ./gbq query runs without asking).
The job runs when install.sh, engine/codex, the global template, the skills installer or a skill
changes.
* codex-mock: the kit's copy has its folder, and the six hooks are read over three sessions at most
install_sh_wires_codex copied install.sh into a folder it had not made (FileNotFoundError on macOS
and Linux, the first run). Codex also runs one event's hooks together (three at Stop, two at
SessionStart), and a hook may miss another's line in the sign of life once (_agents.vu): the
scenario now takes what each session showed, over three sessions at most, before saying a hook did
not run. The control (without the tables install.sh wrote, none runs) stays a single session.
* terminal.py answers a question half a second after it appears, as a person would
Answered at once, the reply could reach the terminal before `read -rs` turned its echo off: the
echoed Enter added a blank line now and then (macOS CI, test-hooks.sh §16, "a re-run asked more or
said other things": 15a16 >). Reproduced here with /bin/bash 3.2 under load, the prompt read by
`read -rs -p " Voyage key: "`: 5 runs in 40 with the extra line before, 0 in 40 after.
* test-hooks.sh §16: a hooks.json of Codex's that does not parse stops install.sh at preflight
Each of step 6's protections taken out one at a time: removing the preflight check of Codex's
hooks.json left every test green (the merge step then only warned, and the install went on). The
whole install.sh, Codex chosen over a hooks.json that does not parse: it stops before anything, the
file left as it was, no install.log, no stand-in called; only the choice is recorded.
* Codex plan: Codex stays closed after steps 6 and 7, and step 6, done and its deviations
Two dated sections. "Changement au plan": steps 6 (install.sh) and 7 (install.ps1) build and test the
whole Codex path of the installers but do not open Codex; opening it will be a one-line PR per
system after a manual vrai-codex run. "Étape 6 — fait et écarts": what install.sh does when Codex is
chosen, the twelve deviations from the plan (pinned installer from the release, the global block
drawn from the template left as it is, the vault's AGENTS.md from engine/codex and none in the team
vault, host_executable for gbq's rules, the question only where Codex is open...), the proof that
Claude alone is unchanged, the tests, the mutations and the CI runs.
* codex phase 7: the launcher pauses Codex when %ProgramData%\OpenAI\Codex could be changed by another account
Step 3's review left a blocking point for Windows: a standard account can create
%ProgramData%\OpenAI\Codex when it is missing, and Codex loads it all the same (its own probe,
config/src/loader/windows.rs, only measures). check_system_settings() runs before any probe and
again just before the question. ProgramData comes from the Known Folder, as Codex finds it, never
from the variable (_managed_files() too). OpenAI and OpenAI\Codex, when there, and the files Codex
reads in them: no link or reparse point, the right kind, owned by SYSTEM, the Administrators or
TrustedInstaller, and no entry letting any other account change them, or (for Codex) the files it
gets. Stricter than Codex's probe, which looks at Users, Authenticated Users and Everyone only.
Otherwise Codex pauses (managed). Tests: the decision on access lists written by hand (every
system), the check over stood-in descriptions, its place in the call; on Windows, real folders
whose owner and access icacls sets, and a junction.
* codex phase 7: install.sh's Codex merges move to engine/codex/wire.py, which install.ps1 shares
The Python install.sh ran from a heredoc (check, merge, approve, restore, global) is now
engine/codex/wire.py: install.sh calls it as before, with the same output (test-hooks.sh 217/217
unchanged); install.ps1 will call it with --ps1 <python.exe>: its lines in French ASCII, and the
hooks in the form Codex runs on Windows, & '<python.exe>' '<hook>' --agent codex, in commandWindows
and command alike, single-quoted (PowerShell would expand $ and read backticks inside double
quotes; quotes, typographic ones too, written twice). Their approval is hashed on that command,
which Codex hashes on Windows (discovery.rs, command_windows.unwrap_or(command)); an entry of the
kit's is recognised by its \.claude\hooks\brain\ path, any case. engine/codex/ joins CODEOWNERS and
"Never merge": it writes the hooks' approval into the user's config.toml, and its rules file lets
gbq run outside Codex's sandbox. Tests: test_codex_wire.py; on Windows, the command run by pwsh and
Windows PowerShell with a path holding ', $HOME, a backtick, a typographic quote, é, & and ;.
* codex phase 7: install.ps1 wires Codex when it is chosen (Codex still closed)
As install.sh does since phase 6, in a section "Codex" before the vault's history: Codex from the
install.ps1 published with the rust-v0.162.1 release, checked against a pinned SHA-256 before it
runs in a PowerShell of its own (CODEX_RELEASE, no question, the chosen CODEX_HOME, none of its
own variables nor VOYAGE_API_KEY), an .exe only; the kit's block in the global AGENTS.md; the
hooks in hooks.json and their approval, said on screen (decision 2); gbq query and gbq search
allowed at the kit's gbq.cmd only; the vault's AGENTS.md when missing; the skills in
~\.agents\skills. A hooks.json it cannot read stops it at preflight, before anything. The question
at a console, never while Codex is closed; codex login, the preferred agent's onboarding and an
agent no longer chosen said at the end. Claude alone: nothing more runs nor is said.
Bibo announces one more section, "Je branche Codex" (steps.rs), so its count is out of 14.
.github/ci/install-ps1-codex.ps1 runs the block's functions against stand-ins under pwsh, on
macOS, Linux and Windows (test-hooks.sh section 15bis's counterpart).
* CI: install.ps1 with Codex chosen, and Claude alone the same as master's install.ps1
test.yml: install.ps1's Codex functions against stand-ins in the hooks, linux and windows jobs.
The windows job puts a Codex of the user's own in place before the first install, then runs
.github/ci/same-as-master.ps1 twice (without agents.json, then with Claude chosen): master's
install.ps1 then this one's over the install in place, the same lines, the same install.log
commands, the same files but the copies of the sources the branch touches, ~\.codex untouched, no
~\.agents. Then, from a copy of the kit where Codex is open: Codex beside Claude, a second run that
rewrites nothing, a hooks.json that does not parse, back to Claude alone.
codex-mock: on Windows, %ProgramData%\OpenAI\Codex as a folder made there is by default pauses
Codex, found through the Known Folder whatever %ProgramData% says (control: codex exec loads it);
the system settings the other scenarios write go in folders locked as an administrator does it.
Then install.ps1 -Agents codex: Codex from its pinned installer, for real, and the real Codex runs
the six hooks it wired, through PowerShell, approved, no trust bypassed (control: without the
tables, none runs); the global and vault AGENTS.md and the skills read; execpolicy: the kit's
gbq.cmd only. The job also runs when install.ps1 changes; 30 minutes.
* Codex plan: step 7, done and its deviations
A dated section, "Étape 7 — fait et écarts": install.ps1's Codex path, the shared wire.py, the single-quoted PowerShell form of the hooks, the pinned installer, gbq.cmd's rules, the %ProgramData% check (Known Folder, stricter than Codex's probe), Bibo's one more section, the question, the proof that Claude alone is unchanged on Windows, and the tests.
* CI: when Codex's installer leaves no codex.exe, its lines in install.log are shown
codex-mock (Windows) and the windows job print install.log from Codex's installer on: the first run of install.ps1 with Codex chosen ended with "Codex ne s'est pas installe", the reason only in a log the runner then dropped.
* install.ps1: Codex's installer runs with Windows' own tar first on its PATH
codex-mock (Windows) ran install.ps1 under Git Bash's PATH, Git's Unix tools first, as a user who
chose them when installing Git has it: Codex's official installer ran GNU tar, which reads
"C:\..." as a remote host ("tar (child): Cannot connect to C: resolve failed"), and left no
codex.exe. The installer now starts with Windows' system folder (bsdtar) ahead of the PATH, put
back afterwards; the stand-in installer of .github/ci/install-ps1-codex.ps1 checks it on Windows.
* test_headless_codex: on Windows, a folder its users may add to, as one made in ProgramData
The Windows job showed the test's premise wrong: a folder made in the runner's temporary folder
is the Administrators' and only theirs and SYSTEM's, so nothing pauses there. The test now gives
it what a folder made in C:\ProgramData inherits (Users may add files and folders, seen on the
runner by codex-mock), and the launcher pauses Codex, naming them.
* CI (windows): install.ps1's Codex functions run with the Python the installer set up
poste-neuf.ps1 leaves only the Store stub on the job's PATH, so the script's Python lookup found
python.exe in WindowsApps ("Python was not found") and stopped on an empty path. The step now puts
the Python of the installed hooks first, as the unit-test step uses it, and the script refuses the
Store stub by name instead of failing further down.
* install-ps1-codex.ps1: Windows' tar is checked past pwsh's own folder, ahead of a GNU tar's
The Windows job's first full run showed the check wrong, not install.ps1: the stand-in installer
runs under pwsh, which puts $PSHOME first on its PATH as it starts (powershell.exe does not, and
$PSHOME has no tar). The check now skips that entry and wants the system folder first, then a folder
the test puts ahead on the PATH as Git's Unix tools are on some PCs. Also checked: a codex.cmd (npm's)
on the PATH is not taken for Codex; nothing turned it red before.
* test_codex_wire: a hook of the kit's named only in commandWindows or command_windows is not added twice
Taking out the reading of those two keys left every test green: the kit writes the same command in
both, so only an entry the user changed shows it.
* same-as-master.ps1: the snapshot leaves install.log out after a run too
Run() kept the new part of install.log in $log, and Snap, called from it, read that as $Log
(PowerShell's names ignore case, and a function sees its caller's variables): install.log was
compared after the branch's run and not before, so the check failed on the log itself. Screen and
commands had already matched master's.
* Codex plan: step 7, what is left open, its protections taken out one at a time, local checks and CI
The ProgramData folder can still appear between the last check and codex exec starting; 39 of the
step's protections taken out one at a time (36 red on macOS, two given a test, one Windows-only);
the green run, and what the earlier runs found: one fact in the kit (GNU tar), three in the test
bench (the Store's python, pwsh's own folder first on its PATH, $log read as $Log).
* Benches open Codex in their copies whatever the gate says
test-hooks.sh, codex_mock.py, test_codex_hooks.py, install-ps1-codex.ps1 and the
windows job replaced the closed line, CODEX_OUVERT = frozenset(), exactly: the change
that opens one system (frozenset({"darwin", "linux"})) would have broken them all,
§16 stopping on "harness not isolated". They now replace the gate's line whatever it
says, then check it is open, so that only the tests that pin the closed gate change
with the opening.
* gbq: its reads start gbrain from a folder no session writes to
Codex runs gbq query and gbq search without asking, outside its sandbox, from a
session's folder, and gbq started gbrain there: Bun reads a bunfig.toml (whose preload
runs before gbrain), a .env and a tsconfig.json in the folder it starts in, and the
sandbox lets a session write them. engine/bin/gbq now starts its reads (query, search,
ask, graph-query) from /, gbq.py (Windows) from its own folder; a write keeps the
caller's folder (gbq import ./notes).
Tests: test-hooks.sh §10, the folder each command starts gbrain from (red before);
the linux and windows jobs, the real Bun and gbrain: a bunfig.toml whose preload runs
when gbrain starts from that folder (the control), and never through gbq query or
gbq search, which still find the vault's note.
* install.ps1: no gbq rule in Codex on Windows, where gbq.cmd goes through cmd.exe
The rule let Codex run gbq query and gbq search without asking, outside its sandbox,
at ~\.local\bin\gbq.cmd. Codex 0.162.1 reads 'x&calc' as one word, the rule allowed
it, and PowerShell hands it to cmd.exe, which reads the line again: the "&" starts a
second command, unasked and unsandboxed (BatBadBut). Until gbq has an entry point that
is not a batch file, install.ps1 puts no rule, says that Codex asks before every gbq,
and the rules file is install.sh's alone (its comment says why, and that gbq's reads
start from /).
Tests: install-ps1-codex.ps1 (no rules folder, said; red before); the windows job;
codex-mock on Windows: no rule in Codex's home, and two controls on the real Codex and
the runner: install.sh's rule at this gbq.cmd would allow gbq query 'x&cd.>w', and run
through PowerShell, the "&" starts the second command.
* wire.py: a hook turned off in /hooks stays off once moved; Windows' hooks follow a new Python
Codex knows a hook by its place in hooks.json. Turned off in /hooks, then moved by a
hook of the user's put before it, the kit's hook got a new table at its new place on
the next install (the update path): Codex ran it again, and nothing was said. approve()
now looks at the event's other tables: one that turns this hook off (its hash and
something else, or "enabled = false" without a hash) keeps it as the user set it, and
it is said.
On Windows the hooks name python.exe. Another Python since the last install, merge()
recognised the kit's entries by their path and left the old python.exe, and approve()
kept the old tables as the user's: Codex would run a Python since removed, and the
night's report said to approve hooks that could not run. merge() now moves an entry
exactly in the kit's form to this install's Python (as settings.json's for Claude),
after a backup, and says so; an entry the user changed stays. approve() writes the
command each table approves as a comment under it, and replaces a table of its own
whose hash is that of the kit's command it names; any other table stays as it is.
Tests: test_codex_wire.py (NewPython, Moved, both forms), test-hooks.sh §15bis,
install-ps1-codex.ps1; each red before.
* Claude alone: the end of the install reads Codex's hooks.json only once the kit wired Codex
To say "Codex is not chosen any more", both installers read ~/.codex/hooks.json (or
$CODEX_HOME's) for anyone who had not chosen Codex, which master never does. On
Windows, a CODEX_HOME on a drive that is not there made Join-Path throw and
install.ps1 exit 1 at its very end, for every Claude alone install (Bibo then shows
the brain's step as failed); and a hooks.json naming one of the kit's hooks by hand
got the message without Codex ever chosen. The message now needs the kit's own record
that it wired Codex (codex-hooks-poses.json); install.ps1 builds the path with
[IO.Path]::Combine and never lets that read stop it.
Tests: the windows job runs same-as-master.ps1 with CODEX_HOME on a drive that is not
there, then with a Codex whose hooks.json names the kit's hook (red before); test-hooks.sh
§16, Claude alone beside such a Codex: the default's output (red before).
* test-hooks.sh §16: Claude alone, install.sh compared with master's
Nothing compared install.sh with master's on macOS and Linux: §16 compared Claude
alone with this branch's own default, so a line or a file added to every install left
it green (217/217 with both, checked by mutation). §16 now runs master's install.sh
(origin/master, which the hooks and linux jobs fetch) and this one's, each in a new
home beside a Codex of the user's own, then both again over that install, without a
choice and with --agents claude: the same output, stub calls and install.log commands,
the same files but the kit's copies of the sources this change touches and
installed.json, this one's re-run leaving the install as it found it, ~/.codex
untouched. Without origin/master: a failure in CI, said and skipped elsewhere.
Mutations, each caught: a line on screen, a file written, an extra logged command,
the hooks.json read of the previous commit undone.
* Bibo: install.ps1's Codex section said without a count, Claude alone still "sur 13"
Its section in SECTIONS made every Bibo user (Claude alone: Bibo chooses no agent
before phase 10b) see "sur 14" and the number 9 skipped, where master says "sur 13".
Codex's section is now in CHOSEN_SECTIONS: said as "▸ Je branche Codex…", without a
count, and the other thirteen counted as on master. app/dev/mock.html is master's
again; the app-windows-install step looks for "sur 13" again.
* SECURITY.md: gbq's reads from /, no gbq rule on Windows, a hook turned off stays off
What the previous commits change for Codex users: the approval keeps a hook turned off
in /hooks, and follows a new Python on Windows; gbq's two reads run outside Codex's
sandbox on macOS and Linux only, started from /, and not with the home folder as
Codex's workspace (a session could then rewrite gbq itself); on Windows Codex asks
before every gbq.
* The comparisons with master: mktemp's names, and ~\.brain-search's copies
Two defects of the benches, found by the first run, nothing to fix in the kit:
test-hooks.sh §16 compared crontab's stand-in calls with the file mktemp names for it
(Linux), a new name each run; same-as-master.ps1 counted the copies the change touches
next to the hooks only, and gbq.py, which install.ps1 copies into ~\.brain-search, is
one now. Both runs said and ran the same; the files differed by gbq.py alone.
* CI (linux): the bunfig.toml control starts gbrain with Bun on the PATH, as gbq does
gbrain is a `#!/usr/bin/env bun` script, and the job's PATH has no ~/.bun/bin: the
control's gbrain never started, so its preload never ran. Its output is now shown
when the control fails.
* Codex plan: steps 6 and 7, review and corrections
Eight findings, each verified and fixed with a test red before: gbq's reads and the
session's folder, no gbq rule on Windows, a hook turned off staying off once moved,
Claude alone compared with master's install.sh, ~/.codex read for Claude alone, a new
Python on Windows, Bibo's count, and what the opening change will touch. The run cited
for step 6 corrected; local checks and CI.
---------
Co-authored-by: Chad El Kurdi <162061136+El-Kurdi-Chad@users.noreply.github.com>1 parent 4038759 commit e6b8be0
27 files changed
Lines changed: 3433 additions & 57 deletions
File tree
- .github
- ci
- workflows
- app/src-tauri/src
- docs
- proposals
- engine
- bin
- codex
- hooks
- search
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| 16 | + | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
| |||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
86 | 86 | | |
87 | 87 | | |
88 | 88 | | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
89 | 92 | | |
90 | 93 | | |
91 | 94 | | |
| |||
0 commit comments