code-agnostic 0.3.4__tar.gz → 0.3.7__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 (160) hide show
  1. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/PKG-INFO +106 -30
  2. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/README.md +105 -29
  3. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/__init__.py +1 -1
  4. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/__main__.py +3 -1
  5. code_agnostic-0.3.7/code_agnostic/agents/claude.py +67 -0
  6. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/compilers.py +8 -0
  7. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/opencode.py +36 -12
  8. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/parser.py +1 -1
  9. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/app_id.py +15 -1
  10. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/apps_service.py +3 -0
  11. code_agnostic-0.3.7/code_agnostic/apps/claude/__init__.py +1 -0
  12. code_agnostic-0.3.7/code_agnostic/apps/claude/config_repository.py +59 -0
  13. code_agnostic-0.3.7/code_agnostic/apps/claude/mapper.py +86 -0
  14. code_agnostic-0.3.7/code_agnostic/apps/claude/service.py +248 -0
  15. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/codex/config_repository.py +2 -1
  16. code_agnostic-0.3.7/code_agnostic/apps/codex/schema.json +5200 -0
  17. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/codex/service.py +8 -1
  18. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/compiled_planning.py +64 -3
  19. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/interfaces/service.py +1 -0
  20. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/loader.py +1 -0
  21. code_agnostic-0.3.7/code_agnostic/apps/opencode/schema.json +1252 -0
  22. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/opencode/service.py +14 -4
  23. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/skills.py +23 -2
  24. code_agnostic-0.3.7/code_agnostic/cli/commands/status.py +64 -0
  25. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/helpers.py +6 -7
  26. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/options.py +0 -12
  27. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/constants.py +4 -0
  28. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/core/repository.py +1 -1
  29. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/executor.py +117 -25
  30. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/git_exclude_service.py +33 -3
  31. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/imports/adapters.py +17 -0
  32. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/imports/service.py +10 -0
  33. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/lossiness.py +65 -7
  34. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/models.py +11 -2
  35. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/planner.py +167 -35
  36. code_agnostic-0.3.7/code_agnostic/skills/compilers.py +107 -0
  37. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/skills/models.py +2 -0
  38. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/skills/parser.py +11 -0
  39. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/loaders.py +12 -1
  40. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/schemas/agent.v1.schema.json +2 -1
  41. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/schemas/rule.v1.schema.json +2 -1
  42. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/schemas/skill.v1.schema.json +2 -1
  43. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/status.py +32 -2
  44. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/renderers.py +55 -8
  45. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/PKG-INFO +106 -30
  46. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/SOURCES.txt +6 -0
  47. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/pyproject.toml +1 -1
  48. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_apply_apps.py +246 -11
  49. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_explain_lossiness.py +37 -0
  50. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_import.py +1 -1
  51. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_plan.py +19 -0
  52. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_skills.py +7 -1
  53. code_agnostic-0.3.7/tests/test_cli_status.py +155 -0
  54. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_workspaces.py +9 -5
  55. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_common_mcp_to_dto.py +16 -0
  56. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_common_repository.py +4 -5
  57. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_git_exclude_service.py +29 -4
  58. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_planner_executor.py +64 -15
  59. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_sync_plan_model.py +23 -0
  60. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_transactional_executor.py +373 -0
  61. code_agnostic-0.3.7/tests/test_version.py +15 -0
  62. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_workspace_config_sync.py +388 -31
  63. code_agnostic-0.3.4/code_agnostic/apps/codex/schema.json +0 -114
  64. code_agnostic-0.3.4/code_agnostic/apps/opencode/schema.json +0 -7675
  65. code_agnostic-0.3.4/code_agnostic/cli/commands/status.py +0 -52
  66. code_agnostic-0.3.4/code_agnostic/skills/compilers.py +0 -39
  67. code_agnostic-0.3.4/tests/test_cli_status.py +0 -64
  68. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/LICENSE +0 -0
  69. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/__init__.py +0 -0
  70. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/codex.py +0 -0
  71. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/models.py +0 -0
  72. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/__init__.py +0 -0
  73. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/codex/__init__.py +0 -0
  74. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/codex/mapper.py +0 -0
  75. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/codex/schema_repository.py +0 -0
  76. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/__init__.py +0 -0
  77. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/framework.py +0 -0
  78. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/interfaces/__init__.py +0 -0
  79. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/interfaces/mapper.py +0 -0
  80. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/interfaces/repositories.py +0 -0
  81. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/models.py +0 -0
  82. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/schema.py +0 -0
  83. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/symlink_planning.py +0 -0
  84. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/utils.py +0 -0
  85. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/__init__.py +0 -0
  86. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/config_repository.py +0 -0
  87. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/mapper.py +0 -0
  88. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/schema.json +0 -0
  89. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/schema_repository.py +0 -0
  90. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/service.py +0 -0
  91. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/opencode/__init__.py +0 -0
  92. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/opencode/config_repository.py +0 -0
  93. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/opencode/mapper.py +0 -0
  94. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/opencode/schema_repository.py +0 -0
  95. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/__init__.py +0 -0
  96. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/aliases.py +0 -0
  97. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/__init__.py +0 -0
  98. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/agents.py +0 -0
  99. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/apply.py +0 -0
  100. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/apps.py +0 -0
  101. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/explain_lossiness.py +0 -0
  102. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/import_.py +0 -0
  103. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/mcp.py +0 -0
  104. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/plan.py +0 -0
  105. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/restore.py +0 -0
  106. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/rules.py +0 -0
  107. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/validate.py +0 -0
  108. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/workspaces.py +0 -0
  109. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/core/__init__.py +0 -0
  110. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/core/workspace_repository.py +0 -0
  111. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/errors.py +0 -0
  112. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/imports/__init__.py +0 -0
  113. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/imports/filesystem.py +0 -0
  114. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/imports/models.py +0 -0
  115. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/mcp_service.py +0 -0
  116. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/rules/__init__.py +0 -0
  117. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/rules/compilers.py +0 -0
  118. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/rules/models.py +0 -0
  119. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/rules/parser.py +0 -0
  120. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/rules/repository.py +0 -0
  121. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/skills/__init__.py +0 -0
  122. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/__init__.py +0 -0
  123. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/schemas/mcp.base.schema.json +0 -0
  124. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/schemas/mcp.v1.schema.json +0 -0
  125. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/__init__.py +0 -0
  126. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/enums.py +0 -0
  127. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/import_selector.py +0 -0
  128. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/sections.py +0 -0
  129. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/tables.py +0 -0
  130. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/utils.py +0 -0
  131. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/validation.py +0 -0
  132. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/workspaces.py +0 -0
  133. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/dependency_links.txt +0 -0
  134. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/entry_points.txt +0 -0
  135. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/requires.txt +0 -0
  136. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/top_level.txt +0 -0
  137. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/setup.cfg +0 -0
  138. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_agents.py +0 -0
  139. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_aliases.py +0 -0
  140. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_apply_codex.py +0 -0
  141. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_apply_cursor.py +0 -0
  142. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_apply_target.py +0 -0
  143. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_apps.py +0 -0
  144. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_flags.py +0 -0
  145. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_git_exclude.py +0 -0
  146. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_import_interactive.py +0 -0
  147. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_mcp.py +0 -0
  148. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_module_organization.py +0 -0
  149. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_restore.py +0 -0
  150. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_rules.py +0 -0
  151. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_validate.py +0 -0
  152. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_workspace_resolution.py +0 -0
  153. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_compiled_planning.py +0 -0
  154. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_dto_to_common_mcp.py +0 -0
  155. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_mcp_service.py +0 -0
  156. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_planner_rules.py +0 -0
  157. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_symlink_planning.py +0 -0
  158. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_utils.py +0 -0
  159. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_workspace_repo_status.py +0 -0
  160. {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_workspaces.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-agnostic
3
- Version: 0.3.4
3
+ Version: 0.3.7
4
4
  Summary: Centralized hub for LLM coding config: MCP, skills, rules, and agents.
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -36,20 +36,29 @@ AI coding tools each want config in a different place and format. When you use m
36
36
  ├── config/
37
37
  │ └── mcp.base.json MCP servers (editor-agnostic)
38
38
  ├── rules/
39
- │ └── python-style.md Rules with YAML frontmatter
39
+ │ └── python-style/
40
+ │ ├── meta.yaml Rule metadata
41
+ │ └── prompt.md Rule instructions
40
42
  ├── skills/
41
- │ └── code-reviewer/SKILL.md Skills with YAML frontmatter
43
+ │ └── code-reviewer/
44
+ │ ├── meta.yaml Skill metadata
45
+ │ └── prompt.md Skill instructions
42
46
  └── agents/
43
- └── architect.md Agents with YAML frontmatter
47
+ └── architect/
48
+ ├── meta.yaml Agent metadata
49
+ └── prompt.md Agent instructions
44
50
 
45
51
  ↓ plan / apply ↓
46
52
 
47
53
  ~/.config/opencode/ Compiled & synced for OpenCode
48
54
  ~/.cursor/ Compiled & synced for Cursor
49
55
  ~/.codex/ Compiled & synced for Codex
56
+ ~/.claude.json and ~/.claude/ Compiled & synced for Claude Code
50
57
  ```
51
58
 
52
- Each resource is cross-compiled to the target editor's native format. Rules become `.mdc` files for Cursor, `AGENTS.md` sections for OpenCode/Codex, etc.
59
+ Each resource is cross-compiled to the target editor's native format. Rules become `.mdc` files for Cursor, `AGENTS.md` sections for OpenCode/Codex, and `CLAUDE.local.md` memory for Claude Code.
60
+
61
+ Legacy single-file rules, `skills/<name>/SKILL.md`, and markdown agents are still supported for migration, but bundle directories are the preferred source format for new config.
53
62
 
54
63
  Today the implementation is still mixed: some assets are compiled and some are symlinked. The active migration plan is to move to generated outputs everywhere with a strict compiler contract instead of implicit per-app behavior.
55
64
 
@@ -86,33 +95,35 @@ code-agnostic import apply -a codex
86
95
  # Enable target editors
87
96
  code-agnostic apps enable -a cursor
88
97
  code-agnostic apps enable -a opencode
98
+ code-agnostic apps enable -a claude
89
99
 
90
100
  # Preview and apply
101
+ code-agnostic validate
91
102
  code-agnostic plan
92
103
  code-agnostic apply
93
104
  ```
94
105
 
95
106
  ## Editor compatibility
96
107
 
97
- | Feature | OpenCode | Cursor | Codex |
98
- |---------|:--------:|:------:|:-----:|
99
- | MCP sync | yes | yes | yes |
100
- | Rules sync (cross-compiled) | yes | yes | yes |
101
- | Skills sync | yes | yes | yes |
102
- | Agents sync | yes | yes | yes |
103
- | Workspace root `AGENTS.md` link | yes | yes | yes |
104
- | Native repo config include for workspace `AGENTS.md` | yes | -- | -- |
105
- | Repo/subdir gets shared workspace `AGENTS.md` today | yes | -- | yes |
106
- | Root-level `AGENTS.md` discovery only | -- | yes | yes |
107
- | Workspace propagation | yes | -- | yes |
108
- | Import from | yes | yes | yes |
109
- | Interactive import (TUI) | yes | yes | yes |
108
+ | Feature | OpenCode | Cursor | Codex | Claude Code |
109
+ |---------|:--------:|:------:|:-----:|:-----------:|
110
+ | MCP sync | yes | yes | yes | yes |
111
+ | Rules sync (cross-compiled) | yes | yes | yes | yes |
112
+ | Skills sync | yes | yes | yes | yes |
113
+ | Agents sync | yes | yes | yes | yes |
114
+ | Workspace root `AGENTS.md` link | yes | yes | yes | yes |
115
+ | Native repo config include for workspace `AGENTS.md` | yes | -- | -- | -- |
116
+ | Repo/subdir gets shared workspace instructions today | yes | -- | yes | yes |
117
+ | Nested `AGENTS.md` discovery | -- | yes | yes | -- |
118
+ | Workspace propagation | yes | -- | yes | yes |
119
+ | Import from | yes | yes | yes | yes |
120
+ | Interactive import (TUI) | yes | yes | yes | yes |
110
121
 
111
122
  Cursor workspace propagation is intentionally disabled to avoid duplicate MCP initialization in multi-root workspaces: https://forum.cursor.com/t/mcp-multi-root-workspace-causes-duplicate-mcp-server-initialization-4x-createclient-actions/144003
112
123
 
113
- OpenCode workspace configs include the shared workspace `AGENTS.md` natively via `instructions`, so repos under the workspace get both repo-local and shared workspace instructions. Codex repos receive workspace instructions through a generated `AGENTS.override.md`, which is added to each repo's `.git/info/exclude`.
124
+ OpenCode workspace configs include the shared workspace `AGENTS.md` natively via `instructions`, so repos under the workspace get both repo-local and shared workspace instructions. Codex repos receive workspace instructions through a generated `AGENTS.override.md`, which is added to each repo's `.git/info/exclude`. Claude Code receives workspace instructions through generated `CLAUDE.local.md` files, never by editing committed `CLAUDE.md`.
114
125
 
115
- Cursor documents `AGENTS.md` as a root-level project file. Codex documents `AGENTS.md` discovery, but not a native config include for an extra workspace file. In practice that means subdirectories and repos opened below the workspace root will not reliably get the shared workspace `AGENTS.md` today for Cursor.
126
+ Cursor documents `AGENTS.md` support in project roots and subdirectories. `code-agnostic` still disables Cursor workspace propagation, so it does not copy or link the shared workspace `AGENTS.md` into child repos; Cursor will load repo-local or nested `AGENTS.md` files that already exist in the opened project. Codex documents nested `AGENTS.md` discovery, but not a native config include for an extra workspace file.
116
127
 
117
128
  ## Features
118
129
 
@@ -121,12 +132,20 @@ Cursor documents `AGENTS.md` as a root-level project file. Codex documents `AGEN
121
132
  Plan-then-apply workflow. Preview every change before it touches disk.
122
133
 
123
134
  ```bash
135
+ code-agnostic validate # check canonical source files
124
136
  code-agnostic plan -a cursor # dry-run for one editor
125
137
  code-agnostic plan # dry-run for all
126
138
  code-agnostic apply # apply changes
127
139
  code-agnostic status # check drift
128
140
  ```
129
141
 
142
+ If managed outputs need repair after an apply, restore the active synced revision:
143
+
144
+ ```bash
145
+ code-agnostic restore
146
+ code-agnostic restore -w myproject
147
+ ```
148
+
130
149
  ### MCP management
131
150
 
132
151
  Add, remove, and list MCP servers without editing JSON by hand.
@@ -162,16 +181,37 @@ code-agnostic rules remove --name python-style
162
181
 
163
182
  ### Skills and agents
164
183
 
165
- Canonical YAML frontmatter format, cross-compiled per editor.
184
+ Canonical YAML frontmatter format, cross-compiled per editor. Install or edit skills in the `code-agnostic` source of truth, then run `plan` / `apply`; do not hand-copy generated skills into `.codex`, `.cursor`, or OpenCode directories.
166
185
 
167
186
  ```bash
168
187
  code-agnostic skills list
169
188
  code-agnostic agents list
170
189
  ```
171
190
 
191
+ Manual skill install today:
192
+
193
+ ```bash
194
+ mkdir -p ~/.config/code-agnostic/skills
195
+ cp -R ./my-skill ~/.config/code-agnostic/skills/my-skill
196
+ code-agnostic plan
197
+ code-agnostic apply
198
+ ```
199
+
200
+ Global skills live under `~/.config/code-agnostic/skills`. Workspace-local skills live under `~/.config/code-agnostic/workspaces/<name>/skills` and can be inspected with `code-agnostic skills list -w <name>`. Codex generated skill outputs are written to `~/.agents/skills`, while Codex agents and config remain under `~/.codex`. Claude Code generated skills and agents are written under `~/.claude/skills` and `~/.claude/agents`, with workspace copies under repo-local `.claude/skills` and `.claude/agents`.
201
+
202
+ Project-local skills are not first-class source inputs in `code-agnostic` yet. If a target app discovers repo-local skill folders such as `.agents/skills`, `.opencode/skills`, or user-created `.claude/skills`, treat those as unmanaged app inputs. Workspace sync writes only the exact generated paths recorded in `.sync-state.json`.
203
+
204
+ Planned convenience command:
205
+
206
+ ```bash
207
+ code-agnostic skills install ./my-skill --apply
208
+ ```
209
+
210
+ That command should copy the skill into the source of truth and then run the normal compiler/apply flow.
211
+
172
212
  ### Workspaces
173
213
 
174
- Register workspace directories. Workspace rules are compiled into a canonical `AGENTS.md` at the workspace root. Repos keep their own repo-specific `AGENTS.md`; Codex receives the workspace rules through generated, git-excluded `AGENTS.override.md` files, while OpenCode workspace configs reference the shared workspace file through `instructions`. Repo-local app config, skills, and agents are propagated for OpenCode and Codex.
214
+ Register workspace directories. Workspace rules are compiled into a canonical `AGENTS.md` at the workspace root. Repos keep their own repo-specific `AGENTS.md`; Codex receives the workspace rules through generated, git-excluded `AGENTS.override.md` files, while OpenCode workspace configs reference the shared workspace file through `instructions`. Claude receives generated `CLAUDE.local.md` files and project MCP entries in `~/.claude.json["projects"][absolute_repo_path]["mcpServers"]`. Repo-local app config, skills, and agents are propagated for OpenCode, Codex, and Claude.
175
215
 
176
216
  `.cursor` workspace propagation is intentionally disabled to avoid duplicate MCP initialization when opening multi-root workspaces in Cursor (related issue: https://forum.cursor.com/t/mcp-multi-root-workspace-causes-duplicate-mcp-server-initialization-4x-createclient-actions/144003).
177
217
 
@@ -198,6 +238,7 @@ Migrate existing config from any supported editor into the hub.
198
238
  ```bash
199
239
  code-agnostic import plan -a codex
200
240
  code-agnostic import apply -a codex
241
+ code-agnostic import plan -a claude
201
242
  code-agnostic import apply -a cursor --include mcp --on-conflict overwrite
202
243
  code-agnostic import plan -a codex -i # interactive TUI picker
203
244
  ```
@@ -210,13 +251,12 @@ All commands use named flags (`-a`, `-w`, `-v`). Singular aliases work too: `app
210
251
 
211
252
  The compiler migration is documented in:
212
253
 
213
- - [ROADMAP.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/ROADMAP.md)
214
- - [docs/compiler/overview.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/overview.md)
215
- - [docs/compiler/skills.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/skills.md)
216
- - [docs/compiler/agents.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/agents.md)
217
- - [docs/compiler/rules.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/rules.md)
218
- - [docs/compiler/mcp.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/mcp.md)
219
- - [docs/compiler/lossiness.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/lossiness.md)
254
+ - [docs/compiler/overview.md](docs/compiler/overview.md)
255
+ - [docs/compiler/skills.md](docs/compiler/skills.md)
256
+ - [docs/compiler/agents.md](docs/compiler/agents.md)
257
+ - [docs/compiler/rules.md](docs/compiler/rules.md)
258
+ - [docs/compiler/mcp.md](docs/compiler/mcp.md)
259
+ - [docs/compiler/lossiness.md](docs/compiler/lossiness.md)
220
260
 
221
261
  ## Roadmap
222
262
 
@@ -231,7 +271,8 @@ The compiler migration is documented in:
231
271
  - [x] Cross-compilation for skills and agents
232
272
  - [x] Per-workspace git-exclude customization
233
273
  - [x] Interactive TUI for import selection
234
- - [ ] Claude Code support
274
+ - [x] Claude Code support
275
+ - [ ] Project-scoped skill installs and sync
235
276
  - [ ] `rules add` / `skills add` / `agents add` commands (open `$EDITOR` with template)
236
277
  - [ ] Planner integration for cross-compiled skills and agents
237
278
  - [ ] Shell auto-complete
@@ -243,3 +284,38 @@ The compiler migration is documented in:
243
284
  uv sync --dev
244
285
  uv run pytest
245
286
  ```
287
+
288
+ Before pushing release-prep work, run the supported Python matrix locally. Tox
289
+ delegates each environment to `uv run --python`, so `uv` can provide the
290
+ requested interpreter when it is not already installed:
291
+
292
+ ```bash
293
+ uvx tox run -p auto
294
+ uvx tox run -e uv310 -- tests/test_version.py -q
295
+ ```
296
+
297
+ For a hermetic Linux matrix that does not depend on locally installed Python
298
+ versions, run the Docker matrix:
299
+
300
+ ```bash
301
+ ./scripts/run-docker-matrix.sh
302
+ ./scripts/run-docker-matrix.sh tests/test_version.py -q
303
+ ```
304
+
305
+ Limit the Docker matrix while iterating:
306
+
307
+ ```bash
308
+ PYTHON_VERSIONS="3.10 3.14" ./scripts/run-docker-matrix.sh tests/test_version.py -q
309
+ ```
310
+
311
+ The release gate still requires GitHub Actions to pass because the published
312
+ workflow is the source of truth for OS coverage across Ubuntu, macOS, and
313
+ Windows on every supported Python version.
314
+
315
+ Real app-ingestion E2E is gated because it requires installed target CLIs and
316
+ uses each tool's own introspection surface:
317
+
318
+ ```bash
319
+ CODE_AGNOSTIC_REAL_APP_E2E=1 uv run pytest tests/e2e/test_real_app_ingestion_e2e.py -q
320
+ CODE_AGNOSTIC_REAL_APP_E2E=1 CODE_AGNOSTIC_REAL_APP_TARGETS=codex,opencode,claude uv run pytest tests/e2e/test_real_app_ingestion_e2e.py -q
321
+ ```
@@ -13,20 +13,29 @@ AI coding tools each want config in a different place and format. When you use m
13
13
  ├── config/
14
14
  │ └── mcp.base.json MCP servers (editor-agnostic)
15
15
  ├── rules/
16
- │ └── python-style.md Rules with YAML frontmatter
16
+ │ └── python-style/
17
+ │ ├── meta.yaml Rule metadata
18
+ │ └── prompt.md Rule instructions
17
19
  ├── skills/
18
- │ └── code-reviewer/SKILL.md Skills with YAML frontmatter
20
+ │ └── code-reviewer/
21
+ │ ├── meta.yaml Skill metadata
22
+ │ └── prompt.md Skill instructions
19
23
  └── agents/
20
- └── architect.md Agents with YAML frontmatter
24
+ └── architect/
25
+ ├── meta.yaml Agent metadata
26
+ └── prompt.md Agent instructions
21
27
 
22
28
  ↓ plan / apply ↓
23
29
 
24
30
  ~/.config/opencode/ Compiled & synced for OpenCode
25
31
  ~/.cursor/ Compiled & synced for Cursor
26
32
  ~/.codex/ Compiled & synced for Codex
33
+ ~/.claude.json and ~/.claude/ Compiled & synced for Claude Code
27
34
  ```
28
35
 
29
- Each resource is cross-compiled to the target editor's native format. Rules become `.mdc` files for Cursor, `AGENTS.md` sections for OpenCode/Codex, etc.
36
+ Each resource is cross-compiled to the target editor's native format. Rules become `.mdc` files for Cursor, `AGENTS.md` sections for OpenCode/Codex, and `CLAUDE.local.md` memory for Claude Code.
37
+
38
+ Legacy single-file rules, `skills/<name>/SKILL.md`, and markdown agents are still supported for migration, but bundle directories are the preferred source format for new config.
30
39
 
31
40
  Today the implementation is still mixed: some assets are compiled and some are symlinked. The active migration plan is to move to generated outputs everywhere with a strict compiler contract instead of implicit per-app behavior.
32
41
 
@@ -63,33 +72,35 @@ code-agnostic import apply -a codex
63
72
  # Enable target editors
64
73
  code-agnostic apps enable -a cursor
65
74
  code-agnostic apps enable -a opencode
75
+ code-agnostic apps enable -a claude
66
76
 
67
77
  # Preview and apply
78
+ code-agnostic validate
68
79
  code-agnostic plan
69
80
  code-agnostic apply
70
81
  ```
71
82
 
72
83
  ## Editor compatibility
73
84
 
74
- | Feature | OpenCode | Cursor | Codex |
75
- |---------|:--------:|:------:|:-----:|
76
- | MCP sync | yes | yes | yes |
77
- | Rules sync (cross-compiled) | yes | yes | yes |
78
- | Skills sync | yes | yes | yes |
79
- | Agents sync | yes | yes | yes |
80
- | Workspace root `AGENTS.md` link | yes | yes | yes |
81
- | Native repo config include for workspace `AGENTS.md` | yes | -- | -- |
82
- | Repo/subdir gets shared workspace `AGENTS.md` today | yes | -- | yes |
83
- | Root-level `AGENTS.md` discovery only | -- | yes | yes |
84
- | Workspace propagation | yes | -- | yes |
85
- | Import from | yes | yes | yes |
86
- | Interactive import (TUI) | yes | yes | yes |
85
+ | Feature | OpenCode | Cursor | Codex | Claude Code |
86
+ |---------|:--------:|:------:|:-----:|:-----------:|
87
+ | MCP sync | yes | yes | yes | yes |
88
+ | Rules sync (cross-compiled) | yes | yes | yes | yes |
89
+ | Skills sync | yes | yes | yes | yes |
90
+ | Agents sync | yes | yes | yes | yes |
91
+ | Workspace root `AGENTS.md` link | yes | yes | yes | yes |
92
+ | Native repo config include for workspace `AGENTS.md` | yes | -- | -- | -- |
93
+ | Repo/subdir gets shared workspace instructions today | yes | -- | yes | yes |
94
+ | Nested `AGENTS.md` discovery | -- | yes | yes | -- |
95
+ | Workspace propagation | yes | -- | yes | yes |
96
+ | Import from | yes | yes | yes | yes |
97
+ | Interactive import (TUI) | yes | yes | yes | yes |
87
98
 
88
99
  Cursor workspace propagation is intentionally disabled to avoid duplicate MCP initialization in multi-root workspaces: https://forum.cursor.com/t/mcp-multi-root-workspace-causes-duplicate-mcp-server-initialization-4x-createclient-actions/144003
89
100
 
90
- OpenCode workspace configs include the shared workspace `AGENTS.md` natively via `instructions`, so repos under the workspace get both repo-local and shared workspace instructions. Codex repos receive workspace instructions through a generated `AGENTS.override.md`, which is added to each repo's `.git/info/exclude`.
101
+ OpenCode workspace configs include the shared workspace `AGENTS.md` natively via `instructions`, so repos under the workspace get both repo-local and shared workspace instructions. Codex repos receive workspace instructions through a generated `AGENTS.override.md`, which is added to each repo's `.git/info/exclude`. Claude Code receives workspace instructions through generated `CLAUDE.local.md` files, never by editing committed `CLAUDE.md`.
91
102
 
92
- Cursor documents `AGENTS.md` as a root-level project file. Codex documents `AGENTS.md` discovery, but not a native config include for an extra workspace file. In practice that means subdirectories and repos opened below the workspace root will not reliably get the shared workspace `AGENTS.md` today for Cursor.
103
+ Cursor documents `AGENTS.md` support in project roots and subdirectories. `code-agnostic` still disables Cursor workspace propagation, so it does not copy or link the shared workspace `AGENTS.md` into child repos; Cursor will load repo-local or nested `AGENTS.md` files that already exist in the opened project. Codex documents nested `AGENTS.md` discovery, but not a native config include for an extra workspace file.
93
104
 
94
105
  ## Features
95
106
 
@@ -98,12 +109,20 @@ Cursor documents `AGENTS.md` as a root-level project file. Codex documents `AGEN
98
109
  Plan-then-apply workflow. Preview every change before it touches disk.
99
110
 
100
111
  ```bash
112
+ code-agnostic validate # check canonical source files
101
113
  code-agnostic plan -a cursor # dry-run for one editor
102
114
  code-agnostic plan # dry-run for all
103
115
  code-agnostic apply # apply changes
104
116
  code-agnostic status # check drift
105
117
  ```
106
118
 
119
+ If managed outputs need repair after an apply, restore the active synced revision:
120
+
121
+ ```bash
122
+ code-agnostic restore
123
+ code-agnostic restore -w myproject
124
+ ```
125
+
107
126
  ### MCP management
108
127
 
109
128
  Add, remove, and list MCP servers without editing JSON by hand.
@@ -139,16 +158,37 @@ code-agnostic rules remove --name python-style
139
158
 
140
159
  ### Skills and agents
141
160
 
142
- Canonical YAML frontmatter format, cross-compiled per editor.
161
+ Canonical YAML frontmatter format, cross-compiled per editor. Install or edit skills in the `code-agnostic` source of truth, then run `plan` / `apply`; do not hand-copy generated skills into `.codex`, `.cursor`, or OpenCode directories.
143
162
 
144
163
  ```bash
145
164
  code-agnostic skills list
146
165
  code-agnostic agents list
147
166
  ```
148
167
 
168
+ Manual skill install today:
169
+
170
+ ```bash
171
+ mkdir -p ~/.config/code-agnostic/skills
172
+ cp -R ./my-skill ~/.config/code-agnostic/skills/my-skill
173
+ code-agnostic plan
174
+ code-agnostic apply
175
+ ```
176
+
177
+ Global skills live under `~/.config/code-agnostic/skills`. Workspace-local skills live under `~/.config/code-agnostic/workspaces/<name>/skills` and can be inspected with `code-agnostic skills list -w <name>`. Codex generated skill outputs are written to `~/.agents/skills`, while Codex agents and config remain under `~/.codex`. Claude Code generated skills and agents are written under `~/.claude/skills` and `~/.claude/agents`, with workspace copies under repo-local `.claude/skills` and `.claude/agents`.
178
+
179
+ Project-local skills are not first-class source inputs in `code-agnostic` yet. If a target app discovers repo-local skill folders such as `.agents/skills`, `.opencode/skills`, or user-created `.claude/skills`, treat those as unmanaged app inputs. Workspace sync writes only the exact generated paths recorded in `.sync-state.json`.
180
+
181
+ Planned convenience command:
182
+
183
+ ```bash
184
+ code-agnostic skills install ./my-skill --apply
185
+ ```
186
+
187
+ That command should copy the skill into the source of truth and then run the normal compiler/apply flow.
188
+
149
189
  ### Workspaces
150
190
 
151
- Register workspace directories. Workspace rules are compiled into a canonical `AGENTS.md` at the workspace root. Repos keep their own repo-specific `AGENTS.md`; Codex receives the workspace rules through generated, git-excluded `AGENTS.override.md` files, while OpenCode workspace configs reference the shared workspace file through `instructions`. Repo-local app config, skills, and agents are propagated for OpenCode and Codex.
191
+ Register workspace directories. Workspace rules are compiled into a canonical `AGENTS.md` at the workspace root. Repos keep their own repo-specific `AGENTS.md`; Codex receives the workspace rules through generated, git-excluded `AGENTS.override.md` files, while OpenCode workspace configs reference the shared workspace file through `instructions`. Claude receives generated `CLAUDE.local.md` files and project MCP entries in `~/.claude.json["projects"][absolute_repo_path]["mcpServers"]`. Repo-local app config, skills, and agents are propagated for OpenCode, Codex, and Claude.
152
192
 
153
193
  `.cursor` workspace propagation is intentionally disabled to avoid duplicate MCP initialization when opening multi-root workspaces in Cursor (related issue: https://forum.cursor.com/t/mcp-multi-root-workspace-causes-duplicate-mcp-server-initialization-4x-createclient-actions/144003).
154
194
 
@@ -175,6 +215,7 @@ Migrate existing config from any supported editor into the hub.
175
215
  ```bash
176
216
  code-agnostic import plan -a codex
177
217
  code-agnostic import apply -a codex
218
+ code-agnostic import plan -a claude
178
219
  code-agnostic import apply -a cursor --include mcp --on-conflict overwrite
179
220
  code-agnostic import plan -a codex -i # interactive TUI picker
180
221
  ```
@@ -187,13 +228,12 @@ All commands use named flags (`-a`, `-w`, `-v`). Singular aliases work too: `app
187
228
 
188
229
  The compiler migration is documented in:
189
230
 
190
- - [ROADMAP.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/ROADMAP.md)
191
- - [docs/compiler/overview.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/overview.md)
192
- - [docs/compiler/skills.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/skills.md)
193
- - [docs/compiler/agents.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/agents.md)
194
- - [docs/compiler/rules.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/rules.md)
195
- - [docs/compiler/mcp.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/mcp.md)
196
- - [docs/compiler/lossiness.md](/Users/alexeyartishevsky/PycharmProjects/llm-sync/docs/compiler/lossiness.md)
231
+ - [docs/compiler/overview.md](docs/compiler/overview.md)
232
+ - [docs/compiler/skills.md](docs/compiler/skills.md)
233
+ - [docs/compiler/agents.md](docs/compiler/agents.md)
234
+ - [docs/compiler/rules.md](docs/compiler/rules.md)
235
+ - [docs/compiler/mcp.md](docs/compiler/mcp.md)
236
+ - [docs/compiler/lossiness.md](docs/compiler/lossiness.md)
197
237
 
198
238
  ## Roadmap
199
239
 
@@ -208,7 +248,8 @@ The compiler migration is documented in:
208
248
  - [x] Cross-compilation for skills and agents
209
249
  - [x] Per-workspace git-exclude customization
210
250
  - [x] Interactive TUI for import selection
211
- - [ ] Claude Code support
251
+ - [x] Claude Code support
252
+ - [ ] Project-scoped skill installs and sync
212
253
  - [ ] `rules add` / `skills add` / `agents add` commands (open `$EDITOR` with template)
213
254
  - [ ] Planner integration for cross-compiled skills and agents
214
255
  - [ ] Shell auto-complete
@@ -220,3 +261,38 @@ The compiler migration is documented in:
220
261
  uv sync --dev
221
262
  uv run pytest
222
263
  ```
264
+
265
+ Before pushing release-prep work, run the supported Python matrix locally. Tox
266
+ delegates each environment to `uv run --python`, so `uv` can provide the
267
+ requested interpreter when it is not already installed:
268
+
269
+ ```bash
270
+ uvx tox run -p auto
271
+ uvx tox run -e uv310 -- tests/test_version.py -q
272
+ ```
273
+
274
+ For a hermetic Linux matrix that does not depend on locally installed Python
275
+ versions, run the Docker matrix:
276
+
277
+ ```bash
278
+ ./scripts/run-docker-matrix.sh
279
+ ./scripts/run-docker-matrix.sh tests/test_version.py -q
280
+ ```
281
+
282
+ Limit the Docker matrix while iterating:
283
+
284
+ ```bash
285
+ PYTHON_VERSIONS="3.10 3.14" ./scripts/run-docker-matrix.sh tests/test_version.py -q
286
+ ```
287
+
288
+ The release gate still requires GitHub Actions to pass because the published
289
+ workflow is the source of truth for OS coverage across Ubuntu, macOS, and
290
+ Windows on every supported Python version.
291
+
292
+ Real app-ingestion E2E is gated because it requires installed target CLIs and
293
+ uses each tool's own introspection surface:
294
+
295
+ ```bash
296
+ CODE_AGNOSTIC_REAL_APP_E2E=1 uv run pytest tests/e2e/test_real_app_ingestion_e2e.py -q
297
+ CODE_AGNOSTIC_REAL_APP_E2E=1 CODE_AGNOSTIC_REAL_APP_TARGETS=codex,opencode,claude uv run pytest tests/e2e/test_real_app_ingestion_e2e.py -q
298
+ ```
@@ -1,3 +1,3 @@
1
1
  __all__ = ["__version__"]
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.3.7"
@@ -48,13 +48,15 @@ cli.add_command(import_group)
48
48
 
49
49
  def main() -> int:
50
50
  try:
51
- cli(standalone_mode=False)
51
+ result = cli(standalone_mode=False)
52
52
  except click.exceptions.Exit as exc:
53
53
  code = exc.exit_code
54
54
  return code if isinstance(code, int) else 1
55
55
  except click.ClickException as exc:
56
56
  exc.show()
57
57
  return 2
58
+ if isinstance(result, int):
59
+ return result
58
60
  return 0
59
61
 
60
62
 
@@ -0,0 +1,67 @@
1
+ """Claude Code subagent Markdown conversion."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import yaml # type: ignore[import-untyped]
10
+
11
+ from code_agnostic.agents.models import Agent
12
+
13
+ _SAFE_FILE_STEM_RE = re.compile(r"[^A-Za-z0-9_-]+")
14
+
15
+
16
+ def normalize_claude_agent_filename(name: str, fallback: str) -> str:
17
+ candidate = name.strip() or fallback.strip()
18
+ normalized = _SAFE_FILE_STEM_RE.sub("-", candidate).strip("-_")
19
+ return normalized or fallback
20
+
21
+
22
+ def serialize_claude_agent(agent: Agent) -> str:
23
+ fm: dict[str, Any] = {}
24
+ if agent.metadata.name:
25
+ fm["name"] = agent.metadata.name
26
+ else:
27
+ fm["name"] = agent.name
28
+
29
+ description = agent.metadata.description or agent.metadata.name or agent.name
30
+ if description:
31
+ fm["description"] = description
32
+
33
+ model = agent.metadata.effective_value("claude", "model")
34
+ if model:
35
+ fm["model"] = model
36
+ reasoning_effort = agent.metadata.effective_value("claude", "reasoning_effort")
37
+ if reasoning_effort:
38
+ fm["effort"] = reasoning_effort
39
+
40
+ for key, value in agent.metadata.app_passthrough(
41
+ "claude",
42
+ consumed_keys={
43
+ "model",
44
+ "reasoning_effort",
45
+ "sandbox_mode",
46
+ "nickname_candidates",
47
+ },
48
+ ).items():
49
+ if key in fm:
50
+ continue
51
+ fm[key] = value
52
+
53
+ parts = [
54
+ "---",
55
+ yaml.dump(fm, default_flow_style=False, sort_keys=False).rstrip(),
56
+ "---",
57
+ "",
58
+ agent.content,
59
+ ]
60
+ return "\n".join(parts)
61
+
62
+
63
+ def claude_agent_target_path(target_dir: Path, agent: Agent) -> Path:
64
+ return (
65
+ target_dir
66
+ / f"{normalize_claude_agent_filename(agent.metadata.name, agent.name)}.md"
67
+ )
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  from abc import ABC, abstractmethod
6
6
 
7
+ from code_agnostic.agents.claude import serialize_claude_agent
7
8
  from code_agnostic.agents.codex import serialize_codex_agent
8
9
  from code_agnostic.agents.models import Agent
9
10
  from code_agnostic.agents.opencode import serialize_opencode_agent
@@ -35,3 +36,10 @@ class CodexAgentCompiler(IAgentCompiler):
35
36
 
36
37
  def compile(self, agent: Agent) -> str:
37
38
  return serialize_codex_agent(agent)
39
+
40
+
41
+ class ClaudeAgentCompiler(IAgentCompiler):
42
+ """Cross-compile for Claude Code subagents."""
43
+
44
+ def compile(self, agent: Agent) -> str:
45
+ return serialize_claude_agent(agent)
@@ -22,25 +22,25 @@ def serialize_opencode_agent(agent: Agent) -> str:
22
22
  if reasoning_effort:
23
23
  fm["reasoningEffort"] = reasoning_effort
24
24
 
25
- tools: dict[str, Any] = {}
26
- if agent.metadata.tools.read is not True:
27
- tools["read"] = agent.metadata.tools.read
28
- if agent.metadata.tools.write is not True:
29
- tools["write"] = agent.metadata.tools.write
30
- if agent.metadata.tools.mcp:
31
- tools["mcp"] = agent.metadata.tools.mcp
32
- if tools:
33
- fm["tools"] = tools
34
-
35
- for key, value in agent.metadata.app_passthrough(
25
+ passthrough = agent.metadata.app_passthrough(
36
26
  "opencode",
37
27
  consumed_keys={
38
28
  "model",
39
29
  "reasoning_effort",
40
30
  "sandbox_mode",
41
31
  "nickname_candidates",
32
+ "permission",
42
33
  },
43
- ).items():
34
+ )
35
+
36
+ permission = _merge_permission(
37
+ _compile_permission(agent),
38
+ agent.metadata.app_overrides.get("opencode", {}).get("permission"),
39
+ )
40
+ if permission:
41
+ fm["permission"] = permission
42
+
43
+ for key, value in passthrough.items():
44
44
  if key in fm:
45
45
  continue
46
46
  fm[key] = value
@@ -54,3 +54,27 @@ def serialize_opencode_agent(agent: Agent) -> str:
54
54
 
55
55
  parts.append(agent.content)
56
56
  return "\n".join(parts)
57
+
58
+
59
+ def _compile_permission(agent: Agent) -> dict[str, Any]:
60
+ permission: dict[str, Any] = {}
61
+ permission["read"] = "allow" if agent.metadata.tools.read else "deny"
62
+ permission["edit"] = "allow" if agent.metadata.tools.write else "deny"
63
+ for item in agent.metadata.tools.mcp:
64
+ server = item.get("server")
65
+ if not server:
66
+ continue
67
+ tool = item.get("tool")
68
+ key = f"{server}_{tool}" if tool else f"{server}_*"
69
+ permission[key] = "allow"
70
+ return permission
71
+
72
+
73
+ def _merge_permission(
74
+ generated: dict[str, Any], override: Any | None
75
+ ) -> dict[str, Any] | Any:
76
+ if override is None:
77
+ return generated
78
+ if isinstance(override, dict):
79
+ return {**generated, **override}
80
+ return override
@@ -19,7 +19,7 @@ from code_agnostic.agents.models import (
19
19
  from code_agnostic.spec.loaders import load_agent_bundle
20
20
 
21
21
  _FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
22
- _APP_OVERRIDE_PREFIXES = ("cursor", "codex", "opencode")
22
+ _APP_OVERRIDE_PREFIXES = ("cursor", "codex", "opencode", "claude")
23
23
 
24
24
 
25
25
  def parse_agent(path: Path) -> Agent: