codexmgr 0.2.1__tar.gz → 0.3.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 (135) hide show
  1. {codexmgr-0.2.1 → codexmgr-0.3.0}/PKG-INFO +69 -37
  2. {codexmgr-0.2.1 → codexmgr-0.3.0}/README.md +67 -36
  3. {codexmgr-0.2.1 → codexmgr-0.3.0}/pyproject.toml +4 -1
  4. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/__init__.py +1 -1
  5. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/interface/parsers/mcp.py +8 -8
  6. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/mcp/__init__.py +38 -0
  7. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/mcp/apply.py +16 -9
  8. codexmgr-0.3.0/src/codexmgr/mcp/cli.py +242 -0
  9. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/mcp/fields.py +9 -20
  10. codexmgr-0.3.0/src/codexmgr/mcp/project.py +181 -0
  11. codexmgr-0.3.0/src/codexmgr/mcp/resolution.py +112 -0
  12. codexmgr-0.3.0/src/codexmgr/mcp/sources.py +186 -0
  13. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/project/apply.py +31 -137
  14. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/project/generated.py +10 -6
  15. codexmgr-0.3.0/src/codexmgr/project/resolution.py +180 -0
  16. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/rules/listing.py +21 -13
  17. codexmgr-0.3.0/src/codexmgr/rules/tree.py +206 -0
  18. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/app.py +79 -90
  19. codexmgr-0.3.0/src/codexmgr/tui/focus.py +182 -0
  20. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/items.py +1 -57
  21. codexmgr-0.3.0/src/codexmgr/tui/mcp_items.py +50 -0
  22. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/mutations.py +14 -0
  23. codexmgr-0.3.0/src/codexmgr/tui/panels.py +113 -0
  24. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/rendering.py +5 -0
  25. codexmgr-0.3.0/src/codexmgr/tui/rule_items.py +56 -0
  26. codexmgr-0.3.0/src/codexmgr/tui/rule_tree.py +141 -0
  27. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/sections.py +1 -1
  28. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/state.py +17 -14
  29. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_mcp_apply_cli.py +81 -6
  30. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_mcp_cli.py +190 -96
  31. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_package_metadata.py +8 -0
  32. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_rules_cli.py +59 -3
  33. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_tui_app.py +125 -0
  34. codexmgr-0.3.0/tests/test_tui_selection_focus.py +142 -0
  35. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_tui_state.py +44 -13
  36. {codexmgr-0.2.1 → codexmgr-0.3.0}/uv.lock +1 -1
  37. codexmgr-0.2.1/src/codexmgr/mcp/cli.py +0 -197
  38. codexmgr-0.2.1/src/codexmgr/tui/rule_items.py +0 -58
  39. {codexmgr-0.2.1 → codexmgr-0.3.0}/.github/actions/install_package/action.yml +0 -0
  40. {codexmgr-0.2.1 → codexmgr-0.3.0}/.github/workflows/py_test.yml +0 -0
  41. {codexmgr-0.2.1 → codexmgr-0.3.0}/.github/workflows/version_publish_main.yml +0 -0
  42. {codexmgr-0.2.1 → codexmgr-0.3.0}/.gitignore +0 -0
  43. {codexmgr-0.2.1 → codexmgr-0.3.0}/pytest.toml +0 -0
  44. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/agents/__init__.py +0 -0
  45. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/agents/file.py +0 -0
  46. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/agents/manager.py +0 -0
  47. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/agents/renderer.py +0 -0
  48. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/commands/__init__.py +0 -0
  49. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/commands/codex.py +0 -0
  50. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/commands/codex_jit.py +0 -0
  51. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/commands/config_mutations.py +0 -0
  52. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/commands/health.py +0 -0
  53. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/commands/navigation.py +0 -0
  54. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/commands/rules.py +0 -0
  55. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/core/__init__.py +0 -0
  56. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/core/errors.py +0 -0
  57. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/core/options.py +0 -0
  58. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/core/paths.py +0 -0
  59. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/core/toml_io.py +0 -0
  60. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/custom_agents/__init__.py +0 -0
  61. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/custom_agents/cli.py +0 -0
  62. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/custom_agents/config.py +0 -0
  63. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/custom_agents/copies.py +0 -0
  64. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/custom_agents/listing.py +0 -0
  65. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/custom_agents/resolution.py +0 -0
  66. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/custom_agents/sources.py +0 -0
  67. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/hooks/__init__.py +0 -0
  68. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/hooks/config.py +0 -0
  69. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/hooks/copies.py +0 -0
  70. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/hooks/listing.py +0 -0
  71. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/hooks/merge.py +0 -0
  72. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/hooks/resolution.py +0 -0
  73. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/hooks/sources.py +0 -0
  74. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/interface/__init__.py +0 -0
  75. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/interface/cli.py +0 -0
  76. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/interface/parser.py +0 -0
  77. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/interface/parsers/__init__.py +0 -0
  78. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/interface/parsers/agents.py +0 -0
  79. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/mcp/config.py +0 -0
  80. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/mcp/discovery.py +0 -0
  81. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/mcp/tables.py +0 -0
  82. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/packages/__init__.py +0 -0
  83. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/packages/cli.py +0 -0
  84. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/packages/config.py +0 -0
  85. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/packages/listing.py +0 -0
  86. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/packages/mutation.py +0 -0
  87. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/packages/sources.py +0 -0
  88. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/project/__init__.py +0 -0
  89. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/project/config.py +0 -0
  90. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/project/snapshot.py +0 -0
  91. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/project/state.py +0 -0
  92. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/project/sync.py +0 -0
  93. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/py.typed +0 -0
  94. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/rules/__init__.py +0 -0
  95. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/rules/config.py +0 -0
  96. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/rules/copies.py +0 -0
  97. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/rules/resolution.py +0 -0
  98. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/rules/sources.py +0 -0
  99. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/skills/__init__.py +0 -0
  100. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/skills/config.py +0 -0
  101. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/skills/copies.py +0 -0
  102. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/skills/listing.py +0 -0
  103. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/skills/resolution.py +0 -0
  104. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/skills/sources.py +0 -0
  105. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/__init__.py +0 -0
  106. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/cli.py +0 -0
  107. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/diff.py +0 -0
  108. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/models.py +0 -0
  109. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/package_refs.py +0 -0
  110. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/package_selection.py +0 -0
  111. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/package_state.py +0 -0
  112. {codexmgr-0.2.1 → codexmgr-0.3.0}/src/codexmgr/tui/staged_packages.py +0 -0
  113. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/conftest.py +0 -0
  114. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_agents_cli.py +0 -0
  115. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_agents_file.py +0 -0
  116. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_agentsmd_list_cli.py +0 -0
  117. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_agentsmd_tools_cli.py +0 -0
  118. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_apply_check_cli.py +0 -0
  119. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_cd_cli.py +0 -0
  120. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_cli.py +0 -0
  121. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_codex_cli.py +0 -0
  122. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_empty_skill_config_cli.py +0 -0
  123. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_home_resolution_cli.py +0 -0
  124. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_hooks_cli.py +0 -0
  125. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_packages_cli.py +0 -0
  126. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_paths.py +0 -0
  127. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_python_compatibility.py +0 -0
  128. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_renderer.py +0 -0
  129. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_skill_copies_cli.py +0 -0
  130. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_skill_home_sources_cli.py +0 -0
  131. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_skill_list_cli.py +0 -0
  132. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_skills_cli.py +0 -0
  133. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_status_doctor_cli.py +0 -0
  134. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_sync_cli.py +0 -0
  135. {codexmgr-0.2.1 → codexmgr-0.3.0}/tests/test_toml_io.py +0 -0
