codexmgr 0.1.2__tar.gz → 0.1.3__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 (106) hide show
  1. {codexmgr-0.1.2 → codexmgr-0.1.3}/.gitignore +4 -1
  2. {codexmgr-0.1.2 → codexmgr-0.1.3}/PKG-INFO +134 -21
  3. {codexmgr-0.1.2 → codexmgr-0.1.3}/README.md +131 -20
  4. {codexmgr-0.1.2 → codexmgr-0.1.3}/pyproject.toml +4 -2
  5. {codexmgr-0.1.2 → codexmgr-0.1.3}/src/codexmgr/__init__.py +1 -1
  6. codexmgr-0.1.3/src/codexmgr/agents/__init__.py +1 -0
  7. codexmgr-0.1.2/src/codexmgr/agents_file.py → codexmgr-0.1.3/src/codexmgr/agents/file.py +1 -1
  8. codexmgr-0.1.2/src/codexmgr/agentsmd.py → codexmgr-0.1.3/src/codexmgr/agents/manager.py +7 -7
  9. {codexmgr-0.1.2/src/codexmgr → codexmgr-0.1.3/src/codexmgr/agents}/renderer.py +1 -1
  10. codexmgr-0.1.3/src/codexmgr/commands/__init__.py +1 -0
  11. {codexmgr-0.1.2/src/codexmgr → codexmgr-0.1.3/src/codexmgr/commands}/codex.py +30 -3
  12. codexmgr-0.1.3/src/codexmgr/commands/codex_jit.py +211 -0
  13. codexmgr-0.1.3/src/codexmgr/commands/config_mutations.py +265 -0
  14. {codexmgr-0.1.2/src/codexmgr → codexmgr-0.1.3/src/codexmgr/commands}/health.py +34 -8
  15. {codexmgr-0.1.2/src/codexmgr → codexmgr-0.1.3/src/codexmgr/commands}/navigation.py +1 -1
  16. codexmgr-0.1.3/src/codexmgr/core/__init__.py +45 -0
  17. codexmgr-0.1.3/src/codexmgr/hooks/__init__.py +25 -0
  18. codexmgr-0.1.3/src/codexmgr/hooks/config.py +167 -0
  19. codexmgr-0.1.3/src/codexmgr/hooks/copies.py +219 -0
  20. codexmgr-0.1.3/src/codexmgr/hooks/listing.py +131 -0
  21. codexmgr-0.1.3/src/codexmgr/hooks/merge.py +255 -0
  22. codexmgr-0.1.3/src/codexmgr/hooks/resolution.py +258 -0
  23. codexmgr-0.1.3/src/codexmgr/hooks/sources.py +127 -0
  24. codexmgr-0.1.3/src/codexmgr/interface/__init__.py +1 -0
  25. {codexmgr-0.1.2/src/codexmgr → codexmgr-0.1.3/src/codexmgr/interface}/cli.py +33 -90
  26. codexmgr-0.1.2/src/codexmgr/cli_parser.py → codexmgr-0.1.3/src/codexmgr/interface/parser.py +82 -64
  27. codexmgr-0.1.3/src/codexmgr/interface/parsers/__init__.py +2 -0
  28. codexmgr-0.1.3/src/codexmgr/interface/parsers/mcp.py +88 -0
  29. codexmgr-0.1.3/src/codexmgr/mcp/__init__.py +56 -0
  30. codexmgr-0.1.2/src/codexmgr/mcp_apply.py → codexmgr-0.1.3/src/codexmgr/mcp/apply.py +2 -2
  31. codexmgr-0.1.2/src/codexmgr/mcp_cli.py → codexmgr-0.1.3/src/codexmgr/mcp/cli.py +31 -24
  32. codexmgr-0.1.2/src/codexmgr/mcp.py → codexmgr-0.1.3/src/codexmgr/mcp/config.py +60 -85
  33. codexmgr-0.1.2/src/codexmgr/mcp_discovery.py → codexmgr-0.1.3/src/codexmgr/mcp/discovery.py +1 -1
  34. codexmgr-0.1.2/src/codexmgr/mcp_fields.py → codexmgr-0.1.3/src/codexmgr/mcp/fields.py +2 -2
  35. codexmgr-0.1.3/src/codexmgr/mcp/tables.py +90 -0
  36. codexmgr-0.1.3/src/codexmgr/packages/__init__.py +13 -0
  37. codexmgr-0.1.3/src/codexmgr/packages/cli.py +109 -0
  38. codexmgr-0.1.3/src/codexmgr/packages/config.py +184 -0
  39. codexmgr-0.1.3/src/codexmgr/packages/listing.py +17 -0
  40. codexmgr-0.1.3/src/codexmgr/packages/mutation.py +207 -0
  41. codexmgr-0.1.3/src/codexmgr/packages/sources.py +80 -0
  42. codexmgr-0.1.3/src/codexmgr/project/__init__.py +1 -0
  43. codexmgr-0.1.3/src/codexmgr/project/apply.py +219 -0
  44. codexmgr-0.1.2/src/codexmgr/project_config.py → codexmgr-0.1.3/src/codexmgr/project/config.py +3 -3
  45. codexmgr-0.1.3/src/codexmgr/project/generated.py +180 -0
  46. codexmgr-0.1.3/src/codexmgr/project/snapshot.py +145 -0
  47. codexmgr-0.1.3/src/codexmgr/project/state.py +43 -0
  48. codexmgr-0.1.3/src/codexmgr/project/sync.py +280 -0
  49. codexmgr-0.1.3/src/codexmgr/skills/__init__.py +28 -0
  50. codexmgr-0.1.2/src/codexmgr/skills.py → codexmgr-0.1.3/src/codexmgr/skills/config.py +31 -42
  51. codexmgr-0.1.3/src/codexmgr/skills/copies.py +199 -0
  52. codexmgr-0.1.2/src/codexmgr/skill_listing.py → codexmgr-0.1.3/src/codexmgr/skills/listing.py +28 -33
  53. codexmgr-0.1.3/src/codexmgr/skills/resolution.py +147 -0
  54. codexmgr-0.1.3/src/codexmgr/skills/sources.py +274 -0
  55. codexmgr-0.1.3/src/codexmgr/tui/__init__.py +2 -0
  56. codexmgr-0.1.3/src/codexmgr/tui/app.py +297 -0
  57. codexmgr-0.1.3/src/codexmgr/tui/cli.py +34 -0
  58. codexmgr-0.1.3/src/codexmgr/tui/diff.py +27 -0
  59. codexmgr-0.1.3/src/codexmgr/tui/items.py +252 -0
  60. codexmgr-0.1.3/src/codexmgr/tui/models.py +50 -0
  61. codexmgr-0.1.3/src/codexmgr/tui/mutations.py +97 -0
  62. codexmgr-0.1.3/src/codexmgr/tui/package_refs.py +89 -0
  63. codexmgr-0.1.3/src/codexmgr/tui/package_selection.py +23 -0
  64. codexmgr-0.1.3/src/codexmgr/tui/rendering.py +92 -0
  65. codexmgr-0.1.3/src/codexmgr/tui/state.py +299 -0
  66. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/conftest.py +1 -1
  67. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_agents_file.py +2 -2
  68. codexmgr-0.1.3/tests/test_apply_check_cli.py +273 -0
  69. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_cd_cli.py +1 -1
  70. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_cli.py +125 -6
  71. codexmgr-0.1.3/tests/test_codex_cli.py +398 -0
  72. codexmgr-0.1.3/tests/test_hooks_cli.py +436 -0
  73. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_mcp_cli.py +60 -4
  74. codexmgr-0.1.3/tests/test_packages_cli.py +601 -0
  75. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_paths.py +1 -1
  76. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_renderer.py +2 -2
  77. codexmgr-0.1.3/tests/test_skill_copies_cli.py +179 -0
  78. codexmgr-0.1.3/tests/test_skill_home_sources_cli.py +58 -0
  79. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_skills_cli.py +51 -0
  80. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_status_doctor_cli.py +116 -8
  81. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_sync_cli.py +10 -4
  82. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_toml_io.py +2 -2
  83. codexmgr-0.1.3/tests/test_tui_app.py +154 -0
  84. codexmgr-0.1.3/tests/test_tui_state.py +338 -0
  85. {codexmgr-0.1.2 → codexmgr-0.1.3}/uv.lock +125 -1
  86. codexmgr-0.1.2/src/codexmgr/project.py +0 -206
  87. codexmgr-0.1.2/src/codexmgr/sync.py +0 -134
  88. codexmgr-0.1.2/tests/test_apply_check_cli.py +0 -83
  89. codexmgr-0.1.2/tests/test_codex_cli.py +0 -154
  90. {codexmgr-0.1.2 → codexmgr-0.1.3}/.github/actions/install_package/action.yml +0 -0
  91. {codexmgr-0.1.2 → codexmgr-0.1.3}/.github/workflows/py_test.yml +0 -0
  92. {codexmgr-0.1.2 → codexmgr-0.1.3}/.github/workflows/version_publish_main.yml +0 -0
  93. {codexmgr-0.1.2 → codexmgr-0.1.3}/pytest.toml +0 -0
  94. {codexmgr-0.1.2/src/codexmgr → codexmgr-0.1.3/src/codexmgr/core}/errors.py +0 -0
  95. {codexmgr-0.1.2/src/codexmgr → codexmgr-0.1.3/src/codexmgr/core}/options.py +0 -0
  96. {codexmgr-0.1.2/src/codexmgr → codexmgr-0.1.3/src/codexmgr/core}/paths.py +0 -0
  97. {codexmgr-0.1.2/src/codexmgr → codexmgr-0.1.3/src/codexmgr/core}/toml_io.py +0 -0
  98. {codexmgr-0.1.2 → codexmgr-0.1.3}/src/codexmgr/py.typed +0 -0
  99. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_agentsmd_list_cli.py +0 -0
  100. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_agentsmd_tools_cli.py +0 -0
  101. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_empty_skill_config_cli.py +0 -0
  102. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_home_resolution_cli.py +0 -0
  103. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_mcp_apply_cli.py +0 -0
  104. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_package_metadata.py +0 -0
  105. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_python_compatibility.py +0 -0
  106. {codexmgr-0.1.2 → codexmgr-0.1.3}/tests/test_skill_list_cli.py +0 -0
