imbue-mngr-codex 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. imbue_mngr_codex-0.1.0/.gitignore +359 -0
  2. imbue_mngr_codex-0.1.0/CHANGELOG.md +16 -0
  3. imbue_mngr_codex-0.1.0/PKG-INFO +177 -0
  4. imbue_mngr_codex-0.1.0/README.md +169 -0
  5. imbue_mngr_codex-0.1.0/UNABRIDGED_CHANGELOG.md +45 -0
  6. imbue_mngr_codex-0.1.0/changelog/.gitkeep +0 -0
  7. imbue_mngr_codex-0.1.0/conftest.py +21 -0
  8. imbue_mngr_codex-0.1.0/imbue/mngr_codex/__init__.py +0 -0
  9. imbue_mngr_codex-0.1.0/imbue/mngr_codex/codex_config.py +531 -0
  10. imbue_mngr_codex-0.1.0/imbue/mngr_codex/codex_config_test.py +331 -0
  11. imbue_mngr_codex-0.1.0/imbue/mngr_codex/conftest.py +35 -0
  12. imbue_mngr_codex-0.1.0/imbue/mngr_codex/plugin.py +791 -0
  13. imbue_mngr_codex-0.1.0/imbue/mngr_codex/plugin_test.py +596 -0
  14. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/__init__.py +0 -0
  15. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/clear_active_marker.sh +70 -0
  16. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/clear_active_marker_test.py +259 -0
  17. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/codex_background_tasks.sh +104 -0
  18. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/codex_marker_state.sh +103 -0
  19. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/common_transcript.sh +295 -0
  20. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/common_transcript_test.py +324 -0
  21. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/set_active_marker.sh +96 -0
  22. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/set_active_marker_test.py +177 -0
  23. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/stream_transcript.sh +190 -0
  24. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/stream_transcript_test.py +204 -0
  25. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/subagent_started.sh +43 -0
  26. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/subagent_started_test.py +94 -0
  27. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/subagent_stopped.sh +40 -0
  28. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/subagent_stopped_test.py +117 -0
  29. imbue_mngr_codex-0.1.0/imbue/mngr_codex/resources/testing.py +59 -0
  30. imbue_mngr_codex-0.1.0/imbue/mngr_codex/test_codex_agent_e2e.py +132 -0
  31. imbue_mngr_codex-0.1.0/imbue/mngr_codex/test_ratchets.py +278 -0
  32. imbue_mngr_codex-0.1.0/pyproject.toml +69 -0
