Repository navigation
fix(codex): pre-trust a worker's working directory so it can boot unattended - #21
Conversation
Co-authored-by: wall-sync <wall-sync@users.noreply.github.com>
…ttended A Codex worker spawned without a human at the keyboard would sit at its very first turn and never start. Codex gates every working directory behind an interactive "do you trust this directory?" prompt, and the answer is persisted per config home as a `[projects."<dir>"] trust_level = "trusted"` table. Each worker gets its OWN isolated CODEX_HOME (so the user's ~/.codex is never mutated), and that home is generated fresh: it has never answered the prompt for anything. So every worker met the prompt on turn one, and an unattended one had nobody to press Yes. Pre-seeding that table is the only suppression that exists. No flag or environment variable skips the prompt — `--dangerously-bypass-approvals-and- sandbox` governs command approval, not directory trust — and a `-c projects…` override is not persisted, so it does not read as an answer either. So append the trust entry to the generated config.toml before the CLI starts, seeded from the user's config as before, keyed on: - the FINAL working directory. Git isolation has already resolved by the time spawn prep runs, so this is the worker's own worktree when one was created and the original repo when isolation fell back — always the directory the CLI will actually open in, and one entry is enough. - its canonical, realpath-resolved spelling. Codex resolves the directory before looking it up, so an entry keyed `/tmp/x` never matches its `/private/tmp/x` and the prompt comes back. The path goes through a TOML basic-string escaper rather than string interpolation: a directory name may legally contain a quote or a backslash on POSIX, and an unparseable config.toml would be a worse failure than the prompt. The short symlinked home that remote control binds its control socket through needs nothing extra — it aliases the same directory, so it sees the same file.
|
Note for review — one file in this diff is not part of the change.
Against the real target it is clean: Exactly one commit, only the intended files, no fork-only files. The PR body above is written to the upstream template and can be reused verbatim when the upstream PR is opened — the only thing it still needs is the terminal captures under |
|
✅ Evidence received. Before and after are both attached. Thanks — this is what makes a PR reviewable in one pass. |
What & why
A Codex agent spawned with nobody at the keyboard would sit at its very first turn and never
start. Codex gates every working directory behind an interactive "do you trust this directory?"
prompt, and the answer is persisted per config home as a
[projects."<dir>"] trust_level = "trusted"table. Each agent is given its own isolatedCODEX_HOMEso the user's~/.codexisnever mutated — and that home is generated fresh, so it has never answered the prompt for anything.
Every such agent therefore met the prompt on turn one and stalled there indefinitely.
Pre-seeding that table is the only suppression that exists. No flag or environment variable skips
the prompt (notably not
--dangerously-bypass-approvals-and-sandbox, which governs commandapproval, not directory trust), and a
-c projects…override is not persisted, so it does not readas an answer either. Verified against codex-cli 0.149.1.
So the fix appends the trust entry to the generated
config.tomlbefore the CLI starts, keyed onthe final working directory (git isolation has already resolved by the time spawn prep runs, so
this is the agent's own worktree when one was created and the original repo when isolation fell
back) in its canonical, realpath-resolved spelling (Codex resolves the directory before looking
it up, so an entry keyed
/tmp/xnever matches its/private/tmp/xand the prompt returns). Thepath goes through a TOML basic-string escaper rather than string interpolation: a directory name may
legally contain a quote or a backslash on POSIX, and an unparseable
config.tomlwould be a worsefailure than the prompt it was meant to remove.
Type of change
Evidence
The failure is a CLI process that hangs rather than anything visual, so the evidence is the
generated
config.tomland the boot behaviour, captured as text.Before
After
How I tested it
npm run test:focusedonmain→552 of 552 passing,
npm run typecheck→ 0 errors.npm run typecheck→ 0 errors.npm run test:focused→ 556 of 556 passing, 0 failing (the 4 new tests are the delta;no pre-existing failures on either ref).
npm run build→ succeeds.src/main/hive.tstomainwhilekeeping the new tests: all 4 go red (transcript under Before). Restored, green again.
round-trips through the TOML escaper, and the entry is keyed on the realpath, which is what
makes it match on macOS where
/tmpresolves to/private/tmp.Discord (optional)
Discord:
Checklist
npm run typecheckpasses.npm run test:focusedpasses.npm run buildsucceeds.commented-out code, or unrelated formatting churn in it.
DESIGN.md/tokens.ts— no ad-hoc colors,spacing, or fonts. (No UI in this change.)
ATTRIBUTION.md. (No art in this change.)