@@ -11,5 +11,8 @@ wheels/
11
11
  AGENTS.md
12
12
  tasks.md
13
13
  .thoughts
14
+ .brainstorm
14
15
  .plan
15
- .agent
16
+ .agent
17
+ .rules
18
+ .docs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codexmgr
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Manage project-local Codex configuration from reusable templates
5
5
  Keywords: agents,cli,codex,configuration,skills
6
6
  Classifier: Development Status :: 4 - Beta
@@ -13,8 +13,10 @@ Classifier: Programming Language :: Python :: 3.13
13
13
  Classifier: Topic :: Software Development
14
14
  Classifier: Typing :: Typed
15
15
  Requires-Python: >=3.11
16
+ Requires-Dist: textual>=8.2.7
16
17
  Requires-Dist: tomlkit>=0.15.0
17
18
  Provides-Extra: dev
19
+ Requires-Dist: pytest-asyncio>=1.4.0; extra == 'dev'
18
20
  Requires-Dist: pytest>=9.0.3; extra == 'dev'
19
21
  Requires-Dist: pyyaml>=6.0.3; extra == 'dev'
20
22
  Description-Content-Type: text/markdown
@@ -31,7 +33,10 @@ The tool is intentionally narrow:
31
33
 
32
34
  - compose reusable AGENTS.md instruction fragments
