claude-dev-env 2.13.0 → 2.14.1
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.
- package/AGENTS.md +135 -0
- package/CLAUDE.md +1 -57
- package/_shared/AGENTS.md +15 -0
- package/_shared/CLAUDE.md +1 -15
- package/_shared/advisor/AGENTS.md +22 -0
- package/_shared/advisor/CLAUDE.md +1 -22
- package/_shared/pr-loop/AGENTS.md +27 -0
- package/_shared/pr-loop/CLAUDE.md +1 -27
- package/_shared/pr-loop/scripts/AGENTS.md +35 -0
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -35
- package/_shared/pr-loop/scripts/code_rules_gate_parts/AGENTS.md +42 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +1 -42
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/AGENTS.md +26 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -26
- package/_shared/pr-loop/scripts/tests/AGENTS.md +44 -0
- package/_shared/pr-loop/scripts/tests/CLAUDE.md +1 -44
- package/_shared/process-tree/AGENTS.md +41 -0
- package/_shared/process-tree/CLAUDE.md +1 -41
- package/agents/AGENTS.md +26 -0
- package/agents/CLAUDE.md +1 -31
- package/agents/clean-coder.md +6 -6
- package/agents/test_agent_frontmatter.py +11 -11
- package/audit-rubrics/AGENTS.md +43 -0
- package/audit-rubrics/CLAUDE.md +1 -43
- package/audit-rubrics/category_rubrics/AGENTS.md +37 -0
- package/audit-rubrics/category_rubrics/CLAUDE.md +1 -37
- package/audit-rubrics/prompts/AGENTS.md +37 -0
- package/audit-rubrics/prompts/CLAUDE.md +1 -37
- package/bin/AGENTS.md +112 -0
- package/bin/CLAUDE.md +1 -112
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-constants.mjs +6 -7
- package/bin/install.mjs +24 -5
- package/bin/install.test.mjs +34 -0
- package/commands/AGENTS.md +13 -0
- package/commands/CLAUDE.md +1 -23
- package/docs/AGENTS.md +32 -0
- package/docs/CLAUDE.md +1 -32
- package/docs/CODE_RULES.md +1 -1
- package/docs/imagegen.md +22 -0
- package/docs/references/AGENTS.md +17 -0
- package/docs/references/CLAUDE.md +1 -17
- package/hooks/AGENTS.md +31 -0
- package/hooks/CLAUDE.md +1 -31
- package/hooks/_gh_pr_author_swap_utils.py +14 -0
- package/hooks/advisory/AGENTS.md +16 -0
- package/hooks/advisory/CLAUDE.md +1 -16
- package/hooks/blocking/AGENTS.md +123 -0
- package/hooks/blocking/CLAUDE.md +1 -123
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/AGENTS.md +28 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +1 -28
- package/hooks/blocking/code_rules_banned_identifiers.py +1 -1
- package/hooks/blocking/code_rules_dead_module_constant.py +149 -37
- package/hooks/blocking/code_rules_probe_chains.py +6 -2
- package/hooks/blocking/config/AGENTS.md +10 -0
- package/hooks/blocking/config/CLAUDE.md +1 -10
- package/hooks/blocking/gh_pr_author_restore.py +7 -2
- package/hooks/blocking/intent_only_ending_blocker.py +11 -16
- package/hooks/blocking/inventory_intent_records/AGENTS.md +26 -0
- package/hooks/blocking/inventory_intent_records/CLAUDE.md +1 -26
- package/hooks/blocking/package_inventory_stale_blocker_parts/AGENTS.md +26 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +1 -26
- package/hooks/blocking/pii_prevention_blocker_parts/AGENTS.md +24 -0
- package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +1 -24
- package/hooks/blocking/tdd_enforcer_parts/AGENTS.md +30 -0
- package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +1 -30
- package/hooks/blocking/test_claude_md_orphan_file_blocker.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +171 -0
- package/hooks/blocking/test_code_rules_enforcer_magic_allowlist.py +1 -1
- package/hooks/blocking/test_gh_pr_author_restore.py +2 -1
- package/hooks/blocking/test_intent_only_ending_blocker.py +4 -0
- package/hooks/diagnostic/AGENTS.md +75 -0
- package/hooks/diagnostic/CLAUDE.md +1 -43
- package/hooks/diagnostic/hook_log_extractor.py +2 -2
- package/hooks/diagnostic/hook_log_init.py +2 -2
- package/hooks/diagnostic/migrations/AGENTS.md +16 -0
- package/hooks/diagnostic/migrations/CLAUDE.md +1 -16
- package/hooks/diagnostic/queries/AGENTS.md +19 -0
- package/hooks/diagnostic/queries/CLAUDE.md +1 -19
- package/hooks/diagnostic/test_hook_log_extractor.py +2 -2
- package/hooks/git-hooks/AGENTS.md +31 -0
- package/hooks/git-hooks/CLAUDE.md +1 -31
- package/hooks/git-hooks/git_hooks_constants/AGENTS.md +21 -0
- package/hooks/git-hooks/git_hooks_constants/CLAUDE.md +1 -21
- package/hooks/git-hooks/git_hooks_constants/__init__.py +4 -6
- package/hooks/git-hooks/pre_push.py +47 -34
- package/hooks/git-hooks/test_pre_push.py +111 -7
- package/hooks/hooks_constants/AGENTS.md +104 -0
- package/hooks/hooks_constants/CLAUDE.md +1 -104
- package/hooks/hooks_constants/hook_log_extractor_constants.py +1 -2
- package/hooks/hooks_constants/task_list_loop_starter_constants.py +4 -3
- package/hooks/hooks_constants/working_style_prompt_constants.py +29 -20
- package/hooks/lifecycle/AGENTS.md +18 -0
- package/hooks/lifecycle/CLAUDE.md +1 -18
- package/hooks/observability/AGENTS.md +20 -0
- package/hooks/observability/CLAUDE.md +1 -20
- package/hooks/session/AGENTS.md +33 -0
- package/hooks/session/CLAUDE.md +1 -33
- package/hooks/session/gh_pr_author_session_cleanup.py +7 -2
- package/hooks/session/task_list_loop_starter.py +3 -3
- package/hooks/session/test_gh_pr_author_session_cleanup.py +2 -1
- package/hooks/session/test_task_list_loop_starter.py +10 -2
- package/hooks/session/test_working_style_prompt.py +9 -4
- package/hooks/validation/AGENTS.md +20 -0
- package/hooks/validation/CLAUDE.md +1 -20
- package/hooks/validators/AGENTS.md +51 -0
- package/hooks/validators/CLAUDE.md +1 -51
- package/hooks/validators/health_check.py +52 -19
- package/hooks/validators/python_style_checks.py +1 -1
- package/hooks/validators/test_health_check.py +112 -27
- package/hooks/workflow/AGENTS.md +16 -0
- package/hooks/workflow/CLAUDE.md +1 -16
- package/installable-surfaces.manifest.json +1 -0
- package/output-styles/AGENTS.md +15 -0
- package/output-styles/CLAUDE.md +1 -15
- package/package.json +2 -1
- package/rules/AGENTS.md +61 -0
- package/rules/CLAUDE.md +1 -61
- package/rules/code-standards.md +5 -9
- package/rules/doc-prose-cuts.md +1 -1
- package/scripts/AGENTS.md +62 -0
- package/scripts/CLAUDE.md +1 -62
- package/scripts/codex_compat_materializer.py +4 -0
- package/scripts/dev_env_scripts_constants/AGENTS.md +21 -0
- package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -21
- package/scripts/sync_to_cursor/AGENTS.md +23 -0
- package/scripts/sync_to_cursor/CLAUDE.md +1 -23
- package/scripts/test_active_capability_references.py +2 -2
- package/scripts/test_validate_instruction_pairs.py +90 -0
- package/scripts/test_verify_installable_package.py +5 -1
- package/scripts/tests/AGENTS.md +33 -0
- package/scripts/tests/CLAUDE.md +1 -33
- package/scripts/tests/test_codex_compat_materializer.py +36 -1
- package/scripts/validate_instruction_pairs.py +183 -0
- package/skills/AGENTS.md +72 -0
- package/skills/CLAUDE.md +1 -72
- package/skills/_shared/AGENTS.md +44 -0
- package/skills/_shared/CLAUDE.md +1 -44
- package/skills/_shared/advisor/AGENTS.md +9 -0
- package/skills/_shared/advisor/CLAUDE.md +1 -9
- package/skills/_shared/pr-loop/AGENTS.md +50 -0
- package/skills/_shared/pr-loop/CLAUDE.md +1 -50
- package/skills/_shared/pr-loop/prompts/AGENTS.md +9 -0
- package/skills/_shared/pr-loop/prompts/CLAUDE.md +1 -9
- package/skills/_shared/pr-loop/scripts/AGENTS.md +35 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -35
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +24 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -24
- package/skills/anthropic-plan/AGENTS.md +34 -0
- package/skills/anthropic-plan/CLAUDE.md +1 -34
- package/skills/anthropic-plan/SKILL.md +1 -1
- package/skills/anthropic-plan/scripts/AGENTS.md +11 -0
- package/skills/anthropic-plan/scripts/CLAUDE.md +1 -11
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +16 -0
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/CLAUDE.md +1 -16
- package/skills/anthropic-plan/templates/AGENTS.md +13 -0
- package/skills/anthropic-plan/templates/CLAUDE.md +1 -13
- package/skills/anthropic-plan/test_skill_contract.py +8 -6
- package/skills/anthropic-plan/workflow/AGENTS.md +14 -0
- package/skills/anthropic-plan/workflow/CLAUDE.md +1 -14
- package/skills/auditing-claude-config/AGENTS.md +21 -0
- package/skills/auditing-claude-config/CLAUDE.md +1 -21
- package/skills/autoconverge/AGENTS.md +36 -0
- package/skills/autoconverge/CLAUDE.md +1 -36
- package/skills/autoconverge/reference/AGENTS.md +16 -0
- package/skills/autoconverge/reference/CLAUDE.md +1 -16
- package/skills/autoconverge/workflow/AGENTS.md +26 -0
- package/skills/autoconverge/workflow/CLAUDE.md +1 -26
- package/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +16 -0
- package/skills/autoconverge/workflow/autoconverge_report_constants/CLAUDE.md +1 -16
- package/skills/bugteam/AGENTS.md +30 -0
- package/skills/bugteam/CLAUDE.md +1 -30
- package/skills/bugteam/reference/AGENTS.md +20 -0
- package/skills/bugteam/reference/CLAUDE.md +1 -20
- package/skills/bugteam/reference/obstacles/AGENTS.md +24 -0
- package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -24
- package/skills/bugteam/scripts/AGENTS.md +30 -0
- package/skills/bugteam/scripts/CLAUDE.md +1 -30
- package/skills/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +18 -0
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +1 -18
- package/skills/closeout/reference/handoff-prompt-template.md +1 -1
- package/skills/codex-review/AGENTS.md +46 -0
- package/skills/codex-review/CLAUDE.md +1 -46
- package/skills/codex-review/reference/AGENTS.md +15 -0
- package/skills/codex-review/reference/CLAUDE.md +1 -15
- package/skills/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +18 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +1 -18
- package/skills/codex-review/test_skill_scaffold.py +3 -3
- package/skills/copilot-review/AGENTS.md +18 -0
- package/skills/copilot-review/CLAUDE.md +1 -18
- package/skills/everything-search/AGENTS.md +17 -0
- package/skills/everything-search/CLAUDE.md +1 -17
- package/skills/fresh-branch/AGENTS.md +14 -0
- package/skills/fresh-branch/CLAUDE.md +1 -14
- package/skills/grok-spawn/AGENTS.md +28 -0
- package/skills/grok-spawn/CLAUDE.md +1 -28
- package/skills/pr-converge/AGENTS.md +32 -0
- package/skills/pr-converge/CLAUDE.md +1 -32
- package/skills/pr-converge/pr_converge_skill_constants/AGENTS.md +26 -0
- package/skills/pr-converge/pr_converge_skill_constants/CLAUDE.md +1 -26
- package/skills/pr-converge/reference/AGENTS.md +28 -0
- package/skills/pr-converge/reference/CLAUDE.md +1 -28
- package/skills/pr-converge/reference/obstacles/AGENTS.md +23 -0
- package/skills/pr-converge/reference/obstacles/CLAUDE.md +1 -23
- package/skills/pr-converge/scripts/AGENTS.md +46 -0
- package/skills/pr-converge/scripts/CLAUDE.md +1 -46
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +18 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -18
- package/skills/pr-converge/workflows/AGENTS.md +16 -0
- package/skills/pr-converge/workflows/CLAUDE.md +1 -16
- package/skills/prototype/SKILL.md +1 -2
- package/skills/prototype/reference/honest-limitations.md +1 -1
- package/skills/prototype/reference/promotion-tasks.md +1 -1
- package/skills/prototype/workflows/promotion.md +1 -1
- package/skills/rebase/AGENTS.md +32 -0
- package/skills/rebase/CLAUDE.md +1 -32
- package/skills/recall/AGENTS.md +30 -0
- package/skills/recall/CLAUDE.md +1 -30
- package/skills/remember/AGENTS.md +31 -0
- package/skills/remember/CLAUDE.md +1 -31
- package/skills/reviews/SKILL.md +1 -1
- package/skills/session-log/AGENTS.md +32 -0
- package/skills/session-log/CLAUDE.md +1 -32
- package/skills/session-tidy/AGENTS.md +36 -0
- package/skills/session-tidy/CLAUDE.md +1 -36
- package/skills/skill-builder/AGENTS.md +49 -0
- package/skills/skill-builder/CLAUDE.md +1 -49
- package/skills/skill-builder/references/AGENTS.md +25 -0
- package/skills/skill-builder/references/CLAUDE.md +1 -25
- package/skills/skill-builder/references/deterministic-elements.md +1 -1
- package/skills/skill-builder/templates/AGENTS.md +14 -0
- package/skills/skill-builder/templates/CLAUDE.md +1 -14
- package/skills/skill-builder/workflows/AGENTS.md +19 -0
- package/skills/skill-builder/workflows/CLAUDE.md +1 -19
- package/skills/task-build/AGENTS.md +29 -0
- package/skills/task-build/CLAUDE.md +1 -29
- package/skills/update/AGENTS.md +38 -0
- package/skills/update/CLAUDE.md +1 -38
- package/system-prompts/AGENTS.md +17 -0
- package/system-prompts/CLAUDE.md +1 -17
- package/system-prompts/software-engineer.xml +3 -3
- package/agents/caveman.md +0 -73
- package/agents/clasp-deployment-orchestrator.md +0 -608
- package/agents/code-advisor.md +0 -23
- package/agents/deep-research.md +0 -152
- package/agents/docs-agent.md +0 -85
- package/commands/commit.md +0 -28
- package/commands/docupdate.md +0 -322
- package/commands/hook-log-extract.md +0 -70
- package/commands/hook-log-init.md +0 -76
- package/commands/implement.md +0 -102
- package/commands/plan.md +0 -14
- package/commands/pr-comments.md +0 -47
- package/commands/review-plan.md +0 -5
- package/commands/right-size.md +0 -15
- package/commands/sum.md +0 -30
- package/skills/imagegen/SKILL.md +0 -21
- package/skills/imagegen/scripts/config/__init__.py +0 -1
- package/skills/imagegen/scripts/config/constants.py +0 -28
- package/skills/imagegen/scripts/imagegen.py +0 -45
- package/skills/imagegen/scripts/imagegen_core.py +0 -528
- package/skills/imagegen/scripts/test_imagegen.py +0 -204
|
@@ -1,21 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Named constants for scripts in `scripts/`. Follows the project convention that timeouts, delays, and retries live in `timing.py`.
|
|
4
|
-
|
|
5
|
-
## Modules
|
|
6
|
-
|
|
7
|
-
| File | Constants for |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `timing.py` | `sweep_empty_dirs.py` - `DEFAULT_AGE_SECONDS` (smallest age before an empty directory is eligible for removal) and `DEFAULT_POLL_INTERVAL` (seconds between sweep passes in continuous-watch mode); `spawn_grok_batch.py` - `WORKER_STAGGER_SECONDS` (seconds between staggered headless grok worker starts); `invoke_code_review.py` - `DEFAULT_CODE_REVIEW_TIMEOUT_SECONDS` (timeout for one headless `/code-review` chain run) |
|
|
10
|
-
| `gh_artifact_upload_constants.py` | `gh_artifact_upload.py` - the `artifacts` release tag, title, and notes body, the GitHub CLI binary name, the asset-name timestamp format and template, the asset download URL template, the notes-file suffix, and the text encoding |
|
|
11
|
-
| `claude_chain_constants.py` | `claude_chain_runner.py` - the chain config filename and home subdirectory, the usage-limit signature text, the per-binary status labels, routing-mode tokens (`usage_ranked` / `ordered_account`), outcome `terminal_status` values (`served` / `advisor_blocked` / `chain_exhausted` / `timeout`), the default timeout, CLI flag and separator tokens, config JSON keys (including optional `credentials_path`), invalid-shape reason text, config-error and exhausted-chain message templates, and CLI exit codes (including advisor-blocked); `invoke_code_review.py` and `resolve_worker_spawn.py` - the text-codec keyword names and the `collect_forwarded_text_codec` helper that forwards them to the subprocess runner for text-mode capture |
|
|
12
|
-
| `claude_chain_usage_constants.py` | `claude_chain_usage.py` - full weekly percent scale, usage-pause skill path segments, CLI config-path flag, JSON report keys, and probe error message templates |
|
|
13
|
-
| `grok_worker_constants.py` | `grok_worker_preflight.py`, `grok_headless_runner.py`, `spawn_grok_batch.py`, and `resolve_worker_spawn.py` - the `grok` binary name and CLI flags, model and subcommand tokens, leader-socket and scratch-file name parts, auth and usage-limit signature lists, outcome classifications, fallthrough reasons, tool-profile names and prompt headers, worker timeouts (default, plus the floor and the `MAXIMUM_WORKER_TIMEOUT_SECONDS` ceiling that the batch spec parse, the headless runner, and the spawn dispatcher all enforce, each bound carrying one rejection template shared by those sites, plus launch-failure return code and post-kill grace), the process-tree kill attempt limit and kill-failed classification, the preflight ping's single-turn cap, ping-cache keys and TTL, batch-spec and summary JSON keys, worker-advisor placeholder launcher/model/effort tokens, four verdict signals, MAXIMUM_WORKER_ADVISOR_CORRECTIONS, advisor_blocked classification, and advisor_session_id report keys, the prompt-part and report-stream join separators, and the CLI launch-error stderr prefix |
|
|
14
|
-
| `code_review_constants.py` | `invoke_code_review.py` - the `/code-review ultra --fix` prompt, opus model alias, permission-mode flag and value, result mode and JSON keys, session-model CLI flag, git dirty-check tokens, and in-session return markers; finding severity tokens (`blocker` / `high` / `medium` / `low` / `nit`), verification verdict tokens, loop terminal tokens (`clean` / `nits_fixed` / `advisor_blocked`), and pure helpers for retained-finding checks, head recording, terminal resolution, and terminal encoding |
|
|
15
|
-
| `active_capability_constants.py` | `active_capability_references.py` - package skills/agents/commands directory names, skill manifest filename, ban-listed capability names, inert fence languages, slash and backtick extract patterns, fence open/close patterns, banned-reason prefix, UTF-8 encoding, and newline join separator |
|
|
16
|
-
| `verify_installable_package_constants.py` | `verify_installable_package.py` - manifest filename and keys, npm pack / tarball / plugin-root tokens, git and node smoke argv pieces, surface classification labels, exit codes, and CLI status headers |
|
|
17
|
-
| `__init__.py` | Empty package marker |
|
|
18
|
-
|
|
19
|
-
## Convention
|
|
20
|
-
|
|
21
|
-
Every constant is `UPPER_SNAKE_CASE` with an explicit type annotation and a docstring. Scripts import from here rather than embedding literal values in their bodies. `code_review_constants.py` also exports pure helpers that resolve review-loop terminals from those tokens.
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# sync_to_cursor
|
|
2
|
+
|
|
3
|
+
Python package that syncs Claude rules and docs to Cursor `.mdc` files. Entry point is `packages/claude-dev-env/scripts/sync_to_cursor.py`; this package holds the implementation modules.
|
|
4
|
+
|
|
5
|
+
## Modules
|
|
6
|
+
|
|
7
|
+
| File | Purpose |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `engine.py` | Main sync logic: loads the manifest, builds rule mappings, hashes sources, writes `.mdc` files, and updates the manifest |
|
|
10
|
+
| `rules.py` | Builds `RuleMapping` objects from Claude rule markdown files; applies transforms to fit Cursor's `.mdc` format |
|
|
11
|
+
| `canonical_docs.py` | Checks and syncs canonical documentation files (`CODE_RULES.md`, `TEST_QUALITY.md`) to the Cursor rules directory |
|
|
12
|
+
| `paths.py` | Resolves the Claude and Cursor layout paths; respects the `LLM_SETTINGS_ROOT` env var for non-home layouts |
|
|
13
|
+
| `hashing.py` | SHA-256 helpers that detect whether source files changed since the last sync run |
|
|
14
|
+
| `config.py` | Package-level constants: `GENERATOR_VERSION`, `CANONICAL_DOC_FILES`, `MAX_RULE_BODY_LINES` |
|
|
15
|
+
| `__init__.py` | Empty package marker |
|
|
16
|
+
|
|
17
|
+
## Layout resolution
|
|
18
|
+
|
|
19
|
+
`paths.py` reads `LLM_SETTINGS_ROOT` from the environment. When set, it uses that path as the base for both `.claude/` and `.cursor/`. When unset, it falls back to `Path.home()`.
|
|
20
|
+
|
|
21
|
+
## Tests
|
|
22
|
+
|
|
23
|
+
Tests live in `packages/claude-dev-env/scripts/tests/test_sync_to_cursor.py`.
|
|
@@ -1,23 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Python package that syncs Claude rules and docs to Cursor `.mdc` files. Entry point is `packages/claude-dev-env/scripts/sync_to_cursor.py`; this package holds the implementation modules.
|
|
4
|
-
|
|
5
|
-
## Modules
|
|
6
|
-
|
|
7
|
-
| File | Purpose |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `engine.py` | Main sync logic: loads the manifest, builds rule mappings, hashes sources, writes `.mdc` files, and updates the manifest |
|
|
10
|
-
| `rules.py` | Builds `RuleMapping` objects from Claude rule markdown files; applies transforms to fit Cursor's `.mdc` format |
|
|
11
|
-
| `canonical_docs.py` | Checks and syncs canonical documentation files (`CODE_RULES.md`, `TEST_QUALITY.md`) to the Cursor rules directory |
|
|
12
|
-
| `paths.py` | Resolves the Claude and Cursor layout paths; respects the `LLM_SETTINGS_ROOT` env var for non-home layouts |
|
|
13
|
-
| `hashing.py` | SHA-256 helpers that detect whether source files changed since the last sync run |
|
|
14
|
-
| `config.py` | Package-level constants: `GENERATOR_VERSION`, `CANONICAL_DOC_FILES`, `MAX_RULE_BODY_LINES` |
|
|
15
|
-
| `__init__.py` | Empty package marker |
|
|
16
|
-
|
|
17
|
-
## Layout resolution
|
|
18
|
-
|
|
19
|
-
`paths.py` reads `LLM_SETTINGS_ROOT` from the environment. When set, it uses that path as the base for both `.claude/` and `.cursor/`. When unset, it falls back to `Path.home()`.
|
|
20
|
-
|
|
21
|
-
## Tests
|
|
22
|
-
|
|
23
|
-
Tests live in `packages/claude-dev-env/scripts/tests/test_sync_to_cursor.py`.
|
|
1
|
+
@AGENTS.md
|
|
@@ -32,7 +32,7 @@ def test_inventory_includes_shipped_skill_and_agent_names() -> None:
|
|
|
32
32
|
|
|
33
33
|
def test_strip_inert_fenced_blocks_drops_historical_examples() -> None:
|
|
34
34
|
markdown = (
|
|
35
|
-
"Use /
|
|
35
|
+
"Use /sr-loop for cleanup.\n"
|
|
36
36
|
"```historical\n"
|
|
37
37
|
"Use /qbug for bugs.\n"
|
|
38
38
|
"```\n"
|
|
@@ -40,7 +40,7 @@ def test_strip_inert_fenced_blocks_drops_historical_examples() -> None:
|
|
|
40
40
|
)
|
|
41
41
|
stripped = strip_inert_fenced_blocks(markdown)
|
|
42
42
|
assert "/qbug" not in stripped
|
|
43
|
-
assert "/
|
|
43
|
+
assert "/sr-loop" in stripped
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
def test_extract_active_capability_names_finds_slash_and_backticks() -> None:
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from validate_instruction_pairs import validate_repository
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def initialize_repository(repository_root: Path) -> None:
|
|
8
|
+
subprocess.run(["git", "init", "--quiet"], cwd=repository_root, check=True)
|
|
9
|
+
subprocess.run(
|
|
10
|
+
["git", "config", "user.email", "tests@example.com"],
|
|
11
|
+
cwd=repository_root,
|
|
12
|
+
check=True,
|
|
13
|
+
)
|
|
14
|
+
subprocess.run(
|
|
15
|
+
["git", "config", "user.name", "Instruction tests"],
|
|
16
|
+
cwd=repository_root,
|
|
17
|
+
check=True,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def stage_instruction_files(repository_root: Path) -> None:
|
|
22
|
+
subprocess.run(["git", "add", "AGENTS.md", "CLAUDE.md"], cwd=repository_root, check=True)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_exact_import_passes(tmp_path: Path) -> None:
|
|
26
|
+
initialize_repository(tmp_path)
|
|
27
|
+
(tmp_path / "AGENTS.md").write_bytes(b"# Canonical guidance\n")
|
|
28
|
+
(tmp_path / "CLAUDE.md").write_bytes(b"@AGENTS.md\n")
|
|
29
|
+
stage_instruction_files(tmp_path)
|
|
30
|
+
|
|
31
|
+
assert validate_repository(tmp_path) == []
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_claude_context_fails_exact_import_check(tmp_path: Path) -> None:
|
|
35
|
+
initialize_repository(tmp_path)
|
|
36
|
+
(tmp_path / "AGENTS.md").write_bytes(b"# Canonical guidance\n")
|
|
37
|
+
(tmp_path / "CLAUDE.md").write_bytes(b"@AGENTS.md\n\nExtra context\n")
|
|
38
|
+
stage_instruction_files(tmp_path)
|
|
39
|
+
|
|
40
|
+
all_errors = validate_repository(tmp_path)
|
|
41
|
+
|
|
42
|
+
assert any("exactly import" in each_error for each_error in all_errors)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_nearest_ancestor_import_passes(tmp_path: Path) -> None:
|
|
46
|
+
initialize_repository(tmp_path)
|
|
47
|
+
nested_directory = tmp_path / ".claude"
|
|
48
|
+
nested_directory.mkdir()
|
|
49
|
+
(tmp_path / "AGENTS.md").write_bytes(b"# Canonical guidance\n")
|
|
50
|
+
(nested_directory / "CLAUDE.md").write_bytes(b"@../AGENTS.md\n")
|
|
51
|
+
subprocess.run(["git", "add", "AGENTS.md", ".claude/CLAUDE.md"], cwd=tmp_path, check=True)
|
|
52
|
+
|
|
53
|
+
assert validate_repository(tmp_path) == []
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_crlf_import_fails_line_ending_check(tmp_path: Path) -> None:
|
|
57
|
+
initialize_repository(tmp_path)
|
|
58
|
+
(tmp_path / "AGENTS.md").write_bytes(b"# Canonical guidance\n")
|
|
59
|
+
(tmp_path / "CLAUDE.md").write_bytes(b"@AGENTS.md\r\n")
|
|
60
|
+
stage_instruction_files(tmp_path)
|
|
61
|
+
|
|
62
|
+
all_errors = validate_repository(tmp_path)
|
|
63
|
+
|
|
64
|
+
assert any("exactly import" in each_error for each_error in all_errors)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_executable_import_fails_git_mode_check(tmp_path: Path) -> None:
|
|
68
|
+
initialize_repository(tmp_path)
|
|
69
|
+
(tmp_path / "AGENTS.md").write_bytes(b"# Canonical guidance\n")
|
|
70
|
+
(tmp_path / "CLAUDE.md").write_bytes(b"@AGENTS.md\n")
|
|
71
|
+
stage_instruction_files(tmp_path)
|
|
72
|
+
subprocess.run(
|
|
73
|
+
["git", "update-index", "--chmod=+x", "CLAUDE.md"],
|
|
74
|
+
cwd=tmp_path,
|
|
75
|
+
check=True,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
all_errors = validate_repository(tmp_path)
|
|
79
|
+
|
|
80
|
+
assert any("Git mode 100644" in each_error for each_error in all_errors)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_untracked_import_fails_tracking_check(tmp_path: Path) -> None:
|
|
84
|
+
initialize_repository(tmp_path)
|
|
85
|
+
(tmp_path / "AGENTS.md").write_bytes(b"# Canonical guidance\n")
|
|
86
|
+
(tmp_path / "CLAUDE.md").write_bytes(b"@AGENTS.md\n")
|
|
87
|
+
|
|
88
|
+
all_errors = validate_repository(tmp_path)
|
|
89
|
+
|
|
90
|
+
assert any("Git mode 100644" in each_error for each_error in all_errors)
|
|
@@ -31,6 +31,7 @@ def test_load_manifest_lists_hooks_and_claude_md() -> None:
|
|
|
31
31
|
all_root_files = mod.required_root_file_names(manifest)
|
|
32
32
|
assert "hooks" in all_directories
|
|
33
33
|
assert "output-styles" in all_directories
|
|
34
|
+
assert "AGENTS.md" in all_root_files
|
|
34
35
|
assert "CLAUDE.md" in all_root_files
|
|
35
36
|
assert MANIFEST_FILENAME in all_root_files
|
|
36
37
|
|
|
@@ -58,10 +59,12 @@ def test_surface_appears_in_tarball_members_for_directory_children() -> None:
|
|
|
58
59
|
all_members = frozenset(
|
|
59
60
|
{
|
|
60
61
|
f"{TARBALL_PACKAGE_PREFIX}hooks/hooks.json",
|
|
62
|
+
f"{TARBALL_PACKAGE_PREFIX}AGENTS.md",
|
|
61
63
|
f"{TARBALL_PACKAGE_PREFIX}CLAUDE.md",
|
|
62
64
|
}
|
|
63
65
|
)
|
|
64
66
|
assert mod.surface_appears_in_tarball_members("hooks", all_members)
|
|
67
|
+
assert mod.surface_appears_in_tarball_members("AGENTS.md", all_members)
|
|
65
68
|
assert mod.surface_appears_in_tarball_members("CLAUDE.md", all_members)
|
|
66
69
|
assert not mod.surface_appears_in_tarball_members("missing-dir", all_members)
|
|
67
70
|
|
|
@@ -69,11 +72,12 @@ def test_surface_appears_in_tarball_members_for_directory_children() -> None:
|
|
|
69
72
|
def test_missing_manifest_surfaces_in_tarball_reports_absent_root_file() -> None:
|
|
70
73
|
manifest = {
|
|
71
74
|
"directories": ["hooks"],
|
|
72
|
-
"root_files": ["CLAUDE.md", "codex-capability-map.json"],
|
|
75
|
+
"root_files": ["AGENTS.md", "CLAUDE.md", "codex-capability-map.json"],
|
|
73
76
|
}
|
|
74
77
|
all_members = frozenset(
|
|
75
78
|
{
|
|
76
79
|
f"{TARBALL_PACKAGE_PREFIX}hooks/hooks.json",
|
|
80
|
+
f"{TARBALL_PACKAGE_PREFIX}AGENTS.md",
|
|
77
81
|
f"{TARBALL_PACKAGE_PREFIX}CLAUDE.md",
|
|
78
82
|
}
|
|
79
83
|
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# scripts/tests
|
|
2
|
+
|
|
3
|
+
pytest suite for the Python scripts and Pester suite for the PowerShell scripts in `scripts/`.
|
|
4
|
+
|
|
5
|
+
## Test files
|
|
6
|
+
|
|
7
|
+
| File | Covers |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `test_setup_project_paths.py` | `setup_project_paths.py` — discovery, filtering, and `project-paths.json` writing |
|
|
10
|
+
| `test_setup_project_paths_config.py` | Configuration constants used by `setup_project_paths.py` |
|
|
11
|
+
| `test_sweep_empty_dirs.py` | `sweep_empty_dirs.py` — age check, one-shot mode, and continuous-watch behavior |
|
|
12
|
+
| `test_sync_to_cursor.py` | `sync_to_cursor/` package — mapping, hashing, manifest, and path resolution |
|
|
13
|
+
| `test_grok_worker_constants.py` | `grok_worker_constants.py` — the accepted batch worker-key set stays in step with the worker key constants, and the unknown-key message names both its placeholders |
|
|
14
|
+
|
|
15
|
+
## PowerShell test files
|
|
16
|
+
|
|
17
|
+
| File | Covers |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `Get-SessionAccount.Tests.ps1` | `Get-SessionAccount.ps1` — noise filtering, profile-storage email recovery, CLI-vs-desktop account resolution, and output formatting |
|
|
20
|
+
|
|
21
|
+
## Running
|
|
22
|
+
|
|
23
|
+
Python scripts (pytest):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
python -m pytest packages/claude-dev-env/scripts/tests/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
PowerShell scripts (Pester 5+, `*.Tests.ps1`):
|
|
30
|
+
|
|
31
|
+
```powershell
|
|
32
|
+
Invoke-Pester -Path packages/claude-dev-env/scripts/tests/
|
|
33
|
+
```
|
package/scripts/tests/CLAUDE.md
CHANGED
|
@@ -1,33 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
pytest suite for the Python scripts and Pester suite for the PowerShell scripts in `scripts/`.
|
|
4
|
-
|
|
5
|
-
## Test files
|
|
6
|
-
|
|
7
|
-
| File | Covers |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `test_setup_project_paths.py` | `setup_project_paths.py` — discovery, filtering, and `project-paths.json` writing |
|
|
10
|
-
| `test_setup_project_paths_config.py` | Configuration constants used by `setup_project_paths.py` |
|
|
11
|
-
| `test_sweep_empty_dirs.py` | `sweep_empty_dirs.py` — age check, one-shot mode, and continuous-watch behavior |
|
|
12
|
-
| `test_sync_to_cursor.py` | `sync_to_cursor/` package — mapping, hashing, manifest, and path resolution |
|
|
13
|
-
| `test_grok_worker_constants.py` | `grok_worker_constants.py` — the accepted batch worker-key set stays in step with the worker key constants, and the unknown-key message names both its placeholders |
|
|
14
|
-
|
|
15
|
-
## PowerShell test files
|
|
16
|
-
|
|
17
|
-
| File | Covers |
|
|
18
|
-
|---|---|
|
|
19
|
-
| `Get-SessionAccount.Tests.ps1` | `Get-SessionAccount.ps1` — noise filtering, profile-storage email recovery, CLI-vs-desktop account resolution, and output formatting |
|
|
20
|
-
|
|
21
|
-
## Running
|
|
22
|
-
|
|
23
|
-
Python scripts (pytest):
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
python -m pytest packages/claude-dev-env/scripts/tests/
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
PowerShell scripts (Pester 5+, `*.Tests.ps1`):
|
|
30
|
-
|
|
31
|
-
```powershell
|
|
32
|
-
Invoke-Pester -Path packages/claude-dev-env/scripts/tests/
|
|
33
|
-
```
|
|
1
|
+
@AGENTS.md
|
|
@@ -77,6 +77,42 @@ def test_discover_agents_returns_sorted_parsed_agents(tmp_path: Path) -> None:
|
|
|
77
77
|
assert [agent.name for agent in agents] == ["Alpha", "Zulu"]
|
|
78
78
|
|
|
79
79
|
|
|
80
|
+
def test_discover_agents_skips_instruction_aliases_and_keeps_real_agents(
|
|
81
|
+
tmp_path: Path,
|
|
82
|
+
) -> None:
|
|
83
|
+
source = tmp_path / "source"
|
|
84
|
+
source.mkdir()
|
|
85
|
+
(source / "real-agent.md").write_text(
|
|
86
|
+
"---\nname: Real Agent\ndescription: real\n---\n",
|
|
87
|
+
encoding="utf-8",
|
|
88
|
+
)
|
|
89
|
+
(source / "CLAUDE.md").write_text("# Guidance\n", encoding="utf-8")
|
|
90
|
+
try:
|
|
91
|
+
(source / "AGENTS.md").symlink_to("CLAUDE.md")
|
|
92
|
+
except OSError as error:
|
|
93
|
+
pytest.skip(f"symlinks unavailable: {error}")
|
|
94
|
+
|
|
95
|
+
agents = materializer.discover_agents(MaterializerConfig(source, tmp_path / "target"))
|
|
96
|
+
|
|
97
|
+
assert [agent.name for agent in agents] == ["Real Agent"]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_discover_agents_rejects_non_alias_reparse_points(tmp_path: Path) -> None:
|
|
101
|
+
source = tmp_path / "source"
|
|
102
|
+
source.mkdir()
|
|
103
|
+
(source / "real-agent.md").write_text(
|
|
104
|
+
"---\nname: Real Agent\ndescription: real\n---\n",
|
|
105
|
+
encoding="utf-8",
|
|
106
|
+
)
|
|
107
|
+
try:
|
|
108
|
+
(source / "linked-agent.md").symlink_to("real-agent.md")
|
|
109
|
+
except OSError as error:
|
|
110
|
+
pytest.skip(f"symlinks unavailable: {error}")
|
|
111
|
+
|
|
112
|
+
with pytest.raises(MaterializerError, match="source reparse point is not allowed"):
|
|
113
|
+
materializer.discover_agents(MaterializerConfig(source, tmp_path / "target"))
|
|
114
|
+
|
|
115
|
+
|
|
80
116
|
def test_content_to_bytes_preserves_bytes_and_encodes_text() -> None:
|
|
81
117
|
assert content_to_bytes(b"payload") == b"payload"
|
|
82
118
|
assert content_to_bytes("payload") == b"payload"
|
|
@@ -662,4 +698,3 @@ def test_frontmatter_rejects_non_string_name() -> None:
|
|
|
662
698
|
"---\nname: 1\ndescription: y\n---\n",
|
|
663
699
|
"bad.md",
|
|
664
700
|
)
|
|
665
|
-
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Validate exact Claude instruction imports and regular Git file modes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
import stat
|
|
9
|
+
import subprocess
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
git_directory_name = ".git"
|
|
13
|
+
git_listing_commands = (
|
|
14
|
+
(("git", "ls-files", "--stage", "-z"), True),
|
|
15
|
+
(("git", "ls-files", "--others", "--exclude-standard", "-z"), False),
|
|
16
|
+
)
|
|
17
|
+
ascii_encoding_name = "ascii"
|
|
18
|
+
utf8_encoding_name = "utf-8"
|
|
19
|
+
regular_git_file_mode = "100644"
|
|
20
|
+
canonical_instruction_names = frozenset(("AGENTS.md", "CLAUDE.md"))
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _read_git_paths_and_modes(
|
|
25
|
+
repository_root: Path,
|
|
26
|
+
) -> tuple[set[Path], dict[Path, set[str]]]:
|
|
27
|
+
all_git_paths: set[Path] = set()
|
|
28
|
+
modes_by_path: dict[Path, set[str]] = {}
|
|
29
|
+
for each_command, each_has_git_mode in git_listing_commands:
|
|
30
|
+
completed_process = subprocess.run(
|
|
31
|
+
each_command,
|
|
32
|
+
cwd=repository_root,
|
|
33
|
+
capture_output=True,
|
|
34
|
+
check=True,
|
|
35
|
+
)
|
|
36
|
+
for each_record in completed_process.stdout.split(b"\0"):
|
|
37
|
+
if not each_record:
|
|
38
|
+
continue
|
|
39
|
+
if each_has_git_mode:
|
|
40
|
+
each_header, each_path_bytes = each_record.split(b"\t", 1)
|
|
41
|
+
each_mode = each_header.split(b" ", 1)[0].decode(ascii_encoding_name)
|
|
42
|
+
each_path = repository_root / Path(os.fsdecode(each_path_bytes))
|
|
43
|
+
modes_by_path.setdefault(each_path, set()).add(each_mode)
|
|
44
|
+
else:
|
|
45
|
+
each_path = repository_root / Path(os.fsdecode(each_record))
|
|
46
|
+
all_git_paths.add(each_path)
|
|
47
|
+
return all_git_paths, modes_by_path
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _discover_named_files(
|
|
51
|
+
repository_root: Path,
|
|
52
|
+
all_git_paths: set[Path],
|
|
53
|
+
expected_name: str,
|
|
54
|
+
) -> list[Path]:
|
|
55
|
+
all_candidate_paths = set(all_git_paths)
|
|
56
|
+
all_candidate_paths.update(repository_root.rglob("*"))
|
|
57
|
+
return sorted(
|
|
58
|
+
each_path
|
|
59
|
+
for each_path in all_candidate_paths
|
|
60
|
+
if git_directory_name not in each_path.parts
|
|
61
|
+
and each_path.name.casefold() == expected_name.casefold()
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _find_nearest_agents_path(
|
|
66
|
+
claude_path: Path,
|
|
67
|
+
repository_root: Path,
|
|
68
|
+
agents_by_directory: dict[Path, Path],
|
|
69
|
+
) -> Path | None:
|
|
70
|
+
each_directory = claude_path.parent
|
|
71
|
+
while True:
|
|
72
|
+
each_agents_path = agents_by_directory.get(each_directory)
|
|
73
|
+
if each_agents_path is not None:
|
|
74
|
+
return each_agents_path
|
|
75
|
+
if each_directory == repository_root:
|
|
76
|
+
return None
|
|
77
|
+
each_directory = each_directory.parent
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _relative_import_path(claude_path: Path, agents_path: Path) -> str:
|
|
81
|
+
return Path(os.path.relpath(agents_path, claude_path.parent)).as_posix()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _expected_import_text(claude_path: Path, agents_path: Path) -> bytes:
|
|
85
|
+
return f"@{_relative_import_path(claude_path, agents_path)}\n".encode(
|
|
86
|
+
utf8_encoding_name
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _is_regular_file(each_path: Path) -> bool:
|
|
91
|
+
try:
|
|
92
|
+
return stat.S_ISREG(each_path.lstat().st_mode)
|
|
93
|
+
except FileNotFoundError:
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def validate_repository(repository_root: Path) -> list[str]:
|
|
98
|
+
"""Validate instruction filenames, modes, and exact Claude imports.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
repository_root: Repository directory containing the Git metadata.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Human-readable validation errors, with an empty list for a valid tree.
|
|
105
|
+
"""
|
|
106
|
+
repository_root = repository_root.resolve()
|
|
107
|
+
all_errors: list[str] = []
|
|
108
|
+
all_git_paths, modes_by_path = _read_git_paths_and_modes(repository_root)
|
|
109
|
+
all_agents_paths = _discover_named_files(
|
|
110
|
+
repository_root, all_git_paths, "AGENTS.md"
|
|
111
|
+
)
|
|
112
|
+
all_claude_paths = _discover_named_files(
|
|
113
|
+
repository_root, all_git_paths, "CLAUDE.md"
|
|
114
|
+
)
|
|
115
|
+
agents_by_directory = {
|
|
116
|
+
each_path.parent: each_path
|
|
117
|
+
for each_path in all_agents_paths
|
|
118
|
+
if each_path.name == "AGENTS.md"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for each_instruction_path in (*all_agents_paths, *all_claude_paths):
|
|
122
|
+
relative_path = each_instruction_path.relative_to(repository_root)
|
|
123
|
+
tracked_modes = modes_by_path.get(each_instruction_path, set())
|
|
124
|
+
if each_instruction_path.name not in canonical_instruction_names:
|
|
125
|
+
all_errors.append(f"Use the canonical filename: {relative_path}")
|
|
126
|
+
if not _is_regular_file(each_instruction_path):
|
|
127
|
+
all_errors.append(f"Use a regular file: {relative_path}")
|
|
128
|
+
if tracked_modes != {regular_git_file_mode}:
|
|
129
|
+
all_errors.append(
|
|
130
|
+
f"Commit the instruction file with Git mode 100644: {relative_path}"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
for each_claude_path in all_claude_paths:
|
|
134
|
+
relative_claude_path = each_claude_path.relative_to(repository_root)
|
|
135
|
+
each_agents_path = _find_nearest_agents_path(
|
|
136
|
+
each_claude_path, repository_root, agents_by_directory
|
|
137
|
+
)
|
|
138
|
+
if each_agents_path is None:
|
|
139
|
+
all_errors.append(f"Add the nearest governing AGENTS.md: {relative_claude_path}")
|
|
140
|
+
continue
|
|
141
|
+
if not _is_regular_file(each_claude_path):
|
|
142
|
+
continue
|
|
143
|
+
expected_bytes = _expected_import_text(each_claude_path, each_agents_path)
|
|
144
|
+
actual_bytes = each_claude_path.read_bytes()
|
|
145
|
+
if actual_bytes != expected_bytes:
|
|
146
|
+
relative_import_path = _relative_import_path(
|
|
147
|
+
each_claude_path, each_agents_path
|
|
148
|
+
)
|
|
149
|
+
relative_agents_path = each_agents_path.relative_to(repository_root)
|
|
150
|
+
all_errors.append(
|
|
151
|
+
f"Make {relative_claude_path} exactly import "
|
|
152
|
+
f"@{relative_import_path} for {relative_agents_path}"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return all_errors
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _parse_arguments() -> argparse.Namespace:
|
|
159
|
+
argument_parser = argparse.ArgumentParser(
|
|
160
|
+
description="Validate exact CLAUDE.md imports and regular AGENTS.md files."
|
|
161
|
+
)
|
|
162
|
+
argument_parser.add_argument(
|
|
163
|
+
"--repository-root",
|
|
164
|
+
type=Path,
|
|
165
|
+
default=Path.cwd(),
|
|
166
|
+
help="Repository root containing the .git directory.",
|
|
167
|
+
)
|
|
168
|
+
return argument_parser.parse_args()
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _main() -> int:
|
|
172
|
+
parsed_arguments = _parse_arguments()
|
|
173
|
+
repository_root = parsed_arguments.repository_root.resolve()
|
|
174
|
+
all_errors = validate_repository(repository_root)
|
|
175
|
+
if all_errors:
|
|
176
|
+
for each_error in all_errors:
|
|
177
|
+
logger.error("%s", each_error)
|
|
178
|
+
return 1
|
|
179
|
+
return 0
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
if __name__ == "__main__":
|
|
183
|
+
raise SystemExit(_main())
|
package/skills/AGENTS.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Skills Directory
|
|
2
|
+
|
|
3
|
+
Each skill is a self-contained folder Claude Code loads on demand. At startup, only the skill's `name` and `description` metadata load. The full `SKILL.md` body and any support files load only when a skill becomes relevant to the conversation.
|
|
4
|
+
|
|
5
|
+
## Skill folder convention
|
|
6
|
+
|
|
7
|
+
| Item | Role |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `SKILL.md` | Required entry point. YAML frontmatter with `name` and `description` (the trigger). Body holds the skill's full instructions. |
|
|
10
|
+
| `scripts/` | Python helper scripts the skill invokes at runtime. |
|
|
11
|
+
| `workflow/` | `.mjs` workflow scripts run via the `Workflow` tool. |
|
|
12
|
+
| `templates/` | Template files the skill or workflow renders at build time. |
|
|
13
|
+
| `reference/` | Reference docs the skill cites or the workflow reads. |
|
|
14
|
+
| `*_constants/` | Python package of named constants imported by `scripts/`. |
|
|
15
|
+
|
|
16
|
+
Skills install to `~/.claude/skills/<skill-name>/` via `packages/claude-dev-env/bin/install.mjs`. See `docs/references/skill-install-system.md` for the install pipeline.
|
|
17
|
+
|
|
18
|
+
## Shared support code
|
|
19
|
+
|
|
20
|
+
**`skills/_shared/`** — skill-local PR-loop helpers plus `@` stubs that name
|
|
21
|
+
canonical homes under **`@~/.claude/_shared/`** (advisor protocol, PR-loop
|
|
22
|
+
contracts, runtime scripts). Map: `skills/_shared/CLAUDE.md`. End-of-run gotchas: `skills/_shared/end-of-run-gotcha-recommendations.md`.
|
|
23
|
+
|
|
24
|
+
## Skill groups
|
|
25
|
+
|
|
26
|
+
**Planning and implementation**
|
|
27
|
+
- `anthropic-plan` — creates a source-grounded plan packet before any code changes
|
|
28
|
+
- `orchestrator` — turns the session into the orchestrator: it spawns executor subagents to do the code edits and test runs; hard decisions go to a shared advisor (Claude warm `session-advisor` via SendMessage; a third-party host: max-tier Claude via CLI Claude-chain)
|
|
29
|
+
- `orchestrator-refresh` — sub-skill fired by the `/orchestrator` loop to re-assert the host-matched shared-advisor discipline mid-run (Claude SendMessage; a third-party host's Claude CLI chain, no Agent-tool advisor spawn)
|
|
30
|
+
- `team-advisor` — binds one advisor at the strongest reachable tier (Claude warm agent; a third-party host: max-tier Claude via CLI Claude-chain, fail closed when unreachable); consult cadence and weight live in `docs/references/advisor-tool.md`
|
|
31
|
+
- `grokify` — builds a paste-ready Grok Build handoff with a Claude advisor charter
|
|
32
|
+
- `grok-spawn` — orchestrator playbook for fleets of headless grok CLI workers (preflight, batch spec, `spawn_grok_batch.py`)
|
|
33
|
+
|
|
34
|
+
**PR review and convergence**
|
|
35
|
+
- `autoconverge` — autonomous single-run workflow that drives a PR to ready
|
|
36
|
+
- `pr-converge` — paced convergence loop across `ScheduleWakeup` ticks
|
|
37
|
+
- `bugteam` — open-loop audit-fix until convergence
|
|
38
|
+
- `copilot-review` — requests and polls a GitHub Copilot review
|
|
39
|
+
- `copilot-finding-triage` — tiers each Copilot gate finding, verifies each code concern with an executed check, then routes it (auto-fix a confirmed defect, resolve a refuted one, page the user only for an inconclusive one)
|
|
40
|
+
- `reviewer-gates` — availability gates for external reviewers (opt-out parse, Copilot quota, Bugbot trigger/detect)
|
|
41
|
+
- `pr-fix-protocol` — applies reviewer findings as verified fixes and drives unresolved review threads to zero
|
|
42
|
+
- `pr-loop-lifecycle` — opens and closes a PR-loop run (grant, teardown, PR description, revoke, report)
|
|
43
|
+
- `pr-loop-cloud-transport` — six-step transport workflow that lets any PR-loop skill run in a session whose `gh` CLI is absent or cannot act on the PR (MCP schema load, origin/HEAD fix, identity rules, the gh-to-MCP substitution matrix, the Copilot status rule, and the post self-check)
|
|
44
|
+
|
|
45
|
+
**Code review guides (Google eng-practices, adapted for an AI reviewer)**
|
|
46
|
+
- `small-cl` — the Small CLs guide; refs: handling reviewer comments
|
|
47
|
+
- `comments` — writing review comments and handling reviewer comments; refs: the review standard, pushback, respectful code reviews
|
|
48
|
+
- `reviews` — the reviewer guide: standard, what to look for, navigating a CL, speed, pushback; refs: CL descriptions, review comments, emergencies, style guides, the two guide indexes
|
|
49
|
+
- `descriptions` — writing good CL descriptions
|
|
50
|
+
- `emergencies` — what counts as an emergency change; refs: what to look for, speed
|
|
51
|
+
- Focused pull request guidance: [`small-cl/SKILL.md`](small-cl/SKILL.md)
|
|
52
|
+
|
|
53
|
+
**Research and discovery**
|
|
54
|
+
- `recall` — retrieves facts from memory files
|
|
55
|
+
- `remember` — saves a decision, gotcha, or architectural choice to the Obsidian vault
|
|
56
|
+
- `everything-search` — file-system search via the Everything `es.exe` CLI
|
|
57
|
+
- `beat-sheet` — reformats a reply as short single-line beats
|
|
58
|
+
- `show` — creates and reviews inline visual explanations: diagrams, interactive widgets, mockups, charts, and illustrations
|
|
59
|
+
|
|
60
|
+
**Session and workflow management**
|
|
61
|
+
- `session-log` — logs a session report to the Obsidian vault
|
|
62
|
+
- `session-tidy` — tidies the session folder
|
|
63
|
+
- `task-build` — gathers open tasks
|
|
64
|
+
- `issue-tracker` — one consistent way to create, update in place, and close GitHub issues for a work-stream: one epic parent with native sub-issues, dedup-first, marker-delimited body sections edited in place, and an epic checklist mirroring the children
|
|
65
|
+
- `closeout` — session-end entry that harvests obstacles into issue-candidate records and delegates filing to the `issue-tracker` agent (skill fallback), keeping the user-validation gate on each draft
|
|
66
|
+
- `privacy-hygiene` — full-repo personal-data and secret sweep plus remediation guide
|
|
67
|
+
- `update` — updates the dev-env package
|
|
68
|
+
- `fresh-branch` — creates a clean branch off main
|
|
69
|
+
- `rebase` — rebases onto main
|
|
70
|
+
- `usage-pause` — waits out the 5-hour usage window in ScheduleWakeup stages that keep agent contexts warm; probes the OAuth usage endpoint or takes a manual reset override
|
|
71
|
+
- `skill-builder` — complete skill-building lifecycle
|
|
72
|
+
- `auditing-claude-config` — audits a Claude Code setup for context-budget waste and produces a migration table with savings
|