@@ -1,7 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codexmgr
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Manage project-local Codex configuration from reusable templates
5
+ Project-URL: Repository, https://github.com/JulianKimmig/codexmgr/
5
6
  Keywords: agents,cli,codex,configuration,skills
6
7
  Classifier: Development Status :: 4 - Beta
7
8
  Classifier: Environment :: Console
@@ -24,9 +25,9 @@ Description-Content-Type: text/markdown
24
25
  # codexmgr
25
26
 
26
27
  `codexmgr` manages reusable Codex project setup. Keep shared `AGENTS.md`
27
- snippets, skills, hooks, custom agents, rule files, packages, and safe MCP
28
- overrides in one manager home, then sync the selected pieces into each project
29
- from `.codex/codexmgr.toml`.
28
+ snippets, skills, hooks, custom agents, rule files, packages, and reusable MCP
29
+ source files in one manager home, then sync the selected pieces into each
30
+ project from `.codex/codexmgr.toml`.
30
31
 
31
32
  The tool is for people who use Codex in several repositories and do not want to
32
33
  copy the same agent instructions by hand. When a shared rule changes, update it
@@ -37,7 +38,7 @@ Use `codexmgr` when a project should:
37
38
  - build `AGENTS.md` from reusable instruction snippets
38
39
  - share skills, hooks, custom agents, and rule files across repositories
39
40
  - enable packaged Codex setups made from those reusable pieces
40
- - keep project MCP overrides out of the user-level Codex config
41
+ - keep reusable MCP server definitions out of the user-level Codex config
41
42
  - check whether generated Codex files match the project config
42
43
  - run `codex` with project `.codex/config.toml` values passed as `-c` overrides
43
44
 
@@ -148,7 +149,7 @@ file for you, and you can also edit it by hand when that is clearer.
148
149
  - `.codex/codexmgr.lock`: resolved AGENTS.md, agent, skill, hook, rule, and MCP