33
35
  - enable or disable Codex skills per project
36
+ - enable or disable reusable Codex hook bundles per project
37
+ - enable or disable packaged sets of AGENTS.md, skill, and hook settings
34
38
  - enable, disable, inspect, and update safe project-local MCP overrides
39
+ - use an interactive terminal UI for common project management tasks
35
40
  - write reproducible lock data for the resolved project configuration
36
41
  - run `codex` with project `.codex/config.toml` values translated into `-c`
37
42
  overrides
@@ -95,10 +100,14 @@ This updates `.codex/codexmgr.toml`, runs `apply`, writes
95
100
 
96
101
  - `.codex/codexmgr.toml`: source configuration edited by CLI commands or by
97
102
  hand
98
- - `.codex/codexmgr.lock`: resolved template, skill, and MCP state written by
103
+ - `.codex/codexmgr.lock`: resolved template, skill, hook, and MCP state written by
99
104
  `apply`
100
105
  - `.codex/config.toml`: Codex config updated with `[[skills.config]]` entries
101
106
  and `[mcp_servers.<id>]` overrides
107
+ - `.codex/hooks.json`: Codex hook config updated with enabled reusable hook
108
+ bundles while preserving unmanaged local hooks
109
+ - `.codex/hooks/<name>`: project-local copies of enabled hook bundle support
110
+ files
102
111
  - `AGENTS.md`: project instructions, with only the managed block replaced
103
112
 
104
113
  The managed AGENTS.md block is:
@@ -113,7 +122,7 @@ Manual content outside this block is preserved. If the block is missing,
113
122
 
114
123
  ## Project Configuration
115
124
 
116
- `.codex/codexmgr.toml` supports AGENTS.md templates, skill state, and MCP
125
+ `.codex/codexmgr.toml` supports AGENTS.md templates, skill state, hook state, and MCP
117
126
  overrides:
118
127
 
119
128
  ```toml
@@ -124,6 +133,10 @@ src = ["coding", "/absolute/or/project-relative/template.toml"]
124
133
  enabled = ["review-helper"]
125
134
  disabled = ["experimental-skill", "skills/local-disabled"]
126
135
 
136
+ [hooks]
137
+ enabled = ["repo-rules"]
138
+ disabled = ["experimental-hook"]
139
+
127
140
  [mcp.servers.browsermcp]
128
141
  enabled = true
129
142
  bearer_token_env_var = "BROWSERMCP_TOKEN"
@@ -134,15 +147,82 @@ Named AGENTS.md templates resolve from `$CODEXMGR_HOME/agentsmd/<name>.toml`.
134
147
  Path-like template values resolve relative to the project unless they are
135
148
  absolute paths.
136
149
 
137
- Named skills resolve from `$CODEX_HOME/skills/<name>/SKILL.md`. If `CODEX_HOME`
138
- is unset, `~/.codex` is used. Path-like skill values resolve to either a
139
- `SKILL.md` file or a directory containing `SKILL.md`. Missing skills are written
140
- as name-based entries so Codex can resolve them later.
150
+ Named skills resolve from `$CODEXMGR_HOME/skills/<name>/SKILL.md` or
151
+ `$CODEX_HOME/skills/<name>/SKILL.md`; duplicate names across distinct homes
152
+ fail. Enabled CODEXMGR_HOME skills are copied into `.agents/skills/<name>` on
153
+ every apply by overlaying source files while preserving extra local files.
154
+ Path-like skill values resolve to either a `SKILL.md` file or a directory
155
+ containing `SKILL.md`. Missing skills are written as name-based entries so Codex
156
+ can resolve them later.
157
+
158
+ Named hooks resolve from `$CODEXMGR_HOME/hooks/<name>/hooks.json`. Enabled hook
159
+ bundles are merged into `.codex/hooks.json` on every apply with
160
+ `codexmanager_meta` added to each managed handler. Existing unmanaged hooks are
161
+ preserved. Bundle files other than the root `hooks.json` are copied into
162
+ `.codex/hooks/<name>`.
163
+
164
+ Packaged configurations resolve from
165
+ `$CODEXMGR_HOME/packages/<name>/config.toml`. A package config is a TOML
166
+ document that can contain root `agentsmd`, `hooks`, and `skills` string lists
167
+ plus optional profile tables:
168
+
169
+ ```toml
170
+ agentsmd = []
171
+ hooks = ["repo-rules"]
172
+ skills = ["repo-rule-manager"]
173
+
174
+ [profiles.strict]
175
+ agentsmd = ["strict-coding"]
176
+ hooks = ["strict-rules"]
177
+ skills = ["strict-review"]
178
+ ```
179
+
180
+ `codexmgr package enable <name>` validates package AGENTS.md and hook
181
+ references, then updates `.codex/codexmgr.toml` as if the corresponding
182
+ `agentsmd add`, `hooks enable`, and `skill enable` commands had been run.
183
+ `codexmgr package disable <name>` removes package AGENTS.md entries when
184
+ present and disables the package skills and hooks.
185
+
186
+ Package profiles are merged with the root package entries:
187
+
188
+ ```bash
189
+ codexmgr package enable repo-rules --profile strict coding --profile python
190
+ ```
191
+
192
+ Direct mutating commands also accept batch targets, for example:
193
+
194
+ ```bash
195
+ codexmgr agentsmd add coding python
196
+ codexmgr skill enable review-helper repo-rule-manager
197
+ codexmgr hooks enable repo-rules audit
198
+ codexmgr mcp enable browsermcp context7
199
+ ```
141
200
 
142
201
  Mutating commands run `apply` automatically unless `--no-sync` is passed.
143
202
  Project guidelines require `apply` whenever `.codex/codexmgr.toml` changes,
144
203
  unless `--no-sync` was explicitly requested.
145
204
 
205
+ ## Interactive TUI
206
+
207
+ `codexmgr tui` opens a Textual-based terminal UI for managing project-local
208
+ configuration. It shows AGENTS.md templates, skills, hooks, packages, and MCP
209
+ server enable overrides in selectable lists. Changes are staged in memory while
210
+ you navigate and toggle entries. Press `s` to save; the save writes
211
+ `.codex/codexmgr.toml` once and runs `apply` once unless `--no-sync` was used.
212
+ Package profiles appear as separate selectable rows under their package.
213
+
214
+ ```bash
215
+ codexmgr tui
216
+ codexmgr tui --no-sync
217
+ codexmgr tui --show-diff
218
+ ```
219
+
220
+ The dashboard shows generated-file sync state. By default it lists stale
221
+ generated paths; with `--show-diff`, it shows unified diffs for the staged
222
+ configuration. MCP editing in the TUI is intentionally limited to the
223
+ project-local `enabled` override. Advanced MCP fields remain available through
224
+ the classic `codexmgr mcp ...` commands.
225
+
146
226
  ## Template Format
147
227
 
148
228
  Template files are TOML documents. Each top-level key must be a table and
@@ -180,20 +260,27 @@ codexmgr apply --diff
180
260
  codexmgr cd [--path | --explorer | --terminal]
181
261
  codexmgr doctor
182
262
  codexmgr status
263
+ codexmgr tui [--no-sync] [--show-diff]
183
264
  codexmgr agentsmd list
184
265
  codexmgr agentsmd show <name-or-template-path>
185
266
  codexmgr agentsmd validate <name-or-template-path>
186
- codexmgr agentsmd add [--no-sync] <name-or-template-path>
187
- codexmgr agentsmd remove [--no-sync] <name-or-template-path>
267
+ codexmgr agentsmd add [--no-sync] <name-or-template-path> [...]
268
+ codexmgr agentsmd remove [--no-sync] <name-or-template-path> [...]
188
269
  codexmgr init-template agentsmd <name>
189
270
  codexmgr skill list
190
- codexmgr skill enable [--no-sync] <name-or-skill-path>
191
- codexmgr skill disable [--no-sync] <name-or-skill-path>
271
+ codexmgr skill enable [--no-sync] <name-or-skill-path> [...]
272
+ codexmgr skill disable [--no-sync] <name-or-skill-path> [...]
273
+ codexmgr hooks list
274
+ codexmgr hooks enable [--no-sync] <hook-name> [...]
275
+ codexmgr hooks disable [--no-sync] <hook-name> [...]
276
+ codexmgr package list
277
+ codexmgr package enable [--no-sync] <package-name> [...] [--profile <name> [...]]
278
+ codexmgr package disable [--no-sync] <package-name> [...] [--profile <name> [...]]
192
279
  codexmgr mcp list
193
280
  codexmgr mcp show <server-id>
194
281
  codexmgr mcp validate
195
- codexmgr mcp enable [--no-sync] <server-id>
196
- codexmgr mcp disable [--no-sync] <server-id>
282
+ codexmgr mcp enable [--no-sync] <server-id> [...]
283
+ codexmgr mcp disable [--no-sync] <server-id> [...]
197
284
  codexmgr mcp set-token-env [--no-sync] <server-id> <ENV_VAR>
198
285
  codexmgr mcp add-env-var [--no-sync] <server-id> <ENV_VAR>
199
286
  codexmgr mcp remove-env-var [--no-sync] <server-id> <ENV_VAR>
@@ -207,9 +294,10 @@ codexmgr codex <args...>
207
294
 
208
295
  `apply` reads `.codex/codexmgr.toml`, resolves configured sources, writes
209
296
  `.codex/codexmgr.lock`, updates `.codex/config.toml` skill entries when a
210
- `[skills]` table is configured, writes local `[mcp_servers.<id>]` overrides when
211
- `[mcp]` is configured, and refreshes the generated `AGENTS.md` block when
212
- `[agents_md]` is configured.
297
+ `[skills]` table is configured, writes `.codex/hooks.json` when `[hooks]` is
298
+ configured, writes local `[mcp_servers.<id>]` overrides when `[mcp]` is
299
+ configured, and refreshes the generated `AGENTS.md` block when `[agents_md]` is
300
+ configured.
213
301
 
214
302
  `apply --check` exits with a failure if generated files are out of sync without
215
303
  writing them. `apply --diff` also avoids writing and prints unified diffs for
@@ -221,10 +309,19 @@ the directory in a file explorer, and `codexmgr cd --terminal` to open a new
221
309
  terminal there.
222
310
 
223
311
  `doctor` checks project setup, home environment variables, project TOML syntax,
224
- referenced snippets, enabled skills, and stale generated files.
312
+ referenced snippets, enabled skills, enabled hook bundles, and stale generated
313
+ files.
314
+
315
+ `status` prints the resolved homes, configured snippets, skills, hooks, and
316
+ whether generated files are in sync.
225
317
 
226
- `status` prints the resolved homes, configured snippets and skills, and whether
227
- generated files are in sync.
318
+ `codexmgr codex` can run with a just-in-time package/profile overlay without
319
+ changing `.codex/codexmgr.toml`. Put Codex arguments after `--` when using this
320
+ syntax:
321
+
322
+ ```bash
323
+ codexmgr codex repo-rules --profile strict coding --profile python -- exec "review this"
324
+ ```
228
325
 
229
326
  ## Project MCP Overrides
230
327
 
@@ -302,12 +399,28 @@ is not present.
302
399
  `init-template agentsmd` creates a starter template under
303
400
  `$CODEXMGR_HOME/agentsmd` and refuses to overwrite an existing template.
304
401
 
305
- `skill list` prints available `$CODEX_HOME/skills/*/SKILL.md` entries and marks
306
- configured skills as enabled, disabled, or missing.
402
+ `skill list` prints available `$CODEXMGR_HOME/skills/*/SKILL.md`,
403
+ `$CODEX_HOME/skills/*/SKILL.md`, and local `.agents/skills/*/SKILL.md` entries
404
+ and marks configured skills as enabled, disabled, or missing.
307
405
 
308
406
  `skill enable` and `skill disable` keep enabled and disabled lists mutually
309
407
  exclusive. Repeated commands keep one entry.
310
408
 
409
+ `hooks list` prints available `$CODEXMGR_HOME/hooks/*/hooks.json` entries and
410
+ marks configured hook bundles as enabled, disabled, or missing.
411
+
412
+ `hooks enable` validates that the named hook bundle exists before writing
413
+ config. `hooks enable` and `hooks disable` keep enabled and disabled lists
414
+ mutually exclusive. Repeated commands keep one entry.
415
+
416
+ `package list` prints available `$CODEXMGR_HOME/packages/*/config.toml`
417
+ entries in sorted order.
418
+
419
+ `package enable` and `package disable` proxy to existing AGENTS.md, skill, and
420
+ hook project-config mutations. Package state is not tracked separately; the
421
+ resulting `[agents_md]`, `[skills]`, and `[hooks]` tables remain the source of
422
+ truth.
423
+
311
424
  `codex` forwards arguments to the real `codex` command. Values from
312
425
  `.codex/config.toml` are flattened into `-c key=value` overrides. User-provided
313
426
  `-c` or `--config` overrides are merged after project config: scalar values
@@ -10,7 +10,10 @@ The tool is intentionally narrow:
10
10
 
11
11
  - compose reusable AGENTS.md instruction fragments
12
12
  - enable or disable Codex skills per project
13
+ - enable or disable reusable Codex hook bundles per project
14
+ - enable or disable packaged sets of AGENTS.md, skill, and hook settings
13
15
  - enable, disable, inspect, and update safe project-local MCP overrides
16
+ - use an interactive terminal UI for common project management tasks
14
17
  - write reproducible lock data for the resolved project configuration
15
18
  - run `codex` with project `.codex/config.toml` values translated into `-c`
16
19
  overrides
@@ -74,10 +77,14 @@ This updates `.codex/codexmgr.toml`, runs `apply`, writes
74
77
 
75
78
  - `.codex/codexmgr.toml`: source configuration edited by CLI commands or by
76
79
  hand
77
- - `.codex/codexmgr.lock`: resolved template, skill, and MCP state written by
80
+ - `.codex/codexmgr.lock`: resolved template, skill, hook, and MCP state written by
78
81
  `apply`
79
82
  - `.codex/config.toml`: Codex config updated with `[[skills.config]]` entries
80
83
  and `[mcp_servers.<id>]` overrides
84
+ - `.codex/hooks.json`: Codex hook config updated with enabled reusable hook
85
+ bundles while preserving unmanaged local hooks
86
+ - `.codex/hooks/<name>`: project-local copies of enabled hook bundle support
87
+ files
81
88
  - `AGENTS.md`: project instructions, with only the managed block replaced
82
89
 
83
90
  The managed AGENTS.md block is:
@@ -92,7 +99,7 @@ Manual content outside this block is preserved. If the block is missing,
92
99
 
93
100
  ## Project Configuration
94
101
 
95
- `.codex/codexmgr.toml` supports AGENTS.md templates, skill state, and MCP
102
+ `.codex/codexmgr.toml` supports AGENTS.md templates, skill state, hook state, and MCP
96
103
  overrides:
97
104
 
98
105
  ```toml
@@ -103,6 +110,10 @@ src = ["coding", "/absolute/or/project-relative/template.toml"]
103
110
  enabled = ["review-helper"]
104
111
  disabled = ["experimental-skill", "skills/local-disabled"]
105
112
 
113
+ [hooks]
114
+ enabled = ["repo-rules"]
115
+ disabled = ["experimental-hook"]
116
+
106
117
  [mcp.servers.browsermcp]
107
118
  enabled = true
108
119
  bearer_token_env_var = "BROWSERMCP_TOKEN"
@@ -113,15 +124,82 @@ Named AGENTS.md templates resolve from `$CODEXMGR_HOME/agentsmd/<name>.toml`.
113
124
  Path-like template values resolve relative to the project unless they are
114
125
  absolute paths.
115
126
 
116
- Named skills resolve from `$CODEX_HOME/skills/<name>/SKILL.md`. If `CODEX_HOME`
117
- is unset, `~/.codex` is used. Path-like skill values resolve to either a
118
- `SKILL.md` file or a directory containing `SKILL.md`. Missing skills are written
119
- as name-based entries so Codex can resolve them later.
127
+ Named skills resolve from `$CODEXMGR_HOME/skills/<name>/SKILL.md` or
128
+ `$CODEX_HOME/skills/<name>/SKILL.md`; duplicate names across distinct homes
129
+ fail. Enabled CODEXMGR_HOME skills are copied into `.agents/skills/<name>` on
130
+ every apply by overlaying source files while preserving extra local files.
131
+ Path-like skill values resolve to either a `SKILL.md` file or a directory
132
+ containing `SKILL.md`. Missing skills are written as name-based entries so Codex
133
+ can resolve them later.
134
+
135
+ Named hooks resolve from `$CODEXMGR_HOME/hooks/<name>/hooks.json`. Enabled hook
136
+ bundles are merged into `.codex/hooks.json` on every apply with
137
+ `codexmanager_meta` added to each managed handler. Existing unmanaged hooks are
138
+ preserved. Bundle files other than the root `hooks.json` are copied into
139
+ `.codex/hooks/<name>`.
140
+
141
+ Packaged configurations resolve from
142
+ `$CODEXMGR_HOME/packages/<name>/config.toml`. A package config is a TOML
143
+ document that can contain root `agentsmd`, `hooks`, and `skills` string lists
144
+ plus optional profile tables:
145
+
146
+ ```toml
147
+ agentsmd = []
148
+ hooks = ["repo-rules"]
149
+ skills = ["repo-rule-manager"]
150
+
151
+ [profiles.strict]
152
+ agentsmd = ["strict-coding"]
153
+ hooks = ["strict-rules"]
154
+ skills = ["strict-review"]
155
+ ```
156
+
157
+ `codexmgr package enable <name>` validates package AGENTS.md and hook
158
+ references, then updates `.codex/codexmgr.toml` as if the corresponding
159
+ `agentsmd add`, `hooks enable`, and `skill enable` commands had been run.
160
+ `codexmgr package disable <name>` removes package AGENTS.md entries when
161
+ present and disables the package skills and hooks.
162
+
163
+ Package profiles are merged with the root package entries:
164
+
165
+ ```bash
166
+ codexmgr package enable repo-rules --profile strict coding --profile python
167
+ ```
168
+
169
+ Direct mutating commands also accept batch targets, for example:
170
+
171
+ ```bash
172
+ codexmgr agentsmd add coding python
173
+ codexmgr skill enable review-helper repo-rule-manager
174
+ codexmgr hooks enable repo-rules audit
175
+ codexmgr mcp enable browsermcp context7
176
+ ```
120
177
 
121
178
  Mutating commands run `apply` automatically unless `--no-sync` is passed.
122
179
  Project guidelines require `apply` whenever `.codex/codexmgr.toml` changes,
123
180
  unless `--no-sync` was explicitly requested.
124
181
 
182
+ ## Interactive TUI
183
+
184
+ `codexmgr tui` opens a Textual-based terminal UI for managing project-local
185
+ configuration. It shows AGENTS.md templates, skills, hooks, packages, and MCP
186
+ server enable overrides in selectable lists. Changes are staged in memory while
187
+ you navigate and toggle entries. Press `s` to save; the save writes
188
+ `.codex/codexmgr.toml` once and runs `apply` once unless `--no-sync` was used.
189
+ Package profiles appear as separate selectable rows under their package.
190
+
191
+ ```bash
192
+ codexmgr tui
193
+ codexmgr tui --no-sync
194
+ codexmgr tui --show-diff
195
+ ```
196
+
197
+ The dashboard shows generated-file sync state. By default it lists stale
198
+ generated paths; with `--show-diff`, it shows unified diffs for the staged
199
+ configuration. MCP editing in the TUI is intentionally limited to the
200
+ project-local `enabled` override. Advanced MCP fields remain available through
201
+ the classic `codexmgr mcp ...` commands.
202
+
125
203
  ## Template Format
126
204
 
127
205
  Template files are TOML documents. Each top-level key must be a table and
@@ -159,20 +237,27 @@ codexmgr apply --diff
159
237
  codexmgr cd [--path | --explorer | --terminal]
160
238
  codexmgr doctor
161
239
  codexmgr status