@@ -0,0 +1,359 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ **/__pycache__/
3
+ **/*.py[codz]
4
+ **/*$py.class
5
+
6
+ # macOS Finder metadata
7
+ **/.DS_Store
8
+
9
+ # C extensions
10
+ **/*.so
11
+
12
+ # Distribution / packaging
13
+ **/.Python
14
+ **/build/
15
+ **/develop-eggs/
16
+ **/dist/
17
+ **/downloads/
18
+ **/eggs/
19
+ **/.eggs/
20
+ **/lib/
21
+ **/lib64/
22
+ **/parts/
23
+ **/sdist/
24
+ **/var/
25
+ **/wheels/
26
+ **/share/python-wheels/
27
+ **/*.egg-info/
28
+ **/.installed.cfg
29
+ **/*.egg
30
+ **/MANIFEST
31
+
32
+ # PyInstaller
33
+ # Usually these files are written by a python script from a template
34
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
35
+ **/*.manifest
36
+ **/*.spec
37
+
38
+ # Installer logs
39
+ **/pip-log.txt
40
+ **/pip-delete-this-directory.txt
41
+
42
+ # Unit test / coverage reports
43
+ **/htmlcov/
44
+ **/.tox/
45
+ **/.nox/
46
+ **/.coverage
47
+ **/.coverage.*
48
+ **/.cache
49
+ **/nosetests.xml
50
+ **/coverage.xml
51
+ **/*.cover
52
+ **/*.py.cover
53
+ **/.hypothesis/
54
+ **/.pytest_cache/
55
+ **/cover/
56
+
57
+ # Translations
58
+ **/*.mo
59
+ **/*.pot
60
+
61
+ # Django stuff:
62
+ **/*.log
63
+ **/local_settings.py
64
+ **/db.sqlite3
65
+ **/db.sqlite3-journal
66
+
67
+ # Flask stuff:
68
+ **/instance/
69
+ **/.webassets-cache
70
+
71
+ # Scrapy stuff:
72
+ **/.scrapy
73
+
74
+ # Sphinx documentation
75
+ **/docs/_build/
76
+
77
+ # PyBuilder
78
+ **/.pybuilder/
79
+ **/target/
80
+
81
+ # Jupyter Notebook
82
+ **/.ipynb_checkpoints
83
+
84
+ # IPython
85
+ **/profile_default/
86
+ **/ipython_config.py
87
+
88
+ # pyenv
89
+ # For a library or package, you might want to ignore these files since the code is
90
+ # intended to run in multiple environments; otherwise, check them in:
91
+ # .python-version
92
+
93
+ # pipenv
94
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
95
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
96
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
97
+ # install all needed dependencies.
98
+ #Pipfile.lock
99
+
100
+ # UV
101
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
102
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
103
+ # commonly ignored for libraries.
104
+ #uv.lock
105
+
106
+ # poetry
107
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
108
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
109
+ # commonly ignored for libraries.
110
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
111
+ #poetry.lock
112
+ #poetry.toml
113
+
114
+ # pdm
115
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
116
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
117
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
118
+ #pdm.lock
119
+ #pdm.toml
120
+ **/.pdm-python
121
+ **/.pdm-build/
122
+
123
+ # pixi
124
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
125
+ #pixi.lock
126
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
127
+ # in the .venv directory. It is recommended not to include this directory in version control.
128
+ **/.pixi
129
+
130
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
131
+ **/__pypackages__/
132
+
133
+ # Celery stuff
134
+ **/celerybeat-schedule
135
+ **/celerybeat.pid
136
+
137
+ # SageMath parsed files
138
+ **/*.sage.py
139
+
140
+ # Environments
141
+ **/.env
142
+ **/.envrc
143
+ **/.venv
144
+ **/.venv-*
145
+ **/env/
146
+ **/venv/
147
+ **/ENV/
148
+ **/env.bak/
149
+ **/venv.bak/
150
+
151
+ # Spyder project settings
152
+ **/.spyderproject
153
+ **/.spyproject
154
+
155
+ # Rope project settings
156
+ **/.ropeproject
157
+
158
+ # mkdocs documentation
159
+ **/site
160
+
161
+ # mypy
162
+ **/.mypy_cache/
163
+ **/.dmypy.json
164
+ **/dmypy.json
165
+
166
+ # Pyre type checker
167
+ **/.pyre/
168
+
169
+ # pytype static type analyzer
170
+ **/.pytype/
171
+
172
+ # Cython debug symbols
173
+ **/cython_debug/
174
+
175
+ # PyCharm
176
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
177
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
178
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
179
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
180
+ **/.idea/
181
+
182
+ # Abstra
183
+ # Abstra is an AI-powered process automation framework.
184
+ # Ignore directories containing user credentials, local state, and settings.
185
+ # Learn more at https://abstra.io/docs
186
+ **/.abstra/
187
+
188
+ # Visual Studio Code
189
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
190
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
191
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
192
+ # you could uncomment the following to ignore the entire vscode folder
193
+ # .vscode/
194
+
195
+ # Ruff stuff:
196
+ **/.ruff_cache/
197
+
198
+ # PyPI configuration file
199
+ **/.pypirc
200
+
201
+ # Cursor
202
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
203
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
204
+ # refer to https://docs.cursor.com/context/ignore-files
205
+ **/.cursorignore
206
+ **/.cursorindexingignore
207
+
208
+ # Marimo
209
+ **/marimo/_static/
210
+ **/marimo/_lsp/
211
+ **/__marimo__/
212
+
213
+ # task folders for local custom claude workflow (at any depth, incl. the
214
+ # root-level `dev` project's `dev/_tasks/`, which `*/*/_tasks/` missed)
215
+ **/_tasks/
216
+ **/.sesskey
217
+
218
+ # Node.js
219
+ **/node_modules/
220
+
221
+ # Frontend build artifacts
222
+ **/frontend-dist/
223
+
224
+ # Claude Code local settings (session-specific permissions)
225
+ **/.claude/settings.local.json
226
+
227
+ # Local Claude settings backup files
228
+ **/.claude/*.bak
229
+
230
+ # Claude worktress
231
+ **/.claude/worktrees
232
+
233
+ # Agent definitions deployed by mngr_subagent_proxy at session start
234
+ **/.claude/agents/
235
+
236
+ # Local mngr settings (not committed)
237
+ **/.mngr/settings.local.toml
238
+
239
+ # Local working / scratch markdown (not committed)
240
+ **/*.local.md
241
+
242
+ # Local working / scratch shell scripts (not committed)
243
+ # (covers user notification scripts like scripts/notify_user.local.sh, too)
244
+ **/*.local.sh
245
+
246
+ # Local-only throwaway scripts (e.g. one-off test harnesses).
247
+ **/scripts/*.local.sh
248
+
249
+ # Test output files (slow tests, coverage summaries)
250
+ **/.test_output/
251
+
252
+ # TMR output directories (reports + test outputs)
253
+ **/tmr_*/
254
+ **/tmr-report/
255
+
256
+ # Active session marker file (used to detect interrupted sessions)
257
+ **/.claude/active
258
+
259
+ # we stick the image build artifacts here
260
+ **/.mngr/dev/build/
261
+ **/.mngr/dev/secrets/
262
+
263
+ # Offload caches and local files
264
+ **/.offload/**
265
+ **/test-results
266
+
267
+ # Minds deploy-time build artifacts.
268
+ # Ignore contents so we can un-ignore the committed `template/` subtree: git
269
+ # won't descend into a fully-ignored directory, so negations must live below
270
+ # the contents pattern rather than below the directory pattern.
271
+ **/.minds/*
272
+ # The template directory is committed: it defines the expected keys for each
273
+ # <service>.sh file, with empty values. `scripts/push_modal_secrets.py` uses
274
+ # it to check that per-env .sh files declare every template key.
275
+ !/.minds/template/
276
+ !/.minds/template/**
277
+ # Vault ACL policies for the minds tiers. The HCL is non-sensitive and is
278
+ # the source of truth for the policies pushed to Vault via
279
+ # `vault policy write <name> .minds/policies/<name>.hcl`.
280
+ !/.minds/policies/
281
+ !/.minds/policies/**
282
+
283
+ # Autofix session artifacts
284
+ **/.autofix/
285
+ **/.reviewer/logs/
286
+ **/.reviewer/outputs/
287
+ **/.reviewer/settings.local.json
288
+ **/.reviewer/.stop_hook_consecutive_blocks
289
+ **/.reviewer/conversation-issues.jsonl
290
+ **/.reviews/
291
+
292
+ # Stuck agent tracking (stop hook escape valve)
293
+ **/.claude/blocked_stop_commits
294
+
295
+ # Scheduled tasks lock file
296
+ **/.claude/scheduled_tasks.lock
297
+
298
+ # Demo recordings (asciinema .cast, .txt, and scripts)
299
+ **/.demos/
300
+
301
+ # for git worktrees from other repos
302
+ **/.external_worktrees/
303
+
304
+ # ignore coverage files generated within subprojects
305
+ **/cov.xml
306
+
307
+ # ignore demos
308
+ **/recordings
309
+ apps/minds_workspace_server/package-lock.json
310
+ **/*.local.md
311
+
312
+ # Generated by the _generate-dockerignore justfile recipe before each
313
+ # test-offload* run. The recipe strips this self-reference so offload's
314
+ # copy_untracked_files ships the generated file into the build context.
315
+ /.dockerignore
316
+
317
+ # Transient offload image-cache marker written by test-offload runs; not
318
+ # checked in (unlike the committed .offload-*-cache-key files which pin CI
319
+ # image versions).
320
+ /.offload-image-cache
321
+
322
+ # Generated by _generate-release-dockerfile from Dockerfile + .release.extras.
323
+ /libs/mngr/imbue/mngr/resources/Dockerfile.release
324
+ **/.reviewer/autofix/issues/
325
+ .reviewer/logs/
326
+
327
+ # Tailwind Play CDN JS for the minds desktop client. Fetched once via
328
+ # `just minds-tailwind` (plain curl, no build) and shipped with the
329
+ # distributable. Not checked in because it's a ~300KB blob we can always
330
+ # re-fetch.
331
+ /apps/minds/imbue/minds/desktop_client/static/tailwind.js
332
+
333
+ # macOS Finder metadata
334
+ **/.DS_Store
335
+ **/.env.swp
336
+ # Vim swap files for any file (`.foo.swp`, `.foo.swo`, etc.) -- generated
337
+ # while a file is open in vim. Never checked in.
338
+ **/.*.sw[a-p]
339
+
340
+ # `minds env deploy` writes a recover-target file at the monorepo root
341
+ # on failed deploys; `minds env recover` deletes it after rolling back.
342
+ # Never checked in. Per-env naming
343
+ # (``.minds-deploy-recover-target-<env-name>.json``) means each in-flight
344
+ # deploy has its own file, so concurrent deploys against different envs
345
+ # don't trip over each other.
346
+ **/.minds-deploy-*.json
347
+ # Per-env deploy lock files (kernel-level ``flock`` targets). Created
348
+ # by ``hold_deploy_lock`` in ``apps/minds/imbue/minds/envs/recover.py``
349
+ # and held for the entire duration of ``minds env deploy`` /
350
+ # ``minds env recover`` so two concurrent invocations against the same
351
+ # env serialize. The file itself is empty and cheap to leave around.
352
+ **/.minds-deploy-lock-*.lock
353
+ **/.antigravitycli/
354
+
355
+ # Playwright MCP scratch artifacts (mock screenshots, page snapshots)
356
+ **/.playwright-mcp/
357
+
358
+ # tmr (task-runner) orchestration scratch report
359
+ **/tmr-report/
@@ -0,0 +1,16 @@
1
+ # Changelog - mngr_codex
2
+
3
+ A concise, human-friendly summary of changes for the `mngr_codex` library. Entries are categorized using the [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) categories: Added, Changed, Deprecated, Removed, Fixed, Security.
4
+
5
+ For the full, unedited changelog entries, see [UNABRIDGED_CHANGELOG.md](UNABRIDGED_CHANGELOG.md).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [v0.1.0] - 2026-06-13
10
+
11
+ ### Added
12
+
13
+ - Added: real `codex` agent-type support as its own plugin (`imbue-mngr-codex`), wiring OpenAI's Codex CLI into mngr and replacing the previous in-core `BaseAgent` stub. Each agent runs under its own per-agent `CODEX_HOME` for isolated config, sessions, and transcripts, while sharing authentication through a write-through `auth.json` symlink so logging in once authenticates every agent. Codex agents report RUNNING while working and WAITING when idle via four hooks (`UserPromptSubmit`/`Stop`/`SubagentStart`/`SubagentStop`); because codex subagents run asynchronously, the `active` marker is recomputed under a lock from a root-turn flag plus one file per in-flight subagent so it stays RUNNING until the root turn AND every subagent are done. Includes conversation resume across stop/start (root `session_id` captured to a tracking file; `mngr start` shell-evaluates `codex resume <id>`), common transcripts readable by `mngr transcript`, and seeded trust/onboarding for a silent first launch.
14
+ - Added: `send_message` blocks until submission registers — the `UserPromptSubmit` hook signals a `mngr-submit-<session>` tmux wait-for channel after it sets the active marker, so `mngr message` returns only once the agent reads RUNNING (closes a race where a follow-up lifecycle check could see the pre-turn idle state).
15
+ - Added: Update handling — codex's blocking startup "Update available!" prompt is disabled, and mngr surfaces updates itself at provision by comparing `codex --version` to `~/.codex/version.json`. A single `update_policy` setting governs action (default `ASK`): `AUTO` runs `codex update` silently, `ASK` prompts on an attended local run (interactive tty + local host) and otherwise logs a non-blocking notice, and `NEVER` only logs the notice.
16
+ - Added: Conformance test asserting codex's emitted common-transcript records validate against the canonical envelope schema (`imbue.mngr.agents.common_transcript_records`); release test now runs on the shared agent release-lifecycle harness (`imbue.mngr.agents.agent_release_testing`) against the real codex binary, including stop/start resume.
@@ -0,0 +1,177 @@
1
+ Metadata-Version: 2.4
2
+ Name: imbue-mngr-codex
3
+ Version: 0.1.0
4
+ Summary: Codex agent type plugin for mngr
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: imbue-mngr==0.2.13
7
+ Description-Content-Type: text/markdown
8
+
9
+ # imbue-mngr-codex
10
+
11
+ The `codex` agent-type plugin for [`mngr`](https://pypi.org/project/imbue-mngr/): real
12
+ support for the OpenAI Codex CLI (the Rust `codex` binary) as a first-class mngr agent,
13
+ on par with the `claude` and `antigravity` agent types.
14
+
15
+ `mngr create my-task codex` launches an interactive Codex TUI agent that mngr can monitor
16
+ (RUNNING/WAITING), message, transcript, stop, resume, and isolate per agent.
17
+
18
+ ## How it works
19
+
20
+ See `specs/agent-plugin-parity/codex-investigation.md` in the monorepo for the full,
21
+ source-verified investigation behind each decision.
22
+
23
+ - **Per-agent isolation via `CODEX_HOME`.** Codex resolves its whole
24
+ config/auth/session/hook tree from `CODEX_HOME` (default `~/.codex`). Each agent gets its
25
+ own `CODEX_HOME` under the agent state dir, injected only on the codex process
26
+ (`env CODEX_HOME=...`), leaving the user's real `$HOME` untouched. codex accepts the
27
+ dotted `~/.mngr/...` cwd, so there is no workspace symlink either.
28
+ - **Shared auth.** The per-agent `auth.json` is a symlink to the user's shared
29
+ `~/.codex/auth.json`. Codex writes that file in place and reloads-before-refreshing, so
30
+ one login authenticates every agent and token refreshes propagate. `config.toml` pins
31
+ `cli_auth_credentials_store = "file"` so codex never falls back to a keyring entry keyed
32
+ by the per-agent `CODEX_HOME` path (which would defeat sharing).
33
+ - **Lifecycle marker (RUNNING/WAITING), subagent-aware.** Codex subagents (the multi-agent
34
+ `spawn_agent` feature) run *asynchronously* -- the root agent's `Stop` hook fires while
35
+ subagents are still running, with no `fullyIdle` signal. So mngr does not just clear the
36
+ marker on `Stop`; it recomputes an `active` marker that is present while either the root
37
+ turn is running (`codex_root_active`, set on `UserPromptSubmit`, cleared on the root
38
+ `Stop`) or any subagent is in flight (one file per `agent_id` under `codex_subagents/`,
39
+ maintained by the `SubagentStart`/`SubagentStop` hooks). The recompute runs under a portable
40
+ `mkdir` lock so a concurrent root `Stop` and final `SubagentStop` can't strand it. A
41
+ recorded root `session_id` guards against a nested `codex` process sharing the same
42
+ `CODEX_HOME`. (Backgrounded OS processes the agent launches are not tracked -- codex emits
43
+ no hook for them.)
44
+ - **Conversation resume.** `mngr stop` then `mngr start` resumes the prior conversation: the
45
+ hook records the root `session_id`, and the launch command shell-evaluates
46
+ `codex resume <id>` (codex's session JSONL survives the hard kill `mngr stop` performs).
47
+ - **Transcripts.** The native rollout JSONL is streamed verbatim to the raw transcript and
48
+ converted into mngr's agent-agnostic common transcript that `mngr transcript` reads.
49
+ - **Trust & hook bypass (consent-gated).** mngr seeds the work dir as a trusted project to
50
+ skip codex's folder-trust dialog, and passes `--dangerously-bypass-hook-trust` so its own
51
+ lifecycle hooks run. Because trusting the workspace also lets codex load repo-local
52
+ `.codex/hooks.json`, that bypass is consent-gated together with workspace trust: mngr
53
+ prompts before trusting (or use `mngr create --yes` / `auto_dismiss_dialogs = true`).
54
+
55
+ ## Configuration
56
+
57
+ Set fields under an `[agent_types.codex]` table in your mngr config, or pass overrides.
58
+
59
+ - `model` — model slug to pin (e.g. `"gpt-5.5"`). Default: unset (codex's own default).
60
+ - `model_reasoning_effort` — `none|minimal|low|medium|high|xhigh`. Default: unset.
61
+ - `sandbox_mode` — `read-only|workspace-write|danger-full-access`. Default: `workspace-write`.
62
+ - `auto_allow_permissions` — when `true`, sets `approval_policy = "never"` so codex never
63
+ prompts for tool approval (the sandbox still applies). Default: `false`.
64
+ - `config_overrides` — free-form key/values merged last into the per-agent `config.toml`.
65
+ - `auto_dismiss_dialogs` — when `true`, trust the repo and allow the hook bypass without
66
+ prompting. Default: `false`.
67
+ - `update_policy` — how mngr handles an outdated codex CLI at provision (see "Updates" below):
68
+ `AUTO` (run `codex update`, no prompt), `ASK` (prompt on an attended local run, else just
69
+ notify), or `NEVER` (only notify). Default: `ASK`.
70
+ - `emit_common_transcript` — emit the common-schema transcript. Default: `true`.
71
+
72
+ ### Updates
73
+
74
+ mngr pins `check_for_update_on_startup = false` in the per-agent `config.toml`, because codex's
75
+ own "Update available!" prompt is **blocking** and would intercept the first message mngr sends
76
+ (an Enter could even select "Update now"). mngr surfaces updates itself instead: at provision it
77
+ compares `codex --version` against the `latest_version` codex last recorded in its own
78
+ `~/.codex/version.json` (no network call — codex refreshes that file on its own throttled
79
+ schedule during your normal codex use). The check always runs and is best-effort: any probe or
80
+ parse failure is swallowed (debug-logged) and never blocks agent creation. When codex is outdated,
81
+ the action is governed by `update_policy`: `AUTO` runs `codex update`; `ASK` (the default) prompts
82
+ to update now only on an *attended* run — a local host driven from an interactive terminal, and
83
+ not `--yes` — otherwise it logs a non-blocking notice (so an unattended remote/deploy agent
84
+ defaults to neither prompting nor upgrading the remote's global install); `NEVER` only logs the
85
+ notice. `codex update` self-detects the install method (it runs `brew upgrade --cask codex` for a
86
+ brew install, `npm i -g` for npm, the curl installer for standalone), so mngr needs no per-method
87
+ logic. Updating is optional — an outdated codex still runs — so a declined prompt, a `NEVER`
88
+ policy, or a non-interactive run never blocks agent creation, and `--yes` does **not** trigger a
89
+ global upgrade (only the explicit `AUTO` policy does).
90
+
91
+ ### Model note
92
+
93
+ Codex picks the account's default model, and a **ChatGPT-account login rejects some
94
+ `*-codex` model slugs** (e.g. `gpt-5.2-codex`) with a 400 "model is not supported when using
95
+ Codex with a ChatGPT account". Two distinct things cause this:
96
+
97
+ - **Deprecation:** `gpt-5.2` / `gpt-5.2-codex` / `gpt-5.3-codex` have been sunset for ChatGPT
98
+ subscriptions (OpenAI's announcement points those users to the API). These fail on a ChatGPT
99
+ plan in *every* mode, including the TUI.
100
+ - **Run-mode entitlement:** the backend gates some `*-codex` models by the `originator` HTTP
101
+ header (i.e. the client identity). The interactive TUI presents as `codex-tui` and is
102
+ allowed; `codex exec` presents as `codex_exec` and is denied. (See the app-server note below
103
+ for why this matters and why we do *not* spoof the TUI identity.)
104
+
105
+ If your agent errors on the first message with the "not supported" 400, set `model` to a model
106
+ your account supports (e.g. `"gpt-5.5"`), or authenticate with an API key (which carries the
107
+ full model entitlement).
108
+
109
+ ## Not yet implemented
110
+
111
+ Relative to `mngr_claude`, these are not yet ported (tracked for follow-up): session
112
+ preservation on destroy, deploy/scheduling contributions, field generators (`waiting_reason`),
113
+ the streaming snapshot, and installation/version management.
114
+
115
+ ## Future direction: an app-server-backed agent variant
116
+
117
+ This agent drives the codex **TUI** by `tmux send-keys` (paste + Enter), with banner-poll
118
+ readiness. That works, but it's fragile (screen-scraping) and codex's `SessionStart` fires
119
+ lazily, so there's no clean pre-input readiness signal. Codex offers a much cleaner surface to
120
+ drive programmatically -- the **app-server** -- and a second agent type built on it is a planned
121
+ follow-up (mirroring `mngr_claude`'s `claude` + `headless_claude` split).
122
+
123
+ We built the TUI agent **first**, though, for a concrete reason: like `claude -p`, the app-server
124
+ does not have full feature parity with the interactive TUI on a ChatGPT-subscription login. The
125
+ backend gates some `*-codex` models on the **client identity** (the `originator`, derived from the
126
+ app-server's `initialize` `clientInfo.name`) -- the first-party TUI presents as `codex-tui` and is
127
+ entitled to them; a programmatic app-server client identifying honestly as mngr is not. The only
128
+ way to close that gap is to spoof the TUI identity, which OpenAI's terms disallow (see "client
129
+ identity" below). So the TUI agent is how you get full `*-codex` model access on a ChatGPT login
130
+ today, and the app-server variant is a *complement* for the cases where the identity gap is
131
+ acceptable (API-key auth, which carries the full entitlement; or only models the honest identity
132
+ already gets) -- not a replacement.
133
+
134
+ ### What it would give us
135
+ - **Programmatic messaging instead of tmux paste.** `codex app-server` speaks a JSON-RPC
136
+ protocol over a socket; you send a turn with `initialize` -> `thread/start` -> `turn/start`.
137
+ No `send-keys`, no paste-visibility polling.
138
+ - **You can still view it in the TUI.** Launch the TUI as a *viewer* with
139
+ `codex --remote unix://<sock>` (accepts `ws://`, `wss://`, `unix://` too) connected to the
140
+ app-server -- so it runs in tmux and you watch it live, but mngr drives it over the socket.
141
+ - **Clean synchronous readiness.** The `initialize` response / `thread.started` event is an
142
+ unambiguous "ready for input" signal -- it eliminates the lazy-`SessionStart` banner-poll
143
+ workaround entirely.
144
+ - **Cleaner lifecycle/transcript.** `turn.started` / `turn.completed` / `item.*` events could
145
+ drive the RUNNING/WAITING marker and the transcript directly, instead of (or alongside) the
146
+ hook scripts. The hooks, subagents, sandbox, and approval policy are all **engine-level**
147
+ (`codex-core`), so they fire identically whether codex is driven via the TUI or the
148
+ app-server -- the existing marker hooks would keep working.
149
+
150
+ ### How (verified against codex 0.138.0)
151
+ - `codex app-server --listen unix://<sock>` runs the server and **works with the brew/npm
152
+ install**. (The convenience wrapper `codex remote-control start` / `codex app-server daemon`
153
+ requires codex's *standalone* installer at a fixed path -- avoid it; use raw `app-server
154
+ --listen`.) `codex app-server proxy --sock <sock>` proxies stdio to a running server's
155
+ control socket.
156
+ - mngr would override `send_message` to speak JSON-RPC to the socket, and `assemble_command`
157
+ would launch `app-server` + a `--remote` TUI viewer instead of the bare TUI.
158
+
159
+ ### Important: client identity and OpenAI's ToS (do NOT spoof the TUI)
160
+ The app-server sets its `originator` from the `initialize` request's `clientInfo.name`. It is
161
+ **tempting but against the spirit (and likely the letter) of OpenAI's terms** to set
162
+ `clientInfo.name = "codex-tui"` so the backend grants the `*-codex` model entitlement it
163
+ otherwise denies non-TUI clients. That presents a programmatic client as the first-party TUI
164
+ specifically to bypass an *intentional* server-side model gate -- which falls under OpenAI's
165
+ "circumvent any restrictions / bypass any protective measures" clause (codex's own code treats
166
+ these names as a trust boundary; the override env var is literally `CODEX_INTERNAL_ORIGINATOR_OVERRIDE`).
167
+
168
+ So the app-server variant must **identify honestly** (mngr's own client name) and use whatever
169
+ models that identity is legitimately entitled to. For the gated `*-codex` models in app-server
170
+ mode, authenticate with an **API key** (OpenAI's documented path for programmatic workflows) --
171
+ do not spoof the TUI. The genuine `codex` TUI agent in this plugin remains the legitimate way
172
+ to use `*-codex` models on a ChatGPT-subscription login (it really *is* the TUI).
173
+
174
+ (Driving codex programmatically via the app-server on a single user's own ChatGPT login is
175
+ itself fine -- it's a first-party feature and OpenAI staff have called such use "permissive";
176
+ the line we don't cross is identity-spoofing to defeat the model gate, plus the usual no
177
+ credential-sharing / no multi-tenant-proxying / no rate-limit-bypass.)