149
150
  state
150
151
  - `.codex/config.toml`: project-local Codex config, including generated
151
- `[[skills.config]]` entries and `[mcp_servers.<id>]` overrides
152
+ `[[skills.config]]` entries and `[mcp_servers.<id>]` server definitions
152
153
  - `.codex/hooks.json`: generated hook config for enabled reusable hook bundles
153
154
  - `.codex/hooks/<name>`: copied support files for enabled hook bundles
154
155
  - `.codex/agents/<name>.toml`: copied custom-agent definitions
@@ -170,7 +171,7 @@ Manual content outside this block is preserved. If the block is missing,
170
171
 
171
172
  `.codex/codexmgr.toml` can opt into each resource type independently. A minimal
172
173
  file may only contain `[agents_md]`; larger projects can add skills, custom
173
- agents, hooks, reusable rules, and MCP overrides as needed. Package commands
174
+ agents, hooks, reusable rules, and MCP sources or overlays as needed. Package commands
174
175
  write those same tables rather than a separate package table.
175
176
 
176
177
  ```toml
@@ -188,6 +189,8 @@ disabled = ["experimental-hook"]
188
189
  [rules]
189
190
  enabled = ["react/", "python/testing.md"]
190
191
  disabled = ["react/materials/"]
192
+ [mcp]
193
+ enabled = ["browsermcp"]
191
194
  [mcp.servers.browsermcp]
192
195
  enabled = true
193
196
  bearer_token_env_var = "BROWSERMCP_TOKEN"
@@ -232,6 +235,9 @@ Rule refs resolve under `$CODEXMGR_HOME/rules/` and use POSIX-style relative
232
235
  paths. Folder refs have a trailing slash and copy regular files recursively into
233
236
  `.rules/` while preserving relative paths.
234
237
 
238
+ Rule listings are grouped by folder. `codexmgr rules list` prints an indented
239
+ tree, while the TUI Rules screen shows the same refs in a collapsible tree.
240
+
235
241
  File rule refs copy one file. Extensionless refs prefer an existing `<ref>.md`.
236
242
  Enabled refs expand first, then disabled file or folder refs remove entries from
237
243
  that candidate set.
@@ -292,7 +298,8 @@ These commands run `apply` automatically unless `--no-sync` is passed.
292
298
 
293
299
  `codexmgr tui` opens a Textual-based terminal UI for project-local
294
300
  configuration. It shows `AGENTS.md` snippets, skills, hooks, custom agents,
295
- rules, packages, and MCP server enable overrides in selectable lists.
301
+ packages, and reusable MCP sources in selectable lists. Rules are shown
302
+ in a collapsible folder tree.
296
303
 
297
304
  Changes are staged in memory while you navigate. Press `s` to save; the save
298
305
  writes `.codex/codexmgr.toml` once and runs `apply` once unless `--no-sync` was
@@ -300,7 +307,9 @@ used.
300
307
 
301
308
  For resources with explicit enable and disable lists, `space` cycles the
302
309
  highlighted row through available, enabled, and disabled states. Package
303
- profiles appear as separate selectable rows under their package.
310
+ profiles appear as separate selectable rows under their package. In the Rules
311
+ tree, cycling a file or folder node updates the full canonical rule ref behind
312
+ that basename label.
304
313
 
305
314
  ```bash
306
315
  codexmgr tui
@@ -312,9 +321,10 @@ The dashboard shows generated-file sync state. By default it lists stale
312
321
  generated paths; with `--show-diff`, it shows unified diffs for the staged
313
322
  configuration.
314
323
 
315
- MCP editing in the TUI is intentionally limited to the project-local `enabled`
316
- override. Advanced MCP fields remain available through the `codexmgr mcp ...`
317
- commands.
324
+ MCP editing in the TUI is intentionally limited to loading and unloading
325
+ reusable `$CODEXMGR_HOME/mcp/*.toml` sources. Advanced per-server overlay fields
326
+ remain available through the `codexmgr mcp ...` commands or direct
327
+ `.codex/codexmgr.toml` edits.
318
328
 
319
329
  ## Template Format
320
330
 
@@ -421,8 +431,9 @@ codexmgr rules enable [--no-sync] <rule-ref> [...]
421
431
  codexmgr rules disable [--no-sync] <rule-ref> [...]
422
432
  ```
423
433
 
424
- `skill list`, `agents list`, `hooks list`, and `rules list` print available
425
- resources and mark configured entries as enabled, disabled, or missing.
434
+ `skill list`, `agents list`, and `hooks list` print available resources and
435
+ mark configured entries as enabled, disabled, or missing. `rules list` prints
436
+ the same state in an indented folder hierarchy.
426
437
 
427
438
  Enable commands validate manager-home sources when the source type must already
428
439
  exist. Enable and disable lists stay mutually exclusive, and repeated commands
@@ -465,40 +476,62 @@ The wrapper can run with a just-in-time package/profile overlay without changing
465
476
  codexmgr codex --package repo-rules --profile strict python -- exec "review this"
466
477
  ```
467
478
 
468
- ## Project MCP Overrides
479
+ ## Project MCP Sources
469
480
 
470
- `codexmgr mcp ...` edits only project-local configuration:
481
+ `codexmgr mcp ...` loads reusable MCP definitions from `$CODEXMGR_HOME/mcp`
482
+ into project-local configuration:
471
483
 
472
- - source state is stored in `.codex/codexmgr.toml` under
473
- `[mcp.servers.<id>]`
474
- - `apply` writes generated overrides into `.codex/config.toml` under
484
+ - reusable source state is stored in `.codex/codexmgr.toml` under `[mcp]`
485
+ - per-project server overlays are stored under `[mcp.servers.<id>]`
486
+ - `apply` writes generated server definitions into `.codex/config.toml` under
475
487
  `[mcp_servers.<id>]`
476
488
  - `$CODEX_HOME/config.toml` and `~/.codex/config.toml` are never modified
477
489
 
478
490
  Mutating MCP commands require a project `.codex/` directory and run `apply`
479
- automatically unless `--no-sync` is passed. They do not create or remove MCP
480
- server definitions; use `codex mcp add` or direct Codex config editing for the
481
- base server setup.
491
+ automatically unless `--no-sync` is passed.
492
+
493
+ Create reusable source files in the same `mcp_servers` shape Codex reads from
494
+ `config.toml`:
495
+
496
+ ```toml
497
+ # ~/.codexmgr/mcp/browsermcp.toml
498
+ [mcp_servers.browsermcp]
499
+ command = "browsermcp"
500
+ args = ["--port", "3000"]
501
+ env_vars = ["BROWSERMCP_TOKEN"]
502
+ ```
482
503
 
483
- List MCP servers available from Codex and show any project override state:
504
+ List reusable sources and show project state:
484
505
 
485
506
  ```bash
486
507
  codexmgr mcp list
487
- codexmgr mcp show context7
508
+ codexmgr mcp show browsermcp
488
509
  codexmgr mcp validate
489
510
  ```
490
511
 
491
- `codexmgr mcp list` shells out to `codex mcp list --json` for read-only
492
- discovery. It does not edit user configuration.
493
-
494
- Enable or disable an existing server without deleting its definition:
512
+ Enable or disable reusable sources for the current project:
495
513
 
496
514
  ```bash
497
- codexmgr mcp disable context7
498
- codexmgr mcp enable context7
515
+ codexmgr mcp enable browsermcp context7
516
+ codexmgr mcp disable browsermcp
517
+ ```
518
+
519
+ `disable` unloads the source from `[mcp].enabled`. It does not keep a generated
520
+ server definition with `enabled = false`.
521
+
522
+ Use `[mcp.servers.<id>]` for project-local overlays. Overlays merge after source
523
+ files, so they can override or add fields:
524
+
525
+ ```toml
526
+ [mcp]
527
+ enabled = ["browsermcp"]
528
+
529
+ [mcp.servers.browsermcp]
530
+ enabled = false
531
+ bearer_token_env_var = "BROWSERMCP_TOKEN"
499
532
  ```
500
533
 
501
- Update token and environment references without storing literal token values:
534
+ Update common token and environment references from the CLI:
502
535
 
503
536
  ```bash
504
537
  codexmgr mcp set-token-env figma FIGMA_TOKEN
@@ -508,7 +541,7 @@ codexmgr mcp set-env-header figma Authorization FIGMA_AUTH_HEADER
508
541
  codexmgr mcp unset-env-header figma Authorization
509
542
  ```
510
543
 
511
- Set a small allowlist of non-secret fields from TOML literals:
544
+ Set a small allowlist of overlay fields from TOML literals:
512
545
 