240
+ codexmgr tui [--no-sync] [--show-diff]
162
241
  codexmgr agentsmd list
163
242
  codexmgr agentsmd show <name-or-template-path>
164
243
  codexmgr agentsmd validate <name-or-template-path>
165
- codexmgr agentsmd add [--no-sync] <name-or-template-path>
166
- codexmgr agentsmd remove [--no-sync] <name-or-template-path>
244
+ codexmgr agentsmd add [--no-sync] <name-or-template-path> [...]
245
+ codexmgr agentsmd remove [--no-sync] <name-or-template-path> [...]
167
246
  codexmgr init-template agentsmd <name>
168
247
  codexmgr skill list
169
- codexmgr skill enable [--no-sync] <name-or-skill-path>
170
- codexmgr skill disable [--no-sync] <name-or-skill-path>
248
+ codexmgr skill enable [--no-sync] <name-or-skill-path> [...]
249
+ codexmgr skill disable [--no-sync] <name-or-skill-path> [...]
250
+ codexmgr hooks list
251
+ codexmgr hooks enable [--no-sync] <hook-name> [...]
252
+ codexmgr hooks disable [--no-sync] <hook-name> [...]
253
+ codexmgr package list
254
+ codexmgr package enable [--no-sync] <package-name> [...] [--profile <name> [...]]
255
+ codexmgr package disable [--no-sync] <package-name> [...] [--profile <name> [...]]
171
256
  codexmgr mcp list
172
257
  codexmgr mcp show <server-id>
173
258
  codexmgr mcp validate
174
- codexmgr mcp enable [--no-sync] <server-id>
175
- codexmgr mcp disable [--no-sync] <server-id>
259
+ codexmgr mcp enable [--no-sync] <server-id> [...]
260
+ codexmgr mcp disable [--no-sync] <server-id> [...]
176
261
  codexmgr mcp set-token-env [--no-sync] <server-id> <ENV_VAR>
177
262
  codexmgr mcp add-env-var [--no-sync] <server-id> <ENV_VAR>
178
263
  codexmgr mcp remove-env-var [--no-sync] <server-id> <ENV_VAR>
@@ -186,9 +271,10 @@ codexmgr codex <args...>
186
271
 
187
272
  `apply` reads `.codex/codexmgr.toml`, resolves configured sources, writes
188
273
  `.codex/codexmgr.lock`, updates `.codex/config.toml` skill entries when a
189
- `[skills]` table is configured, writes local `[mcp_servers.<id>]` overrides when
190
- `[mcp]` is configured, and refreshes the generated `AGENTS.md` block when
191
- `[agents_md]` is configured.
274
+ `[skills]` table is configured, writes `.codex/hooks.json` when `[hooks]` is
275
+ configured, writes local `[mcp_servers.<id>]` overrides when `[mcp]` is
276
+ configured, and refreshes the generated `AGENTS.md` block when `[agents_md]` is
277
+ configured.
192
278
 
193
279
  `apply --check` exits with a failure if generated files are out of sync without
194
280
  writing them. `apply --diff` also avoids writing and prints unified diffs for
@@ -200,10 +286,19 @@ the directory in a file explorer, and `codexmgr cd --terminal` to open a new
200
286
  terminal there.
201
287
 
202
288
  `doctor` checks project setup, home environment variables, project TOML syntax,
203
- referenced snippets, enabled skills, and stale generated files.
289
+ referenced snippets, enabled skills, enabled hook bundles, and stale generated
290
+ files.
291
+
292
+ `status` prints the resolved homes, configured snippets, skills, hooks, and
293
+ whether generated files are in sync.
204
294
 
205
- `status` prints the resolved homes, configured snippets and skills, and whether
206
- generated files are in sync.
295
+ `codexmgr codex` can run with a just-in-time package/profile overlay without
296
+ changing `.codex/codexmgr.toml`. Put Codex arguments after `--` when using this
297
+ syntax:
298
+
299
+ ```bash
300
+ codexmgr codex repo-rules --profile strict coding --profile python -- exec "review this"
301
+ ```
207
302
 
208
303
  ## Project MCP Overrides
209
304
 
@@ -281,12 +376,28 @@ is not present.
281
376
  `init-template agentsmd` creates a starter template under
282
377
  `$CODEXMGR_HOME/agentsmd` and refuses to overwrite an existing template.
283
378
 
284
- `skill list` prints available `$CODEX_HOME/skills/*/SKILL.md` entries and marks
285
- configured skills as enabled, disabled, or missing.
379
+ `skill list` prints available `$CODEXMGR_HOME/skills/*/SKILL.md`,
380
+ `$CODEX_HOME/skills/*/SKILL.md`, and local `.agents/skills/*/SKILL.md` entries
381
+ and marks configured skills as enabled, disabled, or missing.
286
382
 
287
383
  `skill enable` and `skill disable` keep enabled and disabled lists mutually
288
384
  exclusive. Repeated commands keep one entry.
289
385
 
386
+ `hooks list` prints available `$CODEXMGR_HOME/hooks/*/hooks.json` entries and
387
+ marks configured hook bundles as enabled, disabled, or missing.
388
+
389
+ `hooks enable` validates that the named hook bundle exists before writing
390
+ config. `hooks enable` and `hooks disable` keep enabled and disabled lists
391
+ mutually exclusive. Repeated commands keep one entry.
392
+
393
+ `package list` prints available `$CODEXMGR_HOME/packages/*/config.toml`
394
+ entries in sorted order.
395
+
396
+ `package enable` and `package disable` proxy to existing AGENTS.md, skill, and
397
+ hook project-config mutations. Package state is not tracked separately; the
398
+ resulting `[agents_md]`, `[skills]`, and `[hooks]` tables remain the source of
399
+ truth.
400
+
290
401
  `codex` forwards arguments to the real `codex` command. Values from
