codexmgr 0.1.3__tar.gz → 0.2.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 (124) hide show
  1. {codexmgr-0.1.3 → codexmgr-0.2.0}/PKG-INFO +70 -23
  2. {codexmgr-0.1.3 → codexmgr-0.2.0}/README.md +69 -22
  3. {codexmgr-0.1.3 → codexmgr-0.2.0}/pyproject.toml +1 -1
  4. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/__init__.py +1 -1
  5. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/codex_jit.py +20 -1
  6. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/health.py +48 -0
  7. codexmgr-0.2.0/src/codexmgr/commands/rules.py +115 -0
  8. codexmgr-0.2.0/src/codexmgr/custom_agents/__init__.py +1 -0
  9. codexmgr-0.2.0/src/codexmgr/custom_agents/cli.py +120 -0
  10. codexmgr-0.2.0/src/codexmgr/custom_agents/config.py +165 -0
  11. codexmgr-0.2.0/src/codexmgr/custom_agents/copies.py +164 -0
  12. codexmgr-0.2.0/src/codexmgr/custom_agents/listing.py +131 -0
  13. codexmgr-0.2.0/src/codexmgr/custom_agents/resolution.py +95 -0
  14. codexmgr-0.2.0/src/codexmgr/custom_agents/sources.py +135 -0
  15. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/interface/cli.py +8 -0
  16. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/interface/parser.py +26 -0
  17. codexmgr-0.2.0/src/codexmgr/interface/parsers/agents.py +27 -0
  18. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/config.py +26 -3
  19. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/mutation.py +15 -1
  20. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/apply.py +81 -1
  21. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/generated.py +18 -1
  22. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/state.py +10 -0
  23. codexmgr-0.2.0/src/codexmgr/rules/__init__.py +1 -0
  24. codexmgr-0.2.0/src/codexmgr/rules/config.py +193 -0
  25. codexmgr-0.2.0/src/codexmgr/rules/copies.py +198 -0
  26. codexmgr-0.2.0/src/codexmgr/rules/listing.py +135 -0
  27. codexmgr-0.2.0/src/codexmgr/rules/resolution.py +180 -0
  28. codexmgr-0.2.0/src/codexmgr/rules/sources.py +146 -0
  29. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/app.py +50 -53
  30. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/items.py +37 -0
  31. codexmgr-0.2.0/src/codexmgr/tui/mutations.py +170 -0
  32. codexmgr-0.2.0/src/codexmgr/tui/package_state.py +214 -0
  33. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/rendering.py +24 -2
  34. codexmgr-0.2.0/src/codexmgr/tui/rule_items.py +58 -0
  35. codexmgr-0.2.0/src/codexmgr/tui/sections.py +203 -0
  36. codexmgr-0.2.0/src/codexmgr/tui/staged_packages.py +99 -0
  37. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/state.py +52 -95
  38. codexmgr-0.2.0/tests/test_agents_cli.py +245 -0
  39. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_apply_check_cli.py +73 -0
  40. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_codex_cli.py +83 -0
  41. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_packages_cli.py +164 -0
  42. codexmgr-0.2.0/tests/test_rules_cli.py +264 -0
  43. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_status_doctor_cli.py +146 -1
  44. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_tui_app.py +75 -14
  45. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_tui_state.py +147 -1
  46. {codexmgr-0.1.3 → codexmgr-0.2.0}/uv.lock +1 -1
  47. codexmgr-0.1.3/src/codexmgr/tui/mutations.py +0 -97
  48. {codexmgr-0.1.3 → codexmgr-0.2.0}/.github/actions/install_package/action.yml +0 -0
  49. {codexmgr-0.1.3 → codexmgr-0.2.0}/.github/workflows/py_test.yml +0 -0
  50. {codexmgr-0.1.3 → codexmgr-0.2.0}/.github/workflows/version_publish_main.yml +0 -0
  51. {codexmgr-0.1.3 → codexmgr-0.2.0}/.gitignore +0 -0
  52. {codexmgr-0.1.3 → codexmgr-0.2.0}/pytest.toml +0 -0
  53. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/agents/__init__.py +0 -0
  54. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/agents/file.py +0 -0
  55. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/agents/manager.py +0 -0
  56. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/agents/renderer.py +0 -0
  57. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/__init__.py +0 -0
  58. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/codex.py +0 -0
  59. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/config_mutations.py +0 -0
  60. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/commands/navigation.py +0 -0
  61. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/core/__init__.py +0 -0
  62. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/core/errors.py +0 -0
  63. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/core/options.py +0 -0
  64. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/core/paths.py +0 -0
  65. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/core/toml_io.py +0 -0
  66. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/__init__.py +0 -0
  67. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/config.py +0 -0
  68. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/copies.py +0 -0
  69. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/listing.py +0 -0
  70. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/merge.py +0 -0
  71. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/resolution.py +0 -0
  72. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/hooks/sources.py +0 -0
  73. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/interface/__init__.py +0 -0
  74. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/interface/parsers/__init__.py +0 -0
  75. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/interface/parsers/mcp.py +0 -0
  76. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/__init__.py +0 -0
  77. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/apply.py +0 -0
  78. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/cli.py +0 -0
  79. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/config.py +0 -0
  80. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/discovery.py +0 -0
  81. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/fields.py +0 -0
  82. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/mcp/tables.py +0 -0
  83. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/__init__.py +0 -0
  84. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/cli.py +0 -0
  85. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/listing.py +0 -0
  86. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/packages/sources.py +0 -0
  87. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/__init__.py +0 -0
  88. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/config.py +0 -0
  89. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/snapshot.py +0 -0
  90. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/project/sync.py +0 -0
  91. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/py.typed +0 -0
  92. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/__init__.py +0 -0
  93. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/config.py +0 -0
  94. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/copies.py +0 -0
  95. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/listing.py +0 -0
  96. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/resolution.py +0 -0
  97. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/skills/sources.py +0 -0
  98. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/__init__.py +0 -0
  99. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/cli.py +0 -0
  100. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/diff.py +0 -0
  101. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/models.py +0 -0
  102. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/package_refs.py +0 -0
  103. {codexmgr-0.1.3 → codexmgr-0.2.0}/src/codexmgr/tui/package_selection.py +0 -0
  104. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/conftest.py +0 -0
  105. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_agents_file.py +0 -0
  106. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_agentsmd_list_cli.py +0 -0
  107. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_agentsmd_tools_cli.py +0 -0
  108. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_cd_cli.py +0 -0
  109. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_cli.py +0 -0
  110. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_empty_skill_config_cli.py +0 -0
  111. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_home_resolution_cli.py +0 -0
  112. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_hooks_cli.py +0 -0
  113. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_mcp_apply_cli.py +0 -0
  114. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_mcp_cli.py +0 -0
  115. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_package_metadata.py +0 -0
  116. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_paths.py +0 -0
  117. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_python_compatibility.py +0 -0
  118. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_renderer.py +0 -0
  119. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_skill_copies_cli.py +0 -0
  120. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_skill_home_sources_cli.py +0 -0
  121. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_skill_list_cli.py +0 -0
  122. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_skills_cli.py +0 -0
  123. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_sync_cli.py +0 -0
  124. {codexmgr-0.1.3 → codexmgr-0.2.0}/tests/test_toml_io.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codexmgr
3
- Version: 0.1.3
3
+ Version: 0.2.0
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
@@ -34,7 +34,9 @@ The tool is intentionally narrow:
34
34
  - compose reusable AGENTS.md instruction fragments
35
35
  - enable or disable Codex skills per project
36
36
  - enable or disable reusable Codex hook bundles per project
37
- - enable or disable packaged sets of AGENTS.md, skill, and hook settings
37
+ - enable or disable project custom agents from reusable TOML files
38
+ - enable or disable reusable rule files copied into project-local `.rules/`
39
+ - enable or disable packaged sets of AGENTS.md, agent, skill, hook, and rule settings
38
40
  - enable, disable, inspect, and update safe project-local MCP overrides
39
41
  - use an interactive terminal UI for common project management tasks
40
42
  - write reproducible lock data for the resolved project configuration
@@ -100,14 +102,16 @@ This updates `.codex/codexmgr.toml`, runs `apply`, writes
100
102
 
101
103
  - `.codex/codexmgr.toml`: source configuration edited by CLI commands or by
102
104
  hand
103
- - `.codex/codexmgr.lock`: resolved template, skill, hook, and MCP state written by
104
- `apply`
105
+ - `.codex/codexmgr.lock`: resolved template, agent, skill, hook, and MCP state
106
+ written by `apply`
105
107
  - `.codex/config.toml`: Codex config updated with `[[skills.config]]` entries
106
108
  and `[mcp_servers.<id>]` overrides
107
109
  - `.codex/hooks.json`: Codex hook config updated with enabled reusable hook
108
110
  bundles while preserving unmanaged local hooks
109
111
  - `.codex/hooks/<name>`: project-local copies of enabled hook bundle support
110
112
  files
113
+ - `.codex/agents/<name>.toml`: project-local copies of enabled custom agents
114
+ - `.rules/<path>`: project-local copies of enabled reusable rule files
111
115
  - `AGENTS.md`: project instructions, with only the managed block replaced
112
116
 
113
117
  The managed AGENTS.md block is:
@@ -122,8 +126,8 @@ Manual content outside this block is preserved. If the block is missing,
122
126
 
123
127
  ## Project Configuration
124
128
 
125
- `.codex/codexmgr.toml` supports AGENTS.md templates, skill state, hook state, and MCP
126
- overrides:
129
+ `.codex/codexmgr.toml` supports AGENTS.md templates, custom-agent state, skill
130
+ state, hook state, and MCP overrides:
127
131
 
128
132
  ```toml
129
133
  [agents_md]
@@ -133,10 +137,18 @@ src = ["coding", "/absolute/or/project-relative/template.toml"]
133
137
  enabled = ["review-helper"]
134
138
  disabled = ["experimental-skill", "skills/local-disabled"]
135
139
 
140
+ [agents]
141
+ enabled = ["rule-retriever"]
142
+ disabled = ["experimental-agent"]
143
+
136
144
  [hooks]
137
145
  enabled = ["repo-rules"]
138
146
  disabled = ["experimental-hook"]
139
147
 
148
+ [rules]
149
+ enabled = ["react/", "python/testing.md"]
150
+ disabled = ["react/materials/"]
151
+
140
152
  [mcp.servers.browsermcp]
141
153
  enabled = true
142
154
  bearer_token_env_var = "BROWSERMCP_TOKEN"
@@ -155,33 +167,49 @@ Path-like skill values resolve to either a `SKILL.md` file or a directory
155
167
  containing `SKILL.md`. Missing skills are written as name-based entries so Codex
156
168
  can resolve them later.
157
169
 
170
+ Named custom agents resolve from `$CODEXMGR_HOME/agents/<name>.toml`. Enabled
171
+ agents are copied into `.codex/agents/<name>.toml` on every apply. Disabled
172
+ agents remove their managed copy only when the lock records the file as
173
+ codexmgr-managed.
174
+
158
175
  Named hooks resolve from `$CODEXMGR_HOME/hooks/<name>/hooks.json`. Enabled hook
159
176
  bundles are merged into `.codex/hooks.json` on every apply with
160
177
  `codexmanager_meta` added to each managed handler. Existing unmanaged hooks are
161
178
  preserved. Bundle files other than the root `hooks.json` are copied into
162
179
  `.codex/hooks/<name>`.
163
180
 
181
+ Rule refs resolve under `$CODEXMGR_HOME/rules/` and are POSIX-style relative
182
+ paths. Folder refs are stored with a trailing slash and copy all regular files
183
+ recursively into `.rules/` while preserving relative paths. File refs copy one
184
+ file. Extensionless refs prefer an existing `<ref>.md`. Enabled refs expand
185
+ first, then disabled file or folder refs remove entries from that candidate set.
186
+ First-time applies refuse to overwrite unmanaged `.rules/...` files.
187
+
164
188
  Packaged configurations resolve from
165
189
  `$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:
190
+ document that can contain root `agentsmd`, `agents`, `hooks`, `skills`, and `rules`
191
+ string lists plus optional profile tables:
168
192
 
169
193
  ```toml
170
194
  agentsmd = []
195
+ agents = ["rule-retriever"]
171
196
  hooks = ["repo-rules"]
172
197
  skills = ["repo-rule-manager"]
198
+ rules = ["react/"]
173
199
 
174
200
  [profiles.strict]
175
201
  agentsmd = ["strict-coding"]
202
+ agents = ["strict-agent"]
176
203
  hooks = ["strict-rules"]
177
204
  skills = ["strict-review"]
205
+ rules = ["python/testing.md"]
178
206
  ```
179
207
 
180
208
  `codexmgr package enable <name>` validates package AGENTS.md and hook
181
209
  references, then updates `.codex/codexmgr.toml` as if the corresponding
182
210
  `agentsmd add`, `hooks enable`, and `skill enable` commands had been run.
183
211
  `codexmgr package disable <name>` removes package AGENTS.md entries when
184
- present and disables the package skills and hooks.
212
+ present and disables the package skills, hooks, agents, and rules.
185
213
 
186
214
  Package profiles are merged with the root package entries:
187
215
 
@@ -205,10 +233,13 @@ unless `--no-sync` was explicitly requested.
205
233
  ## Interactive TUI
206
234
 
207
235
  `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.
236
+ configuration. It shows AGENTS.md templates, skills, hooks, custom agents,
237
+ rules, packages, and MCP server enable overrides in selectable lists. Changes are
238
+ staged in memory while you navigate and toggle entries. Press `s` to save; the
239
+ save writes `.codex/codexmgr.toml` once and runs `apply` once unless
240
+ `--no-sync` was used.
241
+ For resources with explicit enable and disable lists, `space` cycles the
242
+ highlighted row through available, enabled, and disabled states.
212
243
  Package profiles appear as separate selectable rows under their package.
213
244
 
214
245
  ```bash
@@ -270,9 +301,15 @@ codexmgr init-template agentsmd <name>
270
301
  codexmgr skill list
271
302
  codexmgr skill enable [--no-sync] <name-or-skill-path> [...]
272
303
  codexmgr skill disable [--no-sync] <name-or-skill-path> [...]
304
+ codexmgr agents list
305
+ codexmgr agents enable [--no-sync] <agent-name> [...]
306
+ codexmgr agents disable [--no-sync] <agent-name> [...]
273
307
  codexmgr hooks list
274
308
  codexmgr hooks enable [--no-sync] <hook-name> [...]
275
309
  codexmgr hooks disable [--no-sync] <hook-name> [...]
310
+ codexmgr rules list
311
+ codexmgr rules enable [--no-sync] <rule-ref> [...]
312
+ codexmgr rules disable [--no-sync] <rule-ref> [...]
276
313
  codexmgr package list
277
314
  codexmgr package enable [--no-sync] <package-name> [...] [--profile <name> [...]]
278
315
  codexmgr package disable [--no-sync] <package-name> [...] [--profile <name> [...]]
@@ -294,8 +331,10 @@ codexmgr codex <args...>
294
331
 
295
332
  `apply` reads `.codex/codexmgr.toml`, resolves configured sources, writes
296
333
  `.codex/codexmgr.lock`, updates `.codex/config.toml` skill entries when a
297
- `[skills]` table is configured, writes `.codex/hooks.json` when `[hooks]` is
298
- configured, writes local `[mcp_servers.<id>]` overrides when `[mcp]` is
334
+ `[skills]` table is configured, copies `.codex/agents/<name>.toml` files when
335
+ `[agents]` is configured, writes `.codex/hooks.json` when `[hooks]` is
336
+ configured, copies `.rules/<path>` files when `[rules]` is configured, writes
337
+ local `[mcp_servers.<id>]` overrides when `[mcp]` is
299
338
  configured, and refreshes the generated `AGENTS.md` block when `[agents_md]` is
300
339
  configured.
301
340
 
@@ -309,11 +348,11 @@ the directory in a file explorer, and `codexmgr cd --terminal` to open a new
309
348
  terminal there.
310
349
 
311
350
  `doctor` checks project setup, home environment variables, project TOML syntax,
312
- referenced snippets, enabled skills, enabled hook bundles, and stale generated
313
- files.
351
+ referenced snippets, enabled skills, enabled custom agents, enabled hook
352
+ bundles, enabled rules, and stale generated files.
314
353
 
315
- `status` prints the resolved homes, configured snippets, skills, hooks, and
316
- whether generated files are in sync.
354
+ `status` prints the resolved homes, configured snippets, skills, custom agents,
355
+ hooks, rules, and whether generated files are in sync.
317
356
 
318
357
  `codexmgr codex` can run with a just-in-time package/profile overlay without
319
358
  changing `.codex/codexmgr.toml`. Put Codex arguments after `--` when using this
@@ -413,13 +452,21 @@ marks configured hook bundles as enabled, disabled, or missing.
413
452
  config. `hooks enable` and `hooks disable` keep enabled and disabled lists
414
453
  mutually exclusive. Repeated commands keep one entry.
415
454
 
455
+ `rules list` prints available `$CODEXMGR_HOME/rules/**` files and folders and
456
+ marks configured rule refs as enabled, disabled, or missing.
457
+
458
+ `rules enable` validates and canonicalizes refs before writing config.
459
+ `rules disable` canonicalizes existing refs and permits missing exclusions.
460
+ Enabled and disabled lists are exact-ref mutually exclusive, so parent enables
461
+ and child disables can intentionally coexist.
462
+
416
463
  `package list` prints available `$CODEXMGR_HOME/packages/*/config.toml`
417
464
  entries in sorted order.
418
465
 
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.
466
+ `package enable` and `package disable` proxy to existing AGENTS.md, custom-agent,
467
+ skill, hook, and rule project-config mutations. Package state is not tracked
468
+ separately; the resulting `[agents_md]`, `[agents]`, `[skills]`, `[hooks]`, and `[rules]`
469
+ tables remain the source of truth.
423
470
 
424
471
  `codex` forwards arguments to the real `codex` command. Values from
425
472
  `.codex/config.toml` are flattened into `-c key=value` overrides. User-provided
@@ -11,7 +11,9 @@ The tool is intentionally narrow:
11
11
  - compose reusable AGENTS.md instruction fragments
12
12
  - enable or disable Codex skills per project
13
13
  - enable or disable reusable Codex hook bundles per project
14
- - enable or disable packaged sets of AGENTS.md, skill, and hook settings
14
+ - enable or disable project custom agents from reusable TOML files
15
+ - enable or disable reusable rule files copied into project-local `.rules/`
16
+ - enable or disable packaged sets of AGENTS.md, agent, skill, hook, and rule settings
15
17
  - enable, disable, inspect, and update safe project-local MCP overrides
16
18
  - use an interactive terminal UI for common project management tasks
17
19
  - write reproducible lock data for the resolved project configuration
@@ -77,14 +79,16 @@ This updates `.codex/codexmgr.toml`, runs `apply`, writes
77
79
 
78
80
  - `.codex/codexmgr.toml`: source configuration edited by CLI commands or by
79
81
  hand
80
- - `.codex/codexmgr.lock`: resolved template, skill, hook, and MCP state written by
81
- `apply`
82
+ - `.codex/codexmgr.lock`: resolved template, agent, skill, hook, and MCP state
83
+ written by `apply`
82
84
  - `.codex/config.toml`: Codex config updated with `[[skills.config]]` entries
83
85
  and `[mcp_servers.<id>]` overrides
84
86
  - `.codex/hooks.json`: Codex hook config updated with enabled reusable hook
85
87
  bundles while preserving unmanaged local hooks
86
88
  - `.codex/hooks/<name>`: project-local copies of enabled hook bundle support
87
89
  files
90
+ - `.codex/agents/<name>.toml`: project-local copies of enabled custom agents
91
+ - `.rules/<path>`: project-local copies of enabled reusable rule files
88
92
  - `AGENTS.md`: project instructions, with only the managed block replaced
89
93
 
90
94
  The managed AGENTS.md block is:
@@ -99,8 +103,8 @@ Manual content outside this block is preserved. If the block is missing,
99
103
 
100
104
  ## Project Configuration
101
105
 
102
- `.codex/codexmgr.toml` supports AGENTS.md templates, skill state, hook state, and MCP
103
- overrides:
106
+ `.codex/codexmgr.toml` supports AGENTS.md templates, custom-agent state, skill
107
+ state, hook state, and MCP overrides:
104
108
 
105
109
  ```toml
106
110
  [agents_md]
@@ -110,10 +114,18 @@ src = ["coding", "/absolute/or/project-relative/template.toml"]
110
114
  enabled = ["review-helper"]
111
115
  disabled = ["experimental-skill", "skills/local-disabled"]
112
116
 
117
+ [agents]
118
+ enabled = ["rule-retriever"]
119
+ disabled = ["experimental-agent"]
120
+
113
121
  [hooks]
114
122
  enabled = ["repo-rules"]
115
123
  disabled = ["experimental-hook"]
116
124
 
125
+ [rules]
126
+ enabled = ["react/", "python/testing.md"]
127
+ disabled = ["react/materials/"]
128
+
117
129
  [mcp.servers.browsermcp]
118
130
  enabled = true
119
131
  bearer_token_env_var = "BROWSERMCP_TOKEN"
@@ -132,33 +144,49 @@ Path-like skill values resolve to either a `SKILL.md` file or a directory
132
144
  containing `SKILL.md`. Missing skills are written as name-based entries so Codex
133
145
  can resolve them later.
134
146
 
147
+ Named custom agents resolve from `$CODEXMGR_HOME/agents/<name>.toml`. Enabled
148
+ agents are copied into `.codex/agents/<name>.toml` on every apply. Disabled
149
+ agents remove their managed copy only when the lock records the file as
150
+ codexmgr-managed.
151
+
135
152
  Named hooks resolve from `$CODEXMGR_HOME/hooks/<name>/hooks.json`. Enabled hook
136
153
  bundles are merged into `.codex/hooks.json` on every apply with
137
154
  `codexmanager_meta` added to each managed handler. Existing unmanaged hooks are
138
155
  preserved. Bundle files other than the root `hooks.json` are copied into
139
156
  `.codex/hooks/<name>`.
140
157
 
158
+ Rule refs resolve under `$CODEXMGR_HOME/rules/` and are POSIX-style relative
159
+ paths. Folder refs are stored with a trailing slash and copy all regular files
160
+ recursively into `.rules/` while preserving relative paths. File refs copy one
161
+ file. Extensionless refs prefer an existing `<ref>.md`. Enabled refs expand
162
+ first, then disabled file or folder refs remove entries from that candidate set.
163
+ First-time applies refuse to overwrite unmanaged `.rules/...` files.
164
+
141
165
  Packaged configurations resolve from
142
166
  `$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:
167
+ document that can contain root `agentsmd`, `agents`, `hooks`, `skills`, and `rules`
168
+ string lists plus optional profile tables:
145
169
 
146
170
  ```toml
147
171
  agentsmd = []
172
+ agents = ["rule-retriever"]
148
173
  hooks = ["repo-rules"]
149
174
  skills = ["repo-rule-manager"]
175
+ rules = ["react/"]
150
176
 
151
177
  [profiles.strict]
152
178
  agentsmd = ["strict-coding"]
179
+ agents = ["strict-agent"]
153
180
  hooks = ["strict-rules"]
154
181
  skills = ["strict-review"]
182
+ rules = ["python/testing.md"]
155
183
  ```
156
184
 
157
185
  `codexmgr package enable <name>` validates package AGENTS.md and hook
158
186
  references, then updates `.codex/codexmgr.toml` as if the corresponding
159
187
  `agentsmd add`, `hooks enable`, and `skill enable` commands had been run.
160
188
  `codexmgr package disable <name>` removes package AGENTS.md entries when
161
- present and disables the package skills and hooks.
189
+ present and disables the package skills, hooks, agents, and rules.
162
190
 
163
191
  Package profiles are merged with the root package entries:
164
192
 
@@ -182,10 +210,13 @@ unless `--no-sync` was explicitly requested.
182
210
  ## Interactive TUI
183
211
 
184
212
  `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.
213
+ configuration. It shows AGENTS.md templates, skills, hooks, custom agents,
214
+ rules, packages, and MCP server enable overrides in selectable lists. Changes are
215
+ staged in memory while you navigate and toggle entries. Press `s` to save; the
216
+ save writes `.codex/codexmgr.toml` once and runs `apply` once unless
217
+ `--no-sync` was used.
218
+ For resources with explicit enable and disable lists, `space` cycles the
219
+ highlighted row through available, enabled, and disabled states.
189
220
  Package profiles appear as separate selectable rows under their package.
190
221
 
191
222
  ```bash
@@ -247,9 +278,15 @@ codexmgr init-template agentsmd <name>
247
278
  codexmgr skill list
248
279
  codexmgr skill enable [--no-sync] <name-or-skill-path> [...]
249
280
  codexmgr skill disable [--no-sync] <name-or-skill-path> [...]
281
+ codexmgr agents list
282
+ codexmgr agents enable [--no-sync] <agent-name> [...]
283
+ codexmgr agents disable [--no-sync] <agent-name> [...]
250
284
  codexmgr hooks list
251
285
  codexmgr hooks enable [--no-sync] <hook-name> [...]
252
286
  codexmgr hooks disable [--no-sync] <hook-name> [...]
287
+ codexmgr rules list
288
+ codexmgr rules enable [--no-sync] <rule-ref> [...]
289
+ codexmgr rules disable [--no-sync] <rule-ref> [...]
253
290
  codexmgr package list
254
291
  codexmgr package enable [--no-sync] <package-name> [...] [--profile <name> [...]]
255
292
  codexmgr package disable [--no-sync] <package-name> [...] [--profile <name> [...]]
@@ -271,8 +308,10 @@ codexmgr codex <args...>
271
308
 
272
309
  `apply` reads `.codex/codexmgr.toml`, resolves configured sources, writes
273
310
  `.codex/codexmgr.lock`, updates `.codex/config.toml` skill entries when a
274
- `[skills]` table is configured, writes `.codex/hooks.json` when `[hooks]` is
275
- configured, writes local `[mcp_servers.<id>]` overrides when `[mcp]` is
311
+ `[skills]` table is configured, copies `.codex/agents/<name>.toml` files when
312
+ `[agents]` is configured, writes `.codex/hooks.json` when `[hooks]` is
313
+ configured, copies `.rules/<path>` files when `[rules]` is configured, writes
314
+ local `[mcp_servers.<id>]` overrides when `[mcp]` is
276
315
  configured, and refreshes the generated `AGENTS.md` block when `[agents_md]` is
277
316
  configured.
278
317
 
@@ -286,11 +325,11 @@ the directory in a file explorer, and `codexmgr cd --terminal` to open a new
286
325
  terminal there.
287
326
 
288
327
  `doctor` checks project setup, home environment variables, project TOML syntax,
289
- referenced snippets, enabled skills, enabled hook bundles, and stale generated
290
- files.
328
+ referenced snippets, enabled skills, enabled custom agents, enabled hook
329
+ bundles, enabled rules, and stale generated files.
291
330
 
292
- `status` prints the resolved homes, configured snippets, skills, hooks, and
293
- whether generated files are in sync.
331
+ `status` prints the resolved homes, configured snippets, skills, custom agents,
332
+ hooks, rules, and whether generated files are in sync.
294
333
 
295
334
  `codexmgr codex` can run with a just-in-time package/profile overlay without
296
335
  changing `.codex/codexmgr.toml`. Put Codex arguments after `--` when using this
@@ -390,13 +429,21 @@ marks configured hook bundles as enabled, disabled, or missing.
390
429
  config. `hooks enable` and `hooks disable` keep enabled and disabled lists
391
430
  mutually exclusive. Repeated commands keep one entry.
392
431
 
432
+ `rules list` prints available `$CODEXMGR_HOME/rules/**` files and folders and
433
+ marks configured rule refs as enabled, disabled, or missing.
434
+
435
+ `rules enable` validates and canonicalizes refs before writing config.
436
+ `rules disable` canonicalizes existing refs and permits missing exclusions.
437
+ Enabled and disabled lists are exact-ref mutually exclusive, so parent enables
438
+ and child disables can intentionally coexist.
439
+
393
440
  `package list` prints available `$CODEXMGR_HOME/packages/*/config.toml`
394
441
  entries in sorted order.
395
442
 
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.
443
+ `package enable` and `package disable` proxy to existing AGENTS.md, custom-agent,
444
+ skill, hook, and rule project-config mutations. Package state is not tracked
445
+ separately; the resulting `[agents_md]`, `[agents]`, `[skills]`, `[hooks]`, and `[rules]`
446
+ tables remain the source of truth.
400
447
 
401
448
  `codex` forwards arguments to the real `codex` command. Values from
402
449
  `.codex/config.toml` are flattened into `-c key=value` overrides. User-provided
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codexmgr"
3
- version = "0.1.3"
3
+ version = "0.2.0"
4
4
  description = "Manage project-local Codex configuration from reusable templates"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.1.3"
5
+ __version__ = "0.2.0"
@@ -82,7 +82,7 @@ def build_jit_project_state(
82
82
  codexmgr_home,
83
83
  request.profiles,
84
84
  )
85
- apply_package_entries_to_config(overlay, entries, enabled=True)
85
+ apply_package_entries_to_config(overlay, entries, codexmgr_home, enabled=True)
86
86
  return build_project_state_from_config(overlay, cwd, codex_home, codexmgr_home)
87
87
 
88
88
 
@@ -205,7 +205,26 @@ def _state_paths(state: ProjectBuild) -> list[Path]:
205
205
  *(generated_file.path for generated_file in state.files),
206
206
  *(skill_copy.target for skill_copy in state.skill_copies),
207
207
  *(hook_copy.target for hook_copy in state.hook_copies),
208
+ *(agent_copy.target for agent_copy in state.agent_copies),
209
+ *(_rule_root(rule_copy.target) for rule_copy in state.rule_copies),
208
210
  *state.obsolete_file_targets,
209
211
  *state.obsolete_skill_copy_targets,
210
212
  *state.obsolete_hook_copy_targets,
213
+ *state.obsolete_agent_copy_targets,
214
+ *(_rule_root(target) for target in state.obsolete_rule_copy_targets),
211
215
  ]
216
+
217
+
218
+ def _rule_root(path: Path) -> Path:
219
+ """Return the `.rules` ancestor for a rule file path.
220
+
221
+ Args:
222
+ path: Rule copy path or obsolete rule target.
223
+
224
+ Returns:
225
+ The nearest `.rules` ancestor, or the original path when absent.
226
+ """
227
+ for parent in [path, *path.parents]:
228
+ if parent.name == ".rules":
229
+ return parent
230
+ return path
@@ -7,9 +7,11 @@ from typing import TextIO
7
7
  from ..agents.manager import resolve_locked_agents_md
8
8
  from ..core.errors import CommandError
9
9
  from ..core.paths import project_codex_dir
10
+ from ..custom_agents.listing import configured_agent_lists, missing_enabled_agents
10
11
  from ..project.config import agents_md_sources, load_required_project_config
11
12
  from ..project.sync import generated_file_diffs
12
13
  from ..hooks.listing import configured_hook_lists, missing_enabled_hooks
14
+ from ..rules.listing import configured_rule_lists, missing_enabled_rules
13
15
  from ..skills.listing import configured_skill_lists, missing_enabled_skills
14
16
 
15
17
 
@@ -33,6 +35,8 @@ def run_status(
33
35
  config = load_required_project_config(cwd)
34
36
  enabled, disabled = configured_skill_lists(cwd)
35
37
  enabled_hooks, disabled_hooks = configured_hook_lists(cwd)
38
+ enabled_agents, disabled_agents = configured_agent_lists(cwd)
39
+ enabled_rules, disabled_rules = configured_rule_lists(cwd)
36
40
  diffs = generated_file_diffs(cwd, codex_home, codexmgr_home)
37
41
  lines = [
38
42
  f"Project: {cwd}",
@@ -43,6 +47,10 @@ def run_status(
43
47
  f"Disabled skills: {_format_values(disabled)}",
44
48
  f"Enabled hooks: {_format_values(enabled_hooks)}",
45
49
  f"Disabled hooks: {_format_values(disabled_hooks)}",
50
+ f"Enabled agents: {_format_values(enabled_agents)}",
51
+ f"Disabled agents: {_format_values(disabled_agents)}",
52
+ f"Enabled rules: {_format_values(enabled_rules)}",
53
+ f"Disabled rules: {_format_values(disabled_rules)}",
46
54
  f"Generated files: {_sync_state(diffs)}",
47
55
  ]
48
56
  lines.extend(f" {diff.relative_path}" for diff in diffs)
@@ -81,6 +89,8 @@ def run_doctor(
81
89
  _check_agents_sources(config, cwd, codexmgr_home, report)
82
90
  _check_missing_enabled_skills(cwd, codex_home, codexmgr_home, report)
83
91
  _check_missing_enabled_hooks(cwd, codexmgr_home, report)
92
+ _check_missing_enabled_agents(cwd, codexmgr_home, report)
93
+ _check_missing_enabled_rules(cwd, codexmgr_home, report)
84
94
  _check_generated_files(cwd, codex_home, codexmgr_home, report)
85
95
 
86
96
  has_errors = any(line.startswith("ERROR ") for line in report)
@@ -188,6 +198,44 @@ def _check_missing_enabled_hooks(
188
198
  report.append(f"ERROR Missing enabled hook: {hook}")
189
199
 
190
200
 
201
+ def _check_missing_enabled_agents(
202
+ cwd: Path,
203
+ codexmgr_home: Path,
204
+ report: list[str],
205
+ ) -> None:
206
+ """Check that enabled custom-agent references resolve.
207
+
208
+ Args:
209
+ cwd: Project directory whose configured custom agents should be checked.
210
+ codexmgr_home: codexmgr home used to resolve custom-agent sources.
211
+ report: Mutable diagnostic report receiving any error.
212
+
213
+ Returns:
214
+ None.
215
+ """
216
+ for agent in missing_enabled_agents(cwd, codexmgr_home):
217
+ report.append(f"ERROR Missing enabled agent: {agent}")
218
+
219
+
220
+ def _check_missing_enabled_rules(
221
+ cwd: Path,
222
+ codexmgr_home: Path,
223
+ report: list[str],
224
+ ) -> None:
225
+ """Check that enabled reusable rule references resolve.
226
+
227
+ Args:
228
+ cwd: Project directory whose configured rules should be checked.
229
+ codexmgr_home: codexmgr home used to resolve reusable rules.
230
+ report: Mutable diagnostic report receiving any error.
231
+
232
+ Returns:
233
+ None.
234
+ """
235
+ for rule in missing_enabled_rules(cwd, codexmgr_home):
236
+ report.append(f"ERROR Missing enabled rule: {rule}")
237
+
238
+
191
239
  def _check_generated_files(
192
240
  cwd: Path,
193
241
  codex_home: Path,
@@ -0,0 +1,115 @@
1
+ """CLI helpers for reusable rule management commands."""
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+ from typing import TextIO
6
+
7
+ from ..core.paths import config_path
8
+ from ..core.toml_io import load_optional_toml_file, write_toml_file
9
+ from ..project.apply import apply_project_config
10
+ from ..project.config import require_codex_dir
11
+ from ..rules.config import set_rule_state_in_config
12
+ from ..rules.listing import rule_list_lines
13
+
14
+
15
+ def run_rules_command(
16
+ args: argparse.Namespace,
17
+ cwd: Path,
18
+ codex_home: Path,
19
+ codexmgr_home: Path,
20
+ stdout: TextIO,
21
+ ) -> int:
22
+ """Run a parsed rules command.
23
+
24
+ Args:
25
+ args: Parsed rules command namespace.
26
+ cwd: Project directory for project-local operations.
27
+ codex_home: Codex home used by apply.
28
+ codexmgr_home: Codexmgr home containing source rules.
29
+ stdout: Stream for command output.
30
+
31
+ Returns:
32
+ A process-style exit code.
33
+ """
34
+ if args.rules_command == "list":
35
+ _write_optional_lines(stdout, rule_list_lines(cwd, codexmgr_home))
36
+ return 0
37
+ enabled = args.rules_command == "enable"
38
+ rules = _set_rule_many(args.rules, cwd, codexmgr_home, enabled=enabled)
39
+ verb = "Enabled" if enabled else "Disabled"
40
+ return _finish_config_change(
41
+ [f"{verb} {rule}" for rule in rules],
42
+ args.no_sync,
43
+ cwd,
44
+ codex_home,
45
+ codexmgr_home,
46
+ stdout,
47
+ )
48
+
49
+
50
+ def _set_rule_many(
51
+ rules: list[str],
52
+ cwd: Path,
53
+ codexmgr_home: Path,
54
+ *,
55
+ enabled: bool,
56
+ ) -> list[str]:
57
+ """Set multiple rule states with one config write.
58
+
59
+ Args:
60
+ rules: Rule refs to update.
61
+ cwd: Project directory whose codexmgr.toml should be updated.
62
+ codexmgr_home: Codexmgr home containing source rules.
63
+ enabled: Desired rule state.
64
+
65
+ Returns:
66
+ Canonical rule refs that were updated.
67
+ """
68
+ require_codex_dir(cwd)
69
+ config = load_optional_toml_file(config_path(cwd))
70
+ updated = [
71
+ set_rule_state_in_config(config, rule, codexmgr_home, enabled=enabled)
72
+ for rule in rules
73
+ ]
74
+ write_toml_file(config_path(cwd), config)
75
+ return updated
76
+
77
+
78
+ def _finish_config_change(
79
+ messages: list[str],
80
+ no_sync: bool,
81
+ cwd: Path,
82
+ codex_home: Path,
83
+ codexmgr_home: Path,
84
+ stdout: TextIO,
85
+ ) -> int:
86
+ """Apply generated files after a rules mutation unless opted out.
87
+
88
+ Args:
89
+ messages: Command-specific success messages.
90
+ no_sync: Whether to skip automatic apply.
91
+ cwd: Project directory whose configuration changed.
92
+ codex_home: Codex home for apply.
93
+ codexmgr_home: Codexmgr home for apply.
94
+ stdout: Stream for command output.
95
+
96
+ Returns:
97
+ Zero when mutation and optional apply succeed.
98
+ """
99
+ output = list(messages)
100
+ if not no_sync:
101
+ apply_project_config(cwd, codex_home, codexmgr_home)
102
+ output.append("Applied project Codex configuration")
103
+ stdout.write("\n".join(output) + "\n")
104
+ return 0
105
+
106
+
107
+ def _write_optional_lines(stdout: TextIO, lines: list[str]) -> None:
108
+ """Write lines only when present.
109
+
110
+ Args:
111
+ stdout: Stream for command output.
112
+ lines: Lines to write.
113
+ """
114
+ if lines:
115
+ stdout.write("\n".join(lines) + "\n")
@@ -0,0 +1 @@
1
+ """Manage project-local Codex custom-agent files."""