513
546
  ```bash
514
547
  codexmgr mcp set-field context7 required true
@@ -518,12 +551,11 @@ codexmgr mcp set-field context7 default_tools_approval_mode '"prompt"'
518
551
 
519
552
  Supported `set-field` names are `required`, `startup_timeout_sec`,
520
553
  `tool_timeout_sec`, `enabled_tools`, `disabled_tools`, and
521
- `default_tools_approval_mode`. The direct `enable` and `disable` commands manage
522
- the `enabled` field.
554
+ `default_tools_approval_mode`.
523
555
 
524
- Literal API token writes are intentionally not part of this command surface;
525
- prefer environment variable references such as `bearer_token_env_var`,
526
- `env_vars`, and `env_http_headers`.
556
+ Source files and hand-written overlays can use the full Codex `mcp_servers`
557
+ shape. Prefer environment variable references such as `bearer_token_env_var`,
558
+ `env_vars`, and `env_http_headers` for secrets.
527
559
 
528
560
  ## Development
529
561
 
@@ -1,9 +1,9 @@
1
1
  # codexmgr
2
2
 
3
3
  `codexmgr` manages reusable Codex project setup. Keep shared `AGENTS.md`
4
- snippets, skills, hooks, custom agents, rule files, packages, and safe MCP
5
- overrides in one manager home, then sync the selected pieces into each project
6
- from `.codex/codexmgr.toml`.
4
+ snippets, skills, hooks, custom agents, rule files, packages, and reusable MCP
5
+ source files in one manager home, then sync the selected pieces into each
6
+ project from `.codex/codexmgr.toml`.
7
7
 
8
8
  The tool is for people who use Codex in several repositories and do not want to
9
9
  copy the same agent instructions by hand. When a shared rule changes, update it
@@ -14,7 +14,7 @@ Use `codexmgr` when a project should:
14
14
  - build `AGENTS.md` from reusable instruction snippets
15
15
  - share skills, hooks, custom agents, and rule files across repositories
16
16
  - enable packaged Codex setups made from those reusable pieces
17
- - keep project MCP overrides out of the user-level Codex config
17
+ - keep reusable MCP server definitions out of the user-level Codex config
18
18
  - check whether generated Codex files match the project config
19
19
  - run `codex` with project `.codex/config.toml` values passed as `-c` overrides
20
20
 
@@ -125,7 +125,7 @@ file for you, and you can also edit it by hand when that is clearer.
125
125
  - `.codex/codexmgr.lock`: resolved AGENTS.md, agent, skill, hook, rule, and MCP
126
126
  state
127
127
  - `.codex/config.toml`: project-local Codex config, including generated
128
- `[[skills.config]]` entries and `[mcp_servers.<id>]` overrides
128
+ `[[skills.config]]` entries and `[mcp_servers.<id>]` server definitions
129
129
  - `.codex/hooks.json`: generated hook config for enabled reusable hook bundles
130
130
  - `.codex/hooks/<name>`: copied support files for enabled hook bundles
131
131
  - `.codex/agents/<name>.toml`: copied custom-agent definitions
@@ -147,7 +147,7 @@ Manual content outside this block is preserved. If the block is missing,
147
147
 
148
148
  `.codex/codexmgr.toml` can opt into each resource type independently. A minimal
149
149
  file may only contain `[agents_md]`; larger projects can add skills, custom
150
- agents, hooks, reusable rules, and MCP overrides as needed. Package commands
150
+ agents, hooks, reusable rules, and MCP sources or overlays as needed. Package commands
151
151
  write those same tables rather than a separate package table.
152
152
 
153
153
  ```toml
@@ -165,6 +165,8 @@ disabled = ["experimental-hook"]
165
165
  [rules]
166
166
  enabled = ["react/", "python/testing.md"]
167
167
  disabled = ["react/materials/"]
168
+ [mcp]
169
+ enabled = ["browsermcp"]
168
170
  [mcp.servers.browsermcp]
169
171
  enabled = true
170
172
  bearer_token_env_var = "BROWSERMCP_TOKEN"
@@ -209,6 +211,9 @@ Rule refs resolve under `$CODEXMGR_HOME/rules/` and use POSIX-style relative
209
211
  paths. Folder refs have a trailing slash and copy regular files recursively into
210
212
  `.rules/` while preserving relative paths.
211
213
 
214
+ Rule listings are grouped by folder. `codexmgr rules list` prints an indented
215
+ tree, while the TUI Rules screen shows the same refs in a collapsible tree.
216
+
212
217
  File rule refs copy one file. Extensionless refs prefer an existing `<ref>.md`.
213
218
  Enabled refs expand first, then disabled file or folder refs remove entries from
214
219
  that candidate set.
@@ -269,7 +274,8 @@ These commands run `apply` automatically unless `--no-sync` is passed.
269
274
 
270
275
  `codexmgr tui` opens a Textual-based terminal UI for project-local
271
276
  configuration. It shows `AGENTS.md` snippets, skills, hooks, custom agents,
272
- rules, packages, and MCP server enable overrides in selectable lists.
277
+ packages, and reusable MCP sources in selectable lists. Rules are shown
278
+ in a collapsible folder tree.
273
279
 
274
280
  Changes are staged in memory while you navigate. Press `s` to save; the save
275
281
  writes `.codex/codexmgr.toml` once and runs `apply` once unless `--no-sync` was
@@ -277,7 +283,9 @@ used.
277
283
 
278
284
  For resources with explicit enable and disable lists, `space` cycles the