291
402
  `.codex/config.toml` are flattened into `-c key=value` overrides. User-provided
292
403
  `-c` or `--config` overrides are merged after project config: scalar values
@@ -1,10 +1,11 @@
1
1
  [project]
2
2
  name = "codexmgr"
3
- version = "0.1.2"
3
+ version = "0.1.3"
4
4
  description = "Manage project-local Codex configuration from reusable templates"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
7
  dependencies = [
8
+ "textual>=8.2.7",
8
9
  "tomlkit>=0.15.0",
9
10
  ]
10
11
  keywords = ["codex", "cli", "configuration", "agents", "skills"]
@@ -21,12 +22,13 @@ classifiers = [
21
22
  ]
22
23
 
23
24
  [project.scripts]
24
- codexmgr = "codexmgr.cli:entrypoint"
25
+ codexmgr = "codexmgr.interface.cli:entrypoint"
25
26
 
26
27
  [project.optional-dependencies]
27
28
  dev = [
28
29
  "pytest>=9.0.3",
29
30
  "pyyaml>=6.0.3",
31
+ "pytest-asyncio>=1.4.0",
30
32
  ]
31
33
 
32
34
  [build-system]
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.1.2"
5
+ __version__ = "0.1.3"
@@ -0,0 +1 @@
1
+ """AGENTS.md template resolution, rendering, and managed-file packages."""
@@ -2,7 +2,7 @@
2
2
 
3
3
  from pathlib import Path
4
4
 
5
- from .errors import CommandError
5
+ from ..core.errors import CommandError
6
6
 
7
7
  BEGIN_MARKER = "<!-- BEGIN CODEXMGR GENERATED -->"
8
8
  END_MARKER = "<!-- END CODEXMGR GENERATED -->"
@@ -3,18 +3,18 @@
3
3
  from pathlib import Path
4
4
  from typing import Any
5
5
 
6
- from .agents_file import write_managed_agents_md
7
- from .errors import CommandError
8
- from .options import list_toml_options
9
- from .paths import agents_md_path, config_path, resolve_template
10
- from .project_config import (
6
+ from .file import write_managed_agents_md
7
+ from .renderer import render_agents_markdown
8
+ from ..core.errors import CommandError
9
+ from ..core.options import list_toml_options
10
+ from ..core.paths import agents_md_path, config_path, resolve_template
11
+ from ..core.toml_io import load_optional_toml_file, load_toml_file, write_toml_file
12
+ from ..project.config import (
11
13
  agents_md_sources,
12
14
  load_required_project_config,
13
15
  require_codex_dir,
14
16
  set_agents_md_sources,
15
17
  )
16
- from .renderer import render_agents_markdown
17
- from .toml_io import load_optional_toml_file, load_toml_file, write_toml_file
18
18
 
19
19
 
20
20
  def add_agentsmd(reference: str, cwd: Path, codexmgr_home: Path) -> str:
@@ -5,7 +5,7 @@ from collections.abc import Mapping
5
5
  from dataclasses import dataclass, field
6
6
  from typing import Any
7
7
 
8
- from .errors import CommandError
8
+ from ..core.errors import CommandError
9
9
 
10
10
 
11
11
  @dataclass
@@ -0,0 +1 @@
1
+ """Command implementations for CLI-facing codexmgr features."""
@@ -6,9 +6,36 @@ from collections.abc import Mapping
6
6
  from pathlib import Path
7
7
  from typing import Any
8
8
 
9
- from .errors import CommandError
10
- from .paths import codex_config_path
11
- from .toml_io import format_toml_value, load_optional_toml_file
9
+ from ..core.errors import CommandError
10
+ from ..core.paths import codex_config_path
11
+ from ..core.toml_io import format_toml_value, load_optional_toml_file
12
+ from .codex_jit import parse_codex_jit_request, run_with_jit_overlay
13
+
14
+
15
+ def run_codex_command(
16
+ cwd: Path,
17
+ codex_home: Path,
18
+ codexmgr_home: Path,
19
+ codex_args: list[str],
20
+ ) -> int:
21
+ """Apply project config and run Codex, optionally with a JIT overlay.
22
+
23
+ Args:
24
+ cwd: Project working directory for the external Codex process.
25
+ codex_home: Codex home used to resolve project skills.
26
+ codexmgr_home: codexmgr home containing package sources.
27
+ codex_args: Raw arguments after ``codexmgr codex``.
28
+
29
+ Returns:
30
+ The external Codex process return code.
31
+ """
32
+ request = parse_codex_jit_request(codex_args)
33
+ if request.enabled:
34
+ return run_with_jit_overlay(request, cwd, codex_home, codexmgr_home, run_codex)
35
+ from ..project.apply import apply_project_config
36
+
37
+ apply_project_config(cwd, codex_home, codexmgr_home)
38
+ return run_codex(cwd, codex_args)
12
39
 
13
40
 
14
41
  def run_codex(cwd: Path, codex_args: list[str]) -> int: