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.
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/PKG-INFO +106 -30
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/README.md +105 -29
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/__init__.py +1 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/__main__.py +3 -1
- code_agnostic-0.3.7/code_agnostic/agents/claude.py +67 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/compilers.py +8 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/opencode.py +36 -12
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/parser.py +1 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/app_id.py +15 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/apps_service.py +3 -0
- code_agnostic-0.3.7/code_agnostic/apps/claude/__init__.py +1 -0
- code_agnostic-0.3.7/code_agnostic/apps/claude/config_repository.py +59 -0
- code_agnostic-0.3.7/code_agnostic/apps/claude/mapper.py +86 -0
- code_agnostic-0.3.7/code_agnostic/apps/claude/service.py +248 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/codex/config_repository.py +2 -1
- code_agnostic-0.3.7/code_agnostic/apps/codex/schema.json +5200 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/codex/service.py +8 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/compiled_planning.py +64 -3
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/interfaces/service.py +1 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/loader.py +1 -0
- code_agnostic-0.3.7/code_agnostic/apps/opencode/schema.json +1252 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/opencode/service.py +14 -4
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/skills.py +23 -2
- code_agnostic-0.3.7/code_agnostic/cli/commands/status.py +64 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/helpers.py +6 -7
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/options.py +0 -12
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/constants.py +4 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/core/repository.py +1 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/executor.py +117 -25
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/git_exclude_service.py +33 -3
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/imports/adapters.py +17 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/imports/service.py +10 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/lossiness.py +65 -7
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/models.py +11 -2
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/planner.py +167 -35
- code_agnostic-0.3.7/code_agnostic/skills/compilers.py +107 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/skills/models.py +2 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/skills/parser.py +11 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/loaders.py +12 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/schemas/agent.v1.schema.json +2 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/schemas/rule.v1.schema.json +2 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/schemas/skill.v1.schema.json +2 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/status.py +32 -2
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/renderers.py +55 -8
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/PKG-INFO +106 -30
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/SOURCES.txt +6 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/pyproject.toml +1 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_apply_apps.py +246 -11
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_explain_lossiness.py +37 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_import.py +1 -1
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_plan.py +19 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_skills.py +7 -1
- code_agnostic-0.3.7/tests/test_cli_status.py +155 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_workspaces.py +9 -5
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_common_mcp_to_dto.py +16 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_common_repository.py +4 -5
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_git_exclude_service.py +29 -4
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_planner_executor.py +64 -15
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_sync_plan_model.py +23 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_transactional_executor.py +373 -0
- code_agnostic-0.3.7/tests/test_version.py +15 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_workspace_config_sync.py +388 -31
- code_agnostic-0.3.4/code_agnostic/apps/codex/schema.json +0 -114
- code_agnostic-0.3.4/code_agnostic/apps/opencode/schema.json +0 -7675
- code_agnostic-0.3.4/code_agnostic/cli/commands/status.py +0 -52
- code_agnostic-0.3.4/code_agnostic/skills/compilers.py +0 -39
- code_agnostic-0.3.4/tests/test_cli_status.py +0 -64
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/LICENSE +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/codex.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/agents/models.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/codex/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/codex/mapper.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/codex/schema_repository.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/framework.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/interfaces/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/interfaces/mapper.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/interfaces/repositories.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/models.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/schema.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/symlink_planning.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/common/utils.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/config_repository.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/mapper.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/schema.json +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/schema_repository.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/cursor/service.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/opencode/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/opencode/config_repository.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/opencode/mapper.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/apps/opencode/schema_repository.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/aliases.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/agents.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/apply.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/apps.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/explain_lossiness.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/import_.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/mcp.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/plan.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/restore.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/rules.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/validate.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/cli/commands/workspaces.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/core/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/core/workspace_repository.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/errors.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/imports/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/imports/filesystem.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/imports/models.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/mcp_service.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/rules/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/rules/compilers.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/rules/models.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/rules/parser.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/rules/repository.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/skills/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/schemas/mcp.base.schema.json +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/spec/schemas/mcp.v1.schema.json +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/__init__.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/enums.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/import_selector.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/sections.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/tui/tables.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/utils.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/validation.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic/workspaces.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/dependency_links.txt +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/entry_points.txt +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/requires.txt +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/code_agnostic.egg-info/top_level.txt +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/setup.cfg +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_agents.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_aliases.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_apply_codex.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_apply_cursor.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_apply_target.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_apps.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_flags.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_git_exclude.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_import_interactive.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_mcp.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_module_organization.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_restore.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_rules.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_validate.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_cli_workspace_resolution.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_compiled_planning.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_dto_to_common_mcp.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_mcp_service.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_planner_rules.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_symlink_planning.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_utils.py +0 -0
- {code_agnostic-0.3.4 → code_agnostic-0.3.7}/tests/test_workspace_repo_status.py +0 -0
- {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.
|
|
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
|
|
39
|
+
│ └── python-style/
|
|
40
|
+
│ ├── meta.yaml Rule metadata
|
|
41
|
+
│ └── prompt.md Rule instructions
|
|
40
42
|
├── skills/
|
|
41
|
-
│ └── code-reviewer/
|
|
43
|
+
│ └── code-reviewer/
|
|
44
|
+
│ ├── meta.yaml Skill metadata
|
|
45
|
+
│ └── prompt.md Skill instructions
|
|
42
46
|
└── agents/
|
|
43
|
-
└── architect
|
|
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,
|
|
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
|
|
106
|
-
|
|
|
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`
|
|
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
|
|
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
|
-
- [
|
|
214
|
-
- [docs/compiler/
|
|
215
|
-
- [docs/compiler/
|
|
216
|
-
- [docs/compiler/
|
|
217
|
-
- [docs/compiler/
|
|
218
|
-
- [docs/compiler/
|
|
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
|
-
- [
|
|
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
|
|
16
|
+
│ └── python-style/
|
|
17
|
+
│ ├── meta.yaml Rule metadata
|
|
18
|
+
│ └── prompt.md Rule instructions
|
|
17
19
|
├── skills/
|
|
18
|
-
│ └── code-reviewer/
|
|
20
|
+
│ └── code-reviewer/
|
|
21
|
+
│ ├── meta.yaml Skill metadata
|
|
22
|
+
│ └── prompt.md Skill instructions
|
|
19
23
|
└── agents/
|
|
20
|
-
└── architect
|
|
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,
|
|
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
|
|
83
|
-
|
|
|
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`
|
|
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
|
|
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
|
-
- [
|
|
191
|
-
- [docs/compiler/
|
|
192
|
-
- [docs/compiler/
|
|
193
|
-
- [docs/compiler/
|
|
194
|
-
- [docs/compiler/
|
|
195
|
-
- [docs/compiler/
|
|
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
|
-
- [
|
|
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
|
+
```
|
|
@@ -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
|
-
|
|
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
|
-
)
|
|
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:
|