279
285
  highlighted row through available, enabled, and disabled states. Package
280
- profiles appear as separate selectable rows under their package.
286
+ profiles appear as separate selectable rows under their package. In the Rules
287
+ tree, cycling a file or folder node updates the full canonical rule ref behind
288
+ that basename label.
281
289
 
282
290
  ```bash
283
291
  codexmgr tui
@@ -289,9 +297,10 @@ The dashboard shows generated-file sync state. By default it lists stale
289
297
  generated paths; with `--show-diff`, it shows unified diffs for the staged
290
298
  configuration.
291
299
 
292
- MCP editing in the TUI is intentionally limited to the project-local `enabled`
293
- override. Advanced MCP fields remain available through the `codexmgr mcp ...`
294
- commands.
300
+ MCP editing in the TUI is intentionally limited to loading and unloading
301
+ reusable `$CODEXMGR_HOME/mcp/*.toml` sources. Advanced per-server overlay fields
302
+ remain available through the `codexmgr mcp ...` commands or direct
303
+ `.codex/codexmgr.toml` edits.
295
304
 
296
305
  ## Template Format
297
306
 
@@ -398,8 +407,9 @@ codexmgr rules enable [--no-sync] <rule-ref> [...]
398
407
  codexmgr rules disable [--no-sync] <rule-ref> [...]
399
408
  ```
400
409
 
401
- `skill list`, `agents list`, `hooks list`, and `rules list` print available
402
- resources and mark configured entries as enabled, disabled, or missing.
410
+ `skill list`, `agents list`, and `hooks list` print available resources and
411
+ mark configured entries as enabled, disabled, or missing. `rules list` prints
412
+ the same state in an indented folder hierarchy.
403
413
 
404
414
  Enable commands validate manager-home sources when the source type must already
405
415
  exist. Enable and disable lists stay mutually exclusive, and repeated commands
@@ -442,40 +452,62 @@ The wrapper can run with a just-in-time package/profile overlay without changing
442
452
  codexmgr codex --package repo-rules --profile strict python -- exec "review this"
443
453
  ```
444
454
 
445
- ## Project MCP Overrides
455
+ ## Project MCP Sources
446
456
 
447
- `codexmgr mcp ...` edits only project-local configuration:
457
+ `codexmgr mcp ...` loads reusable MCP definitions from `$CODEXMGR_HOME/mcp`
458
+ into project-local configuration:
448
459
 
449
- - source state is stored in `.codex/codexmgr.toml` under
450
- `[mcp.servers.<id>]`
451
- - `apply` writes generated overrides into `.codex/config.toml` under
460
+ - reusable source state is stored in `.codex/codexmgr.toml` under `[mcp]`
461
+ - per-project server overlays are stored under `[mcp.servers.<id>]`
462
+ - `apply` writes generated server definitions into `.codex/config.toml` under
452
463
  `[mcp_servers.<id>]`
453
464
  - `$CODEX_HOME/config.toml` and `~/.codex/config.toml` are never modified
454
465
 
455
466
  Mutating MCP commands require a project `.codex/` directory and run `apply`
456
- automatically unless `--no-sync` is passed. They do not create or remove MCP
457
- server definitions; use `codex mcp add` or direct Codex config editing for the
458
- base server setup.
467
+ automatically unless `--no-sync` is passed.
468
+
469
+ Create reusable source files in the same `mcp_servers` shape Codex reads from
470
+ `config.toml`:
471
+
472
+ ```toml
473
+ # ~/.codexmgr/mcp/browsermcp.toml
474
+ [mcp_servers.browsermcp]
475
+ command = "browsermcp"
476
+ args = ["--port", "3000"]
477
+ env_vars = ["BROWSERMCP_TOKEN"]
478
+ ```
459
479
 
460
- List MCP servers available from Codex and show any project override state:
480
+ List reusable sources and show project state:
461
481
 
462
482
  ```bash
463
483
  codexmgr mcp list
464
- codexmgr mcp show context7
484
+ codexmgr mcp show browsermcp
465
485
  codexmgr mcp validate
466
486
  ```
467
487
 
468
- `codexmgr mcp list` shells out to `codex mcp list --json` for read-only
469
- discovery. It does not edit user configuration.
470
-
471
- Enable or disable an existing server without deleting its definition:
488
+ Enable or disable reusable sources for the current project:
472
489
 
473
490
  ```bash
474
- codexmgr mcp disable context7
475
- codexmgr mcp enable context7
491
+ codexmgr mcp enable browsermcp context7
492
+ codexmgr mcp disable browsermcp
493
+ ```
494
+
495
+ `disable` unloads the source from `[mcp].enabled`. It does not keep a generated
496
+ server definition with `enabled = false`.
497
+
498
+ Use `[mcp.servers.<id>]` for project-local overlays. Overlays merge after source
499
+ files, so they can override or add fields:
500
+
501
+ ```toml
502
+ [mcp]
503
+ enabled = ["browsermcp"]
504
+
505
+ [mcp.servers.browsermcp]
506
+ enabled = false
507
+ bearer_token_env_var = "BROWSERMCP_TOKEN"
476
508
  ```
477
509
 
478
- Update token and environment references without storing literal token values:
510
+ Update common token and environment references from the CLI:
479
511
 
480
512
  ```bash
481
513
  codexmgr mcp set-token-env figma FIGMA_TOKEN
@@ -485,7 +517,7 @@ codexmgr mcp set-env-header figma Authorization FIGMA_AUTH_HEADER
485
517
  codexmgr mcp unset-env-header figma Authorization
486
518
  ```
487
519
 
488
- Set a small allowlist of non-secret fields from TOML literals:
520
+ Set a small allowlist of overlay fields from TOML literals:
489
521
 
490
522
  ```bash
491
523
  codexmgr mcp set-field context7 required true
@@ -495,12 +527,11 @@ codexmgr mcp set-field context7 default_tools_approval_mode '"prompt"'
495
527
 
496
528
  Supported `set-field` names are `required`, `startup_timeout_sec`,
497
529
  `tool_timeout_sec`, `enabled_tools`, `disabled_tools`, and
498
- `default_tools_approval_mode`. The direct `enable` and `disable` commands manage
499
- the `enabled` field.
530
+ `default_tools_approval_mode`.
500
531
 
501
- Literal API token writes are intentionally not part of this command surface;
502
- prefer environment variable references such as `bearer_token_env_var`,
503
- `env_vars`, and `env_http_headers`.
532
+ Source files and hand-written overlays can use the full Codex `mcp_servers`
533
+ shape. Prefer environment variable references such as `bearer_token_env_var`,
534
+ `env_vars`, and `env_http_headers` for secrets.
504
535
 
505
536
  ## Development
506
537
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codexmgr"
3
- version = "0.2.1"
3
+ version = "0.3.0"
4
4
  description = "Manage project-local Codex configuration from reusable templates"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -21,6 +21,9 @@ classifiers = [
21
21
  "Typing :: Typed",
22
22
  ]
23
23
 
24
+ [project.urls]
25
+ Repository = "https://github.com/JulianKimmig/codexmgr/"
26
+
24
27
  [project.scripts]
25
28
  codexmgr = "codexmgr.interface.cli:entrypoint"
26
29
 
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.2.1"
5
+ __version__ = "0.3.0"
@@ -19,21 +19,21 @@ def add_mcp_parser(
19
19
  Returns:
20
20
  None. The parser is mutated in place.
21
21
  """
22
- mcp = subparsers.add_parser("mcp", help="Manage project MCP server overrides")
22
+ mcp = subparsers.add_parser("mcp", help="Manage project MCP sources and overrides")
23
23
  mcp_subparsers = mcp.add_subparsers(dest="mcp_command", required=True)
24
24
 
25
- mcp_subparsers.add_parser("list", help="List project MCP server overrides")
25
+ mcp_subparsers.add_parser("list", help="List reusable MCP sources")
26
26
 
27
- show = mcp_subparsers.add_parser("show", help="Show one project MCP override")
28
- show.add_argument("server_id", help="MCP server id")
27
+ show = mcp_subparsers.add_parser("show", help="Show one reusable MCP source")
28
+ show.add_argument("server_id", help="MCP source name")
29
29
 
30
- enable = mcp_subparsers.add_parser("enable", help="Enable an MCP server locally")
30
+ enable = mcp_subparsers.add_parser("enable", help="Enable reusable MCP sources")
31
31
  add_no_sync_argument(enable)
32
- enable.add_argument("server_ids", nargs="+", help="MCP server ids")
32
+ enable.add_argument("server_ids", nargs="+", help="MCP source names")
33
33
 
34
- disable = mcp_subparsers.add_parser("disable", help="Disable an MCP server locally")
34
+ disable = mcp_subparsers.add_parser("disable", help="Disable reusable MCP sources")
35
35
  add_no_sync_argument(disable)
36
- disable.add_argument("server_ids", nargs="+", help="MCP server ids")
36
+ disable.add_argument("server_ids", nargs="+", help="MCP source names")
37
37
 
38
38
  token = mcp_subparsers.add_parser(
39
39
  "set-token-env",
@@ -26,31 +26,69 @@ from .fields import (
26
26
  validate_field,
27
27
  validate_override,
28
28
  )
29
+ from .project import (
30
+ disable_mcp_sources,
31
+ enable_mcp_sources,
32
+ mcp_source_names,
33
+ set_mcp_source_enabled_in_config,
34
+ )
35
+ from .resolution import (
36
+ McpResolution,
37
+ empty_mcp_resolution,
38
+ resolve_project_mcp,
39
+ validate_mcp_config,
40
+ )
41
+ from .sources import (
42
+ McpSource,
43
+ available_mcp_source_names,
44
+ load_mcp_source,
45
+ load_mcp_sources,
46
+ mcp_source_file,
47
+ mcp_sources_dir,
48
+ require_mcp_source,
49
+ resolve_mcp_source,
50
+ )
29
51
 
30
52
  __all__ = [
31
53
  "APPROVAL_MODES",
32
54
  "CodexMcpServer",
55
+ "McpResolution",
56
+ "McpSource",
33
57
  "SAFE_FIELDS",
34
58
  "SET_FIELD_NAMES",
35
59
  "add_env_var",
36
60
  "apply_mcp_overrides",
61
+ "available_mcp_source_names",
37
62
  "available_state",
38
63
  "configured_overrides",
64
+ "disable_mcp_sources",
39
65
  "discover_codex_servers",
66
+ "empty_mcp_resolution",
67
+ "enable_mcp_sources",
40
68
  "is_string_map",
41
69
  "known_fields",
70
+ "load_mcp_source",
71
+ "load_mcp_sources",
42
72
  "mcp_lock_data",
73
+ "mcp_source_file",
74
+ "mcp_source_names",
75
+ "mcp_sources_dir",
43
76
  "parse_value",
44
77
  "remove_env_var",
78
+ "require_mcp_source",
79
+ "resolve_mcp_source",
45
80
  "require_string_list",
81
+ "resolve_project_mcp",
46
82
  "resolve_overrides",
47
83
  "set_enabled",
84
+ "set_mcp_source_enabled_in_config",
48
85
  "set_env_header",
49
86
  "set_field",
50
87
  "set_token_env",
51
88
  "unset_env_header",
52
89
  "unsupported_field_warnings",
53
90
  "validate_field",
91
+ "validate_mcp_config",
54
92
  "validate_override",
55
93
  "validate_overrides",
56
94
  ]
@@ -1,4 +1,4 @@
1
- """Apply project MCP overrides to generated Codex config and lock data."""
1
+ """Apply project MCP server tables to generated Codex config and lock data."""
2
2
 
3
3
  from collections.abc import Mapping, MutableMapping
4
4
  from typing import Any
@@ -9,14 +9,14 @@ from ..core.toml_io import ensure_toml_table
9
9
 
10
10
  def apply_mcp_overrides(
11
11
  codex_config: MutableMapping[str, Any],
12
- overrides: Mapping[str, Mapping[str, Any]],
12
+ servers: Mapping[str, Mapping[str, Any]],
13
13
  previous_lock: Mapping[str, Any],
14
14
  ) -> None:
15
- """Apply MCP overrides to a local Codex config document.
15
+ """Apply MCP server tables to a local Codex config document.
16
16
 
17
17
  Args:
18
18
  codex_config: Mutable .codex/config.toml document.
19
- overrides: Current MCP overrides.
19
+ servers: Current generated MCP server tables.
20
20
  previous_lock: Previous codexmgr lock data.
21
21
  """
22
22
  mcp_servers = ensure_toml_table(
@@ -25,7 +25,7 @@ def apply_mcp_overrides(
25
25
  ".codex/config.toml [mcp_servers] must be a table",
26
26
  )
27
27
  _remove_previous_fields(mcp_servers, previous_lock)
28
- for server_id, fields in overrides.items():
28
+ for server_id, fields in servers.items():
29
29
  target = ensure_toml_table(
30
30
  mcp_servers,
31
31
  server_id,
@@ -34,16 +34,23 @@ def apply_mcp_overrides(
34
34
  target.update(known_fields(fields))
35
35
 
36
36
 
37
- def mcp_lock_data(overrides: Mapping[str, Mapping[str, Any]]) -> dict[str, Any]:
38
- """Build lock data for MCP overrides.
37
+ def mcp_lock_data(
38
+ enabled_sources: list[str],
39
+ servers: Mapping[str, Mapping[str, Any]],
40
+ ) -> dict[str, Any]:
41
+ """Build lock data for generated MCP state.
39
42
 
40
43
  Args:
41
- overrides: Current MCP overrides.
44
+ enabled_sources: Reusable MCP source names enabled by the project.
45
+ servers: Current generated MCP server tables.
42
46
 
43
47
  Returns:
44
48
  Lockfile MCP data.
45
49
  """
46
- return {"servers": {key: known_fields(value) for key, value in overrides.items()}}
50
+ return {
51
+ "enabled": list(enabled_sources),
52
+ "servers": {key: known_fields(value) for key, value in servers.items()},
53
+ }
47
54
 
48
55
 
49
56
  def _remove_previous_fields(