Add codex-cli pack (OpenAI Codex CLI — experimental)#8
Merged
royosherove merged 12 commits intomainfrom Apr 16, 2026
Merged
Conversation
…law pack (pg_hba TCP auth, systemd EnvironmentFile, --no-onboard) codex-cli: - Remove bedrockify dependency — uses OpenAI API directly - Add --openai-api-key param with interactive prompt - Fix config.toml schema per official Codex CLI docs - Store API key with chmod 600 - Support codex login as alternative auth ironclaw: - Add TCP trust auth in pg_hba.conf (IronClaw uses DATABASE_URL with TCP) - Write systemd unit with EnvironmentFile and --no-onboard - Enable user lingering for boot-start README: - Add codex-cli entries (one-liner, pack table, standalone install) - Note about OpenAI API key requirement
…evice-auth refs H1: Remove /etc/profile.d API key block (root-only chmod 600 = broken for ec2-user) H2: Fix unreachable env check - pack_config_get now picks up existing OPENAI_API_KEY H3: Remove non-existent --device-auth flag, use 'codex login' or OPENAI_API_KEY env
…v0.121 install.sh: - Fix truncated API key prompt (syntax error — bash -n fails) - Remove stale approval_policy/sandbox_mode config.toml keys (these are CLI args in current codex, not config file keys) - Replace 'loki-agent' refs with 'lowkey' - Clean up interactive prompt with proper read -rp and non-interactive fallback - Sandbox mode via --sandbox CLI arg, not config.toml manifest.yaml: - Replace approval-policy/sandbox-mode params with single 'sandbox' param - Align with current codex CLI conventions (v0.121+) Tested: bash -n passes, registry/CFN/terraform all have codex-cli
a651145 to
2470ba5
Compare
Major rewrite based on Codex CLI's own review of PR #8. Configured as a BUILDER AGENT (not sandboxed) per Roy's direction. HIGH blockers fixed: - Add codex-cli to packs/registry.json (installer discovery source) - Remove fake --openai-api-key flag from README (was never wired through install.sh / bootstrap.sh). Document 'codex login' as the honest post- deploy flow, same pattern as kiro-cli. - Restore approval_policy + sandbox_mode as valid config.toml keys (previous 'CLI-only' claim was wrong — verified against codex 0.118). Builder agent config: - approval_policy = "never" (no command prompts) - sandbox_mode = "danger-full-access" (full filesystem/network) - model = configurable via --model (default: gpt-5.4) Config merge (idempotent, preserves user edits): - Wraps managed keys in sentinel comments (>>> managed <<<) - Placed at TOP of file so bare keys stay top-level (not scoped into user's [features]/[plugins]/[projects] tables) - Strips any user top-level duplicates of managed keys before re-writing MED blockers fixed: - Add packs/codex-cli/resources/shell-profile.sh with aliases + banner - Add packs/codex-cli/test.sh (28 contract checks, all pass) - Fix manifest params: all have name/description/default (scripts/verify-pack green) - README: fix self-contradiction (bedrockify claim removed), dedupe pack table - deploy/README.md: update PackName list to include all agents Verified: - scripts/verify-pack ./packs/codex-cli: 36 passed, 0 failed - bash tests/test-pack-contracts.sh: 176 passed, 0 failed - bash packs/codex-cli/test.sh: 28 passed, 0 failed - End-to-end smoke test: codex binary parses merged config.toml cleanly with realistic user-owned [features]/[plugins]/[projects] tables
Addresses round-2 review: packs/registry.json was drifting from registry.yaml
(missing default_model, requires_openai_key, description mismatch). Tests
only checked presence, not parity.
Resolution: YAML is now the source of truth. JSON is a generated artifact
consumed only by the client-side installer (install.sh uses jq, no YAML
parser available on the client machine). Both files still ship — but JSON
is never hand-edited.
Changes:
- scripts/sync-registry NEW. Regenerates registry.json from registry.yaml.
Supports --check for CI (non-zero on drift).
- tests/test-pack-contracts.sh Adds Contract 5b: sync-registry --check must pass.
This fails CI on any manual JSON edit that drifts.
- packs/registry.json Regenerated from registry.yaml. codex-cli entry
now includes default_model='gpt-5.4' and
requires_openai_key=true.
- docs/pack-checklist.md Documents YAML = truth, JSON = generated.
Explicit 'do NOT edit by hand' + sync command.
codex-cli follow-ups from review:
- install.sh: fixed misleading comment claiming tomllib/tomli_w merge path
(implementation is regex-based text rewrite, and that's fine).
- install.sh: expanded post-install NOTICE to clearly state auth is REQUIRED
on the remote machine and is deferred to a follow-up feature. Users SSM in
and run 'codex login' (or --with-api-key). Message makes it unambiguous.
- README: updated pack descriptions with 'SSM into the instance and run
codex login' so the post-deploy step is obvious before install.
Not addressed here (per Roy's direction):
- Headless/device-auth codex login flow — tracked as separate feature.
Verification:
- bash scripts/sync-registry --check OK
- scripts/verify-pack ./packs/codex-cli 36/0
- bash tests/test-pack-contracts.sh 177/0 (new Contract 5b included)
- bash packs/codex-cli/test.sh 28/0
- bash packs/codex-cli/install.sh --help exits 0
…solation)
Addresses remaining LOW findings from round-2 review:
- **CODEX_CLI_VERSION**: was pinned to literal string 'latest' with a
'pin version for reproducible installs' comment — contradictory.
Now defaults to 'latest' with env override: CODEX_CLI_VERSION=1.2.3
bash install.sh. Comment updated to match reality.
- **Arg parser**: previously silently swallowed unknown flags. Now:
--unknown -> error + exit 2
--region (no value) -> error: --region requires a value
positional foo -> error + exit 2
-- -> terminates option parsing
Fail-fast surface for typos and for pack composition.
- **TOML escaping**: --model value is now properly escaped per TOML
basic-string rules. Double-quotes, backslashes, control chars all
escaped. Newlines/CR are rejected (not legal in basic strings) with
a clear error. Defends against a user passing --model 'gpt"' etc.
- **Sentinel collision**: managed block detection now uses a tempered
regex (?:(?!START).)*? that refuses to cross a second START marker.
If a user has a stray 'managed by lowkey' comment in their config,
we only strip the FIRST well-formed START..END region, bounding
any accidental damage to real blocks.
Tested end-to-end:
- PACK_MODEL='evil"; rm -rf /' -> correctly escaped, no injection
- PACK_MODEL='gpt\\5' -> escaped to "gpt\\\\5" in TOML
- PACK_MODEL=$'gpt\n5' -> rejected with exit 2
- user config with stray sentinel in comment -> managed block added,
stray comment preserved
- managed block + stray START later -> first block replaced, stray preserved
- real codex binary parses merged config successfully
Verification:
- scripts/verify-pack ./packs/codex-cli 36/0
- tests/test-pack-contracts.sh 177/0
- packs/codex-cli/test.sh 28/0
- scripts/sync-registry --check OK
The sync-registry script (introduced in 32f7e3c) is now a critical piece of the installer — if the YAML→JSON transform is broken, the client-side installer gets wrong/stale data. This adds heavy test coverage plus a dedicated CI workflow to prevent silent breakage. tests/test-sync-registry.sh (17 test groups, 35 assertions): 1. repo HEAD JSON is in sync with YAML 2. regenerate is byte-for-byte identical to committed JSON (deterministic) 3. --check detects hand-edited JSON (description tampering) 4. --check detects missing field (e.g. default_model stripped) 5. --check handles missing registry.json file 6. generated JSON is valid JSON (jq parses it) 7. Unicode preserved literally (em-dash), no \uXXXX escapes 8. codex-cli entry has all 7 expected fields with correct values/types 9. YAML and JSON are deeply equal (Python deep-compare) 10. adding a new YAML pack is detected, then regenerate works 11. deps arrays (openclaw.deps=[bedrockify]) round-trip as JSON arrays 12. empty objects (codex-cli.ports={}) round-trip as {} 13. invalid YAML fails with non-zero exit (clean failure, not silent) 14. list-of-strings (nemoclaw.compatible_profiles) round-trip 15. top-level 'defaults' section present with all 7 keys 16. YAML pack set == JSON pack set (neither adds nor loses packs) 17. sync is idempotent (3 back-to-back runs produce identical SHA-256) PyYAML install fallback: pip --user → pip3 → apt python3-yaml → sudo pip. .github/workflows/registry-sync.yml (NEW): - Dedicated workflow triggered by any change to registry.yaml, registry.json, scripts/sync-registry, or tests/test-sync-registry.sh - Runs: bash scripts/sync-registry --check - Runs: bash tests/test-sync-registry.sh - Fires on push (main + feature/* + add-*) and all PRs - Runs BEFORE pack-tests.yml so a drift failure is called out crisply .github/workflows/pack-tests.yml: - 'Install test prereqs' step adds 'python3 -m pip install pyyaml' so CI always has a YAML parser available for any test.sh that needs it. The existing Contract 5b in tests/test-pack-contracts.sh (run as part of pack-tests matrix) keeps calling sync-registry --check, so drift is caught in at least three places now: 1. Local pre-commit: bash tests/test-sync-registry.sh 2. CI pack-tests job: Contract 5b 3. CI registry-sync: dedicated fast-fail workflow Verification: - bash tests/test-sync-registry.sh 35/0 - bash tests/test-pack-contracts.sh 177/0 - bash scripts/verify-pack ./packs/codex-cli 36/0 - bash packs/codex-cli/test.sh 28/0 - CI discovery finds tests/test-sync-registry.sh automatically
Two LOW findings from Codex CLI's round-3 review:
1. Missing-value arg handling leaked bash's ${2:?} diagnostic
(e.g. 'line 66: 2: --region requires a value', exit 1) instead of
the script's own error path. Replaced with explicit check + clean
error + exit 2, matching the strictness of unknown-option handling.
Also correctly rejects '--region --model foo' (next token starts
with '-', so it's not a value).
2. README quick-start said 'Codex CLI — requires API key' which was
inconsistent with the rest of the file (which correctly notes both
ChatGPT/browser login AND API key are supported). Reworded to
'builder agent, no Bedrock' and added a hint that auth is your
choice of login method.
Verified:
- bash packs/codex-cli/install.sh --region -> clean error, exit 2
- bash packs/codex-cli/install.sh --model -> clean error, exit 2
- bash packs/codex-cli/install.sh --region --model foo -> rejects, exit 2
- bash packs/codex-cli/install.sh --bogus -> rejects, exit 2 (unchanged)
- scripts/verify-pack ./packs/codex-cli 36/0
- tests/test-pack-contracts.sh 177/0
- tests/test-sync-registry.sh 35/0
- packs/codex-cli/test.sh 28/0
Found by fresh-EC2 smoke test on AL2023 arm64: Running 'bash packs/codex-cli/install.sh' on a stock AL2023 image with system-installed Node.js (dnf) failed with: npm error code EACCES npm error Error: EACCES: permission denied, mkdir '/usr/lib/node_modules/@openai' Root cause: npm's global prefix defaults to /usr/lib/node_modules (root-owned) when Node.js comes from dnf/yum. 'npm install -g' as ec2-user fails. Production bootstrap masks this because it sets up mise-managed Node.js first (user-owned prefix under ~/.local/share/mise/...). But the pack must also work when run standalone — which is a documented use case. Fix: three-tier install strategy 1. If mise is present and current npm prefix is not writable, activate mise (switches to user-owned prefix). 2. If npm prefix is user-writable, install directly. 3. Otherwise, fall back to sudo npm install -g with a warning pointing at mise.run as the cleaner long-term fix. Fails cleanly if sudo is unavailable in case 3 — no silent corruption. Tested locally (all suites green): - scripts/verify-pack ./packs/codex-cli 36/0 - tests/test-sync-registry.sh 35/0 - tests/test-pack-contracts.sh 177/0 - packs/codex-cli/test.sh 28/0 Will re-verify on fresh EC2 via SSM after push.
…i PR Captures the three tiers of manual testing run against this branch: 1. In-process merge-block stress tests (11 scenarios) — adversarial inputs, injection attempts, sentinel collisions, idempotency 2. Host-level CLI tests with isolated HOME (9 scenarios) — real codex binary, arg parser edge cases, user-config preservation 3. Fresh EC2 smoke test on AL2023 arm64 t4g.medium — production-like deploy via CFN + SSM The EC2 smoke test caught a real bug (npm EACCES on root-owned global prefix when mise falls back to system Node) that the automated suite missed. Fix landed in 209086c. This doc means the next pack change can re-run the same scenarios and not regress. Includes re-run instructions at three levels of infra cost (10s / 1min / 5min) and a commit-history summary of what the log covers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
New agent pack for OpenAI Codex CLI.
Key differences from other packs
--openai-api-key sk-...codex login(browser OAuth) if no key providedFiles
packs/codex-cli/manifest.yaml— pack metadatapacks/codex-cli/install.sh— installer (npm install, config.toml, env setup)packs/registry.yaml— registry entry withrequires_openai_key: truedeploy/cloudformation/template.yaml— added to AllowedValuesdeploy/terraform/variables.tf— added to validationREADME.md— one-liner, pack table, standalone install exampleConfig schema
Verified against official Codex CLI docs:
model,approval_policy,sandbox_mode— all documented keysmodel_providerneeded (uses default OpenAI endpoint)~/.codex/env.shwithchmod 600Code review
Two rounds of review completed (Opus 4.6 + follow-up). All CRITICAL/HIGH findings fixed:
--device-authflag/etc/profile.dAPI key block