claude-dev-env 2.3.0 → 2.5.0
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/CLAUDE.md +53 -48
- package/_shared/pr-loop/scripts/_claude_permissions_common.py +84 -0
- package/_shared/pr-loop/scripts/code_rules_gate.py +4 -2
- package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -306
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +44 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -24
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -107
- package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +290 -48
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +42 -2
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +36 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +100 -1
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -497
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +311 -2
- package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -301
- package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -85
- package/_shared/pr-loop/worker-spawn.md +1 -1
- package/agents/CLAUDE.md +3 -1
- package/agents/caveman.md +0 -1
- package/agents/clasp-deployment-orchestrator.md +0 -1
- package/agents/clean-coder.md +0 -1
- package/agents/code-advisor.md +0 -1
- package/agents/code-quality-agent.md +1 -2
- package/agents/code-verifier.md +3 -4
- package/agents/deep-research.md +0 -1
- package/agents/docs-agent.md +0 -1
- package/agents/git-commit-crafter.md +0 -1
- package/agents/issue-tracker.md +42 -0
- package/agents/plan-packet-validator.md +0 -1
- package/agents/pr-description-writer.md +0 -1
- package/agents/skill-writer-agent.md +84 -0
- package/agents/test_agent_frontmatter.py +67 -18
- package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +105 -3
- package/audit-rubrics/prompts/category-o-docstring-vs-impl-drift.md +29 -13
- package/bin/CLAUDE.md +68 -5
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-constants.mjs +88 -0
- package/bin/install.mjs +1138 -114
- package/bin/install.prune.test.mjs +869 -19
- package/bin/install.test.mjs +906 -2
- package/commands/implement.md +1 -1
- package/commands/right-size.md +1 -1
- package/docs/CLAUDE.md +2 -0
- package/docs/host-pool-health-monitor.md +102 -0
- package/docs/references/CLAUDE.md +5 -2
- package/docs/references/advisor-tool.md +13 -0
- package/docs/references/code-review-enforcement.md +107 -0
- package/docs/references/team-advisor-skill.md +14 -0
- package/docs/wsl-docker-cowork-starter-matrix.md +89 -0
- package/hooks/blocking/CLAUDE.md +9 -1
- package/hooks/blocking/code_review_enforcement_config_bootstrap.py +53 -0
- package/hooks/blocking/code_review_gate_deny.py +74 -0
- package/hooks/blocking/code_review_pr_create_gate.py +198 -0
- package/hooks/blocking/code_review_push_gate.py +145 -0
- package/hooks/blocking/code_review_stamp_directory_write_blocker.py +348 -0
- package/hooks/blocking/code_review_stamp_store.py +233 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +7 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +15 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +212 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +138 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +49 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +38 -0
- package/hooks/blocking/code_verifier_spawn_preflight_gate.py +39 -27
- package/hooks/blocking/config/__init__.py +5 -5
- package/hooks/blocking/config/code_review_enforcement_constants.py +113 -0
- package/hooks/blocking/config/test_code_review_enforcement_constants.py +113 -0
- package/hooks/blocking/config/verified_commit_constants.py +160 -155
- package/hooks/blocking/conftest.py +2 -0
- package/hooks/blocking/convergence_gate_blocker.py +112 -23
- package/hooks/blocking/destructive_command_blocker.py +19 -6
- package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +256 -0
- package/hooks/blocking/pr_description_proof_of_work.py +52 -34
- package/hooks/blocking/pre_tool_use_dispatcher.py +24 -24
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +4 -1
- package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +62 -0
- package/hooks/blocking/test_code_review_gate_deny.py +54 -0
- package/hooks/blocking/test_code_review_pr_create_gate.py +199 -0
- package/hooks/blocking/test_code_review_push_gate.py +205 -0
- package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +199 -0
- package/hooks/blocking/test_code_review_stamp_store.py +205 -0
- package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +124 -2
- package/hooks/blocking/test_convergence_gate_blocker.py +153 -5
- package/hooks/blocking/test_destructive_command_blocker.py +1 -1
- package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +45 -0
- package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +231 -0
- package/hooks/blocking/test_pr_description_proof_of_work.py +151 -0
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +17 -8
- package/hooks/blocking/test_verdict_directory_write_blocker.py +808 -808
- package/hooks/blocking/test_verification_verdict_store.py +974 -903
- package/hooks/blocking/test_verified_commit_gate.py +581 -581
- package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -131
- package/hooks/blocking/test_volatile_path_in_post_blocker.py +114 -2
- package/hooks/blocking/verdict_directory_write_blocker.py +687 -687
- package/hooks/blocking/verification_verdict_store.py +1039 -1014
- package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +29 -17
- package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +35 -0
- package/hooks/blocking/verified_commit_message_accuracy_blocker.py +167 -167
- package/hooks/blocking/verifier_verdict_minter.py +280 -280
- package/hooks/blocking/volatile_path_in_post_blocker.py +69 -8
- package/hooks/git-hooks/git_hooks_constants/__init__.py +6 -0
- package/hooks/git-hooks/pre_push.py +89 -2
- package/hooks/git-hooks/test_pre_push.py +128 -0
- package/hooks/hooks.json +26 -1
- package/hooks/hooks_constants/CLAUDE.md +3 -1
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +8 -0
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -0
- package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +26 -11
- package/hooks/hooks_constants/convergence_gate_blocker_constants.py +20 -3
- package/hooks/hooks_constants/destructive_command_segment_constants.py +3 -1
- package/hooks/hooks_constants/enter_worktree_prefetch_constants.py +18 -18
- package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +48 -0
- package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -4
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +4 -0
- package/hooks/hooks_constants/pyproject_config_discovery_constants.py +16 -0
- package/hooks/hooks_constants/ruff_integration_constants.py +16 -0
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +24 -0
- package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +6 -0
- package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +8 -1
- package/hooks/lifecycle/enter_worktree_origin_prefetch.py +163 -146
- package/hooks/lifecycle/test_enter_worktree_origin_prefetch.py +185 -178
- package/hooks/pyproject.toml +1 -0
- package/hooks/validators/CLAUDE.md +2 -0
- package/hooks/validators/config/__init__.py +0 -0
- package/hooks/validators/config/directory_exemption_constants.py +183 -0
- package/hooks/validators/config/test_directory_exemption_constants.py +21 -0
- package/hooks/validators/conftest.py +4 -0
- package/hooks/validators/mypy_integration.py +63 -50
- package/hooks/validators/pyproject_config_discovery.py +101 -0
- package/hooks/validators/ruff_integration.py +257 -25
- package/hooks/validators/run_all_validators.py +223 -19
- package/hooks/validators/test_directory_exemption_constants.py +185 -0
- package/hooks/validators/test_mypy_integration.py +32 -0
- package/hooks/validators/test_pyproject_config_discovery.py +94 -0
- package/hooks/validators/test_python_antipattern_checks.py +110 -5
- package/hooks/validators/test_ruff_integration.py +160 -2
- package/hooks/validators/test_run_all_validators.py +140 -68
- package/hooks/validators/test_run_all_validators_config_discovery.py +123 -0
- package/hooks/validators/test_run_all_validators_pretooluse.py +159 -1
- package/package.json +10 -2
- package/rules/CLAUDE.md +1 -0
- package/rules/docstring-prose-matches-implementation.md +45 -67
- package/rules/durable-post-artifacts.md +7 -0
- package/rules/state-what-is.md +25 -0
- package/rules/verified-commit-gate-skip.md +1 -1
- package/scripts/CLAUDE.md +1 -0
- package/scripts/Capture-PoolHealth.ps1 +410 -0
- package/scripts/_code_review_test_support.py +404 -0
- package/scripts/claude_chain_runner.py +141 -1
- package/scripts/codec_forwarding_test_support.py +83 -0
- package/scripts/conftest.py +23 -0
- package/scripts/dev_env_scripts_constants/CLAUDE.md +2 -2
- package/scripts/dev_env_scripts_constants/claude_chain_constants.py +53 -1
- package/scripts/dev_env_scripts_constants/code_review_constants.py +129 -12
- package/scripts/dev_env_scripts_constants/test_code_review_constants.py +55 -0
- package/scripts/invoke_code_review.py +550 -38
- package/scripts/resolve_worker_spawn.py +626 -619
- package/scripts/spawn_grok_batch.py +672 -672
- package/scripts/test_claude_chain_runner.py +131 -0
- package/scripts/test_invoke_code_review_chain.py +70 -0
- package/scripts/test_invoke_code_review_cli.py +192 -0
- package/scripts/test_invoke_code_review_codec.py +77 -0
- package/scripts/test_invoke_code_review_contract.py +256 -0
- package/scripts/test_invoke_code_review_git.py +123 -0
- package/scripts/test_invoke_code_review_mode.py +99 -0
- package/scripts/test_resolve_worker_spawn.py +1014 -1014
- package/scripts/test_resolve_worker_spawn_codec.py +101 -0
- package/skills/CLAUDE.md +2 -0
- package/skills/auditing-claude-config/SKILL.md +114 -114
- package/skills/autoconverge/SKILL.md +427 -421
- package/skills/autoconverge/reference/convergence.md +26 -4
- package/skills/autoconverge/reference/multi-pr.md +6 -1
- package/skills/autoconverge/reference/stop-conditions.md +16 -10
- package/skills/autoconverge/workflow/CLAUDE.md +1 -0
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +4 -4
- package/skills/autoconverge/workflow/converge.codex-gate.test.mjs +175 -3
- package/skills/autoconverge/workflow/converge.contract.test.mjs +1263 -1244
- package/skills/autoconverge/workflow/converge.mjs +191 -8
- package/skills/autoconverge/workflow/converge.p2-advance.test.mjs +202 -0
- package/skills/autoconverge/workflow/converge_multi.mjs +7 -3
- package/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +5 -0
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +265 -265
- package/skills/closeout/SKILL.md +33 -50
- package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +8 -0
- package/skills/codex-review/scripts/run_codex_review.py +233 -1
- package/skills/codex-review/scripts/test_run_codex_review.py +189 -0
- package/skills/condensing-instructions/SKILL.md +81 -0
- package/skills/copilot-review/SKILL.md +119 -119
- package/skills/e-code-review/SKILL.md +52 -0
- package/skills/e-code-review/reference/fix.md +54 -0
- package/skills/e-code-review/reference/loop.md +43 -0
- package/skills/e-code-review/reference/low.md +57 -0
- package/skills/e-code-review/reference/medium.md +153 -0
- package/skills/e-code-review/reference/xhigh.md +182 -0
- package/skills/e-simplify/SKILL.md +97 -0
- package/skills/fresh-branch/CLAUDE.md +2 -0
- package/skills/fresh-branch/SKILL.md +2 -0
- package/skills/fresh-branch/scripts/create_fresh_branch.py +78 -180
- package/skills/fresh-branch/scripts/fresh_branch_git_commands.py +285 -0
- package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +1 -0
- package/skills/fresh-branch/scripts/pytest.ini +4 -0
- package/skills/fresh-branch/scripts/test_create_fresh_branch.py +98 -0
- package/skills/fresh-branch/scripts/test_fresh_branch_git_commands.py +310 -0
- package/skills/issue-tracker/SKILL.md +92 -0
- package/skills/issue-tracker/reference/epic-and-sub-issue-model.md +55 -0
- package/skills/issue-tracker/reference/handoff-schema.md +64 -0
- package/skills/issue-tracker/reference/operation-matrix.md +41 -0
- package/skills/orchestrator/SKILL.md +162 -21
- package/skills/orchestrator/scripts/status_gate.py +625 -0
- package/skills/orchestrator/scripts/status_gate_constants/__init__.py +1 -0
- package/skills/orchestrator/scripts/status_gate_constants/config/__init__.py +1 -0
- package/skills/orchestrator/scripts/status_gate_constants/config/constants.py +47 -0
- package/skills/orchestrator/scripts/test_status_gate.py +439 -0
- package/skills/orchestrator-refresh/SKILL.md +110 -35
- package/skills/plan-to-pr/SKILL.md +155 -0
- package/skills/plan-to-pr/reference/final-validation-tasks.md +15 -0
- package/skills/plan-to-pr/reference/model-routing.md +36 -0
- package/skills/plan-to-pr/reference/packet-contract.md +43 -0
- package/skills/plan-to-pr/reference/packet-schema.json +57 -0
- package/skills/plan-to-pr/reference/process-inventory.md +22 -0
- package/skills/plan-to-pr/reference/review-loop.md +33 -0
- package/skills/plan-to-pr/reference/run-record.schema.json +27 -0
- package/skills/plan-to-pr/reference/self-audit-tasks.md +15 -0
- package/skills/plan-to-pr/reference/task-seeds.md +14 -0
- package/skills/plan-to-pr/reference/task-ticket.md +38 -0
- package/skills/plan-to-pr/scripts/config/__init__.py +1 -0
- package/skills/plan-to-pr/scripts/config/constants.py +193 -0
- package/skills/plan-to-pr/scripts/create_packet.py +173 -0
- package/skills/plan-to-pr/scripts/test_create_packet.py +102 -0
- package/skills/plan-to-pr/scripts/test_validate_packet.py +256 -0
- package/skills/plan-to-pr/scripts/test_validate_protocol.py +135 -0
- package/skills/plan-to-pr/scripts/test_validate_run.py +158 -0
- package/skills/plan-to-pr/scripts/validate_packet.py +655 -0
- package/skills/plan-to-pr/scripts/validate_protocol.py +622 -0
- package/skills/plan-to-pr/scripts/validate_run.py +173 -0
- package/skills/plan-to-pr/test_skill_contract.py +207 -0
- package/skills/plan-to-pr/test_task_ticket_contract.py +151 -0
- package/skills/pr-converge/SKILL.md +472 -469
- package/skills/pr-converge/reference/examples.md +3 -3
- package/skills/pr-converge/reference/fix-protocol.md +1 -1
- package/skills/pr-converge/reference/ground-rules.md +7 -4
- package/skills/pr-converge/reference/multi-pr-orchestration.md +4 -1
- package/skills/pr-converge/reference/per-tick.md +5 -5
- package/skills/pr-converge/reference/progress-checklist.md +1 -1
- package/skills/pr-converge/scripts/check_convergence_gates.py +279 -279
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -507
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -84
- package/skills/pr-converge/test_step5_host_branch.py +1 -1
- package/skills/pr-fix-protocol/SKILL.md +1 -1
- package/skills/privacy-hygiene/SKILL.md +68 -68
- package/skills/prototype/SKILL.md +86 -0
- package/skills/prototype/reference/honest-limitations.md +23 -0
- package/skills/prototype/reference/promotion-tasks.md +23 -0
- package/skills/prototype/scripts/build_sandbox_settings.py +249 -0
- package/skills/prototype/scripts/conftest.py +15 -0
- package/skills/prototype/scripts/launch_sandbox.py +205 -0
- package/skills/prototype/scripts/probe_sandbox_safety.py +311 -0
- package/skills/prototype/scripts/prototype_scripts_constants/__init__.py +1 -0
- package/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
- package/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +41 -0
- package/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +23 -0
- package/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +45 -0
- package/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +10 -0
- package/skills/prototype/scripts/test_build_sandbox_settings.py +275 -0
- package/skills/prototype/scripts/test_launch_sandbox.py +303 -0
- package/skills/prototype/scripts/test_probe_sandbox_safety.py +284 -0
- package/skills/prototype/workflows/promotion.md +27 -0
- package/skills/prototype/workflows/sandbox.md +35 -0
- package/skills/release-notes-html/SKILL.md +164 -0
- package/skills/skill-builder/CLAUDE.md +3 -3
- package/skills/skill-builder/SKILL.md +5 -5
- package/skills/skill-builder/references/CLAUDE.md +1 -1
- package/skills/skill-builder/references/delegation-map.md +3 -3
- package/skills/skill-builder/references/description-field.md +1 -1
- package/skills/skill-builder/references/skill-modularity.md +2 -3
- package/skills/skill-builder/workflows/CLAUDE.md +1 -1
- package/skills/skill-builder/workflows/improve-skill.md +1 -1
- package/skills/skill-builder/workflows/new-skill.md +2 -2
- package/skills/task-build/CLAUDE.md +8 -7
- package/skills/task-build/SKILL.md +16 -8
- package/skills/task-build/reference/tool-routing.md +19 -0
- package/skills/team-advisor/SKILL.md +2 -2
- package/scripts/test_invoke_code_review.py +0 -672
- package/skills/closeout/reference/issue-body-templates.md +0 -108
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"""Tests for the sandbox safety-hook probe.
|
|
2
|
+
|
|
3
|
+
The block-detection unit tests drive fixture hook scripts, and the
|
|
4
|
+
integration tests point a settings file at the real installed safety hooks
|
|
5
|
+
to prove they block their probe payloads end to end.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import importlib.util
|
|
11
|
+
import json
|
|
12
|
+
import sys
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from types import ModuleType
|
|
15
|
+
|
|
16
|
+
from prototype_scripts_constants.config.build_sandbox_settings_constants import (
|
|
17
|
+
ALL_SAFETY_HOOK_SCRIPT_BASENAMES,
|
|
18
|
+
COMMAND_KEY,
|
|
19
|
+
HOOKS_KEY,
|
|
20
|
+
MATCHER_KEY,
|
|
21
|
+
PRE_TOOL_USE_KEY,
|
|
22
|
+
)
|
|
23
|
+
from prototype_scripts_constants.config.probe_sandbox_safety_constants import (
|
|
24
|
+
DESTRUCTIVE_PROBE_COMMAND,
|
|
25
|
+
ENVELOPE_TOOL_INPUT_KEY,
|
|
26
|
+
ENVELOPE_TOOL_NAME_KEY,
|
|
27
|
+
PII_PROBE_TOKEN_PREFIX,
|
|
28
|
+
PII_PROBE_TOOL_NAME,
|
|
29
|
+
PROBE_FAILURE_EXIT_CODE,
|
|
30
|
+
PROBE_SUCCESS_EXIT_CODE,
|
|
31
|
+
TOOL_INPUT_COMMAND_KEY,
|
|
32
|
+
TOOL_INPUT_CONTENT_KEY,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
SCRIPTS_DIRECTORY = Path(__file__).resolve().parent
|
|
36
|
+
PROBE_PATH = SCRIPTS_DIRECTORY / "probe_sandbox_safety.py"
|
|
37
|
+
HOOKS_BLOCKING_DIRECTORY = SCRIPTS_DIRECTORY.parents[2] / "hooks" / "blocking"
|
|
38
|
+
|
|
39
|
+
PII_HOOK_BASENAME = ALL_SAFETY_HOOK_SCRIPT_BASENAMES[0]
|
|
40
|
+
DESTRUCTIVE_HOOK_BASENAME = ALL_SAFETY_HOOK_SCRIPT_BASENAMES[1]
|
|
41
|
+
|
|
42
|
+
DENY_HOOK_SOURCE = (
|
|
43
|
+
"import json, sys\n"
|
|
44
|
+
"sys.stdout.write(json.dumps("
|
|
45
|
+
'{"hookSpecificOutput": {"permissionDecision": "deny"}}))\n'
|
|
46
|
+
)
|
|
47
|
+
ASK_HOOK_SOURCE = (
|
|
48
|
+
"import json, sys\n"
|
|
49
|
+
"sys.stdout.write(json.dumps("
|
|
50
|
+
'{"hookSpecificOutput": {"permissionDecision": "ask"}}))\n'
|
|
51
|
+
)
|
|
52
|
+
ALLOW_HOOK_SOURCE = "import sys\nsys.exit(0)\n"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def load_probe_module() -> ModuleType:
|
|
56
|
+
spec = importlib.util.spec_from_file_location("probe_sandbox_safety", PROBE_PATH)
|
|
57
|
+
assert spec is not None
|
|
58
|
+
assert spec.loader is not None
|
|
59
|
+
probe_module = importlib.util.module_from_spec(spec)
|
|
60
|
+
spec.loader.exec_module(probe_module)
|
|
61
|
+
return probe_module
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def quoted_command(script_path: Path) -> str:
|
|
65
|
+
return f'"{sys.executable}" "{script_path}"'
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def real_hook_settings_document() -> dict:
|
|
69
|
+
pii_hook_path = HOOKS_BLOCKING_DIRECTORY / PII_HOOK_BASENAME
|
|
70
|
+
destructive_hook_path = HOOKS_BLOCKING_DIRECTORY / DESTRUCTIVE_HOOK_BASENAME
|
|
71
|
+
return {
|
|
72
|
+
HOOKS_KEY: {
|
|
73
|
+
PRE_TOOL_USE_KEY: [
|
|
74
|
+
{
|
|
75
|
+
MATCHER_KEY: "Write",
|
|
76
|
+
HOOKS_KEY: [{COMMAND_KEY: quoted_command(pii_hook_path)}],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
MATCHER_KEY: "Bash",
|
|
80
|
+
HOOKS_KEY: [{COMMAND_KEY: quoted_command(destructive_hook_path)}],
|
|
81
|
+
},
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def real_hook_deny_mode_settings_document() -> dict:
|
|
88
|
+
settings_document = real_hook_settings_document()
|
|
89
|
+
settings_document["env"] = {"CLAUDE_DESTRUCTIVE_DENY_MODE": "1"}
|
|
90
|
+
return settings_document
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def write_settings_file(tmp_path: Path, settings_document: dict) -> Path:
|
|
94
|
+
settings_path = tmp_path / "sandbox-settings.json"
|
|
95
|
+
settings_path.write_text(json.dumps(settings_document), encoding="utf-8")
|
|
96
|
+
return settings_path
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_settings_environment_overrides_reads_the_env_block() -> None:
|
|
100
|
+
probe = load_probe_module()
|
|
101
|
+
environment_overrides = probe.settings_environment_overrides(
|
|
102
|
+
real_hook_deny_mode_settings_document()
|
|
103
|
+
)
|
|
104
|
+
assert environment_overrides == {"CLAUDE_DESTRUCTIVE_DENY_MODE": "1"}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_settings_environment_overrides_empty_without_an_env_block() -> None:
|
|
108
|
+
probe = load_probe_module()
|
|
109
|
+
environment_overrides = probe.settings_environment_overrides(
|
|
110
|
+
real_hook_settings_document()
|
|
111
|
+
)
|
|
112
|
+
assert environment_overrides == {}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_main_exits_zero_when_the_real_destructive_hook_denies_in_deny_mode(
|
|
116
|
+
tmp_path: Path,
|
|
117
|
+
) -> None:
|
|
118
|
+
probe = load_probe_module()
|
|
119
|
+
settings_path = write_settings_file(
|
|
120
|
+
tmp_path, real_hook_deny_mode_settings_document()
|
|
121
|
+
)
|
|
122
|
+
exit_code = probe.main(["--settings", str(settings_path)])
|
|
123
|
+
assert exit_code == PROBE_SUCCESS_EXIT_CODE
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_pii_basename_probe_payload_carries_the_secret() -> None:
|
|
127
|
+
probe = load_probe_module()
|
|
128
|
+
probe_payload = probe.build_probe_payload_for_basename(PII_HOOK_BASENAME)
|
|
129
|
+
assert probe_payload[ENVELOPE_TOOL_NAME_KEY] == PII_PROBE_TOOL_NAME
|
|
130
|
+
content = probe_payload[ENVELOPE_TOOL_INPUT_KEY][TOOL_INPUT_CONTENT_KEY]
|
|
131
|
+
assert PII_PROBE_TOKEN_PREFIX in content
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_destructive_basename_probe_payload_carries_the_command() -> None:
|
|
135
|
+
probe = load_probe_module()
|
|
136
|
+
probe_payload = probe.build_probe_payload_for_basename(DESTRUCTIVE_HOOK_BASENAME)
|
|
137
|
+
command = probe_payload[ENVELOPE_TOOL_INPUT_KEY][TOOL_INPUT_COMMAND_KEY]
|
|
138
|
+
assert command == DESTRUCTIVE_PROBE_COMMAND
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_find_hook_command_for_basename_returns_the_matching_command() -> None:
|
|
142
|
+
probe = load_probe_module()
|
|
143
|
+
settings_document = real_hook_settings_document()
|
|
144
|
+
command = probe.find_hook_command_for_basename(settings_document, PII_HOOK_BASENAME)
|
|
145
|
+
assert command is not None
|
|
146
|
+
assert PII_HOOK_BASENAME in command
|
|
147
|
+
assert probe.find_hook_command_for_basename(settings_document, "absent.py") is None
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_parse_command_argv_splits_and_unquotes_the_command() -> None:
|
|
151
|
+
probe = load_probe_module()
|
|
152
|
+
command_argv = probe.parse_command_argv('"/usr/bin/python" "/a/b hook.py"')
|
|
153
|
+
assert command_argv == ["/usr/bin/python", "/a/b hook.py"]
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_hook_blocks_probe_reports_true_for_a_deny_hook(tmp_path: Path) -> None:
|
|
157
|
+
probe = load_probe_module()
|
|
158
|
+
deny_hook_path = tmp_path / "deny_hook.py"
|
|
159
|
+
deny_hook_path.write_text(DENY_HOOK_SOURCE, encoding="utf-8")
|
|
160
|
+
command_argv = [sys.executable, str(deny_hook_path)]
|
|
161
|
+
probe_payload = probe.build_probe_payload_for_basename(DESTRUCTIVE_HOOK_BASENAME)
|
|
162
|
+
assert probe.hook_blocks_probe(command_argv, probe_payload, {}) is True
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def test_hook_blocks_probe_reports_false_for_an_ask_hook(tmp_path: Path) -> None:
|
|
166
|
+
probe = load_probe_module()
|
|
167
|
+
ask_hook_path = tmp_path / "ask_hook.py"
|
|
168
|
+
ask_hook_path.write_text(ASK_HOOK_SOURCE, encoding="utf-8")
|
|
169
|
+
command_argv = [sys.executable, str(ask_hook_path)]
|
|
170
|
+
probe_payload = probe.build_probe_payload_for_basename(DESTRUCTIVE_HOOK_BASENAME)
|
|
171
|
+
assert probe.hook_blocks_probe(command_argv, probe_payload, {}) is False
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def test_hook_blocks_probe_reports_false_for_an_allow_hook(tmp_path: Path) -> None:
|
|
175
|
+
probe = load_probe_module()
|
|
176
|
+
allow_hook_path = tmp_path / "allow_hook.py"
|
|
177
|
+
allow_hook_path.write_text(ALLOW_HOOK_SOURCE, encoding="utf-8")
|
|
178
|
+
command_argv = [sys.executable, str(allow_hook_path)]
|
|
179
|
+
probe_payload = probe.build_probe_payload_for_basename(DESTRUCTIVE_HOOK_BASENAME)
|
|
180
|
+
assert probe.hook_blocks_probe(command_argv, probe_payload, {}) is False
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def test_probe_safety_hook_blocks_against_the_real_pii_hook() -> None:
|
|
184
|
+
probe = load_probe_module()
|
|
185
|
+
settings_document = real_hook_settings_document()
|
|
186
|
+
assert probe.probe_safety_hook(settings_document, PII_HOOK_BASENAME) is True
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def test_main_exits_three_when_the_real_destructive_hook_only_asks(
|
|
190
|
+
tmp_path: Path,
|
|
191
|
+
) -> None:
|
|
192
|
+
probe = load_probe_module()
|
|
193
|
+
settings_path = write_settings_file(tmp_path, real_hook_settings_document())
|
|
194
|
+
exit_code = probe.main(["--settings", str(settings_path)])
|
|
195
|
+
assert exit_code == PROBE_FAILURE_EXIT_CODE
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def test_main_exits_zero_when_both_real_hooks_hard_deny(tmp_path: Path) -> None:
|
|
199
|
+
probe = load_probe_module()
|
|
200
|
+
deny_pii_hook_path = tmp_path / PII_HOOK_BASENAME
|
|
201
|
+
deny_pii_hook_path.write_text(DENY_HOOK_SOURCE, encoding="utf-8")
|
|
202
|
+
deny_destructive_hook_path = tmp_path / DESTRUCTIVE_HOOK_BASENAME
|
|
203
|
+
deny_destructive_hook_path.write_text(DENY_HOOK_SOURCE, encoding="utf-8")
|
|
204
|
+
settings_document = {
|
|
205
|
+
HOOKS_KEY: {
|
|
206
|
+
PRE_TOOL_USE_KEY: [
|
|
207
|
+
{
|
|
208
|
+
MATCHER_KEY: "Write",
|
|
209
|
+
HOOKS_KEY: [{COMMAND_KEY: quoted_command(deny_pii_hook_path)}],
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
MATCHER_KEY: "Bash",
|
|
213
|
+
HOOKS_KEY: [
|
|
214
|
+
{COMMAND_KEY: quoted_command(deny_destructive_hook_path)}
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
settings_path = write_settings_file(tmp_path, settings_document)
|
|
221
|
+
exit_code = probe.main(["--settings", str(settings_path)])
|
|
222
|
+
assert exit_code == PROBE_SUCCESS_EXIT_CODE
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def test_main_exits_three_when_a_hook_allows(tmp_path: Path) -> None:
|
|
226
|
+
probe = load_probe_module()
|
|
227
|
+
allow_pii_hook_path = tmp_path / PII_HOOK_BASENAME
|
|
228
|
+
allow_pii_hook_path.write_text(ALLOW_HOOK_SOURCE, encoding="utf-8")
|
|
229
|
+
destructive_hook_path = HOOKS_BLOCKING_DIRECTORY / DESTRUCTIVE_HOOK_BASENAME
|
|
230
|
+
settings_document = {
|
|
231
|
+
HOOKS_KEY: {
|
|
232
|
+
PRE_TOOL_USE_KEY: [
|
|
233
|
+
{
|
|
234
|
+
MATCHER_KEY: "Write",
|
|
235
|
+
HOOKS_KEY: [{COMMAND_KEY: quoted_command(allow_pii_hook_path)}],
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
MATCHER_KEY: "Bash",
|
|
239
|
+
HOOKS_KEY: [{COMMAND_KEY: quoted_command(destructive_hook_path)}],
|
|
240
|
+
},
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
settings_path = write_settings_file(tmp_path, settings_document)
|
|
245
|
+
exit_code = probe.main(["--settings", str(settings_path)])
|
|
246
|
+
assert exit_code == PROBE_FAILURE_EXIT_CODE
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def test_main_exits_three_when_the_settings_file_is_absent(tmp_path: Path) -> None:
|
|
250
|
+
probe = load_probe_module()
|
|
251
|
+
absent_settings_path = tmp_path / "does-not-exist.json"
|
|
252
|
+
exit_code = probe.main(["--settings", str(absent_settings_path)])
|
|
253
|
+
assert exit_code == PROBE_FAILURE_EXIT_CODE
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def test_main_exits_three_when_the_settings_file_is_invalid_json(tmp_path: Path) -> None:
|
|
257
|
+
probe = load_probe_module()
|
|
258
|
+
settings_path = tmp_path / "sandbox-settings.json"
|
|
259
|
+
settings_path.write_text("{not valid json", encoding="utf-8")
|
|
260
|
+
exit_code = probe.main(["--settings", str(settings_path)])
|
|
261
|
+
assert exit_code == PROBE_FAILURE_EXIT_CODE
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def test_main_exits_three_when_a_hook_script_is_bogus(tmp_path: Path) -> None:
|
|
265
|
+
probe = load_probe_module()
|
|
266
|
+
bogus_pii_hook_path = tmp_path / PII_HOOK_BASENAME
|
|
267
|
+
destructive_hook_path = HOOKS_BLOCKING_DIRECTORY / DESTRUCTIVE_HOOK_BASENAME
|
|
268
|
+
settings_document = {
|
|
269
|
+
HOOKS_KEY: {
|
|
270
|
+
PRE_TOOL_USE_KEY: [
|
|
271
|
+
{
|
|
272
|
+
MATCHER_KEY: "Write",
|
|
273
|
+
HOOKS_KEY: [{COMMAND_KEY: quoted_command(bogus_pii_hook_path)}],
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
MATCHER_KEY: "Bash",
|
|
277
|
+
HOOKS_KEY: [{COMMAND_KEY: quoted_command(destructive_hook_path)}],
|
|
278
|
+
},
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
settings_path = write_settings_file(tmp_path, settings_document)
|
|
283
|
+
exit_code = probe.main(["--settings", str(settings_path)])
|
|
284
|
+
assert exit_code == PROBE_FAILURE_EXIT_CODE
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Promotion workflow (Phase 2)
|
|
2
|
+
|
|
3
|
+
Turn a successful proof-of-concept into a real, verified change. Run every step in the normal, fully-hooked session — never inside the `--bare` sandbox. The sandbox produced a reference build; promotion re-verifies it to standard and often rewrites parts of it.
|
|
4
|
+
|
|
5
|
+
## Seed the task list first
|
|
6
|
+
|
|
7
|
+
Register every item in `reference/promotion-tasks.md` as a session task (`TaskCreate`, or `TodoWrite` if that is the host tool). Work only from the task list. Mark each complete with evidence — a command result, a path, a verdict, or a skill's return.
|
|
8
|
+
|
|
9
|
+
## The clean-room protocol
|
|
10
|
+
|
|
11
|
+
The task seeds carry the full ordered detail. The shape:
|
|
12
|
+
|
|
13
|
+
1. **Confirm** the POC is worth promoting and the user wants it shipped.
|
|
14
|
+
2. **Fresh branch** off freshly-fetched `origin/main` via `fresh-branch` — clean history, based on live upstream.
|
|
15
|
+
3. **Bring content as an uncommitted diff.** Copy the POC's file changes into the new branch's working tree. Do not cherry-pick or merge the sandbox commits; the sandbox history stays behind.
|
|
16
|
+
4. **Cleanup.** Remove scratch files, debug dumps, and temp helpers the POC created (`cleanup-temp-files` rule).
|
|
17
|
+
5. **Privacy sweep** via `privacy-hygiene` over the diff.
|
|
18
|
+
6. **Verify** with the `code-verifier` agent — `model: sonnet`, worker-model routing per [`skills/orchestrator/SKILL.md`](../../orchestrator/SKILL.md#workflow-agent-routing); resolver-supplied sonnet-equivalent on third-party hosts — in a fresh context. This is where standards re-engage. Expect findings and a repair loop — the POC was un-TDD'd.
|
|
19
|
+
7. **Commit and PR.** Only on a clean verdict, run `/commit`, then open a draft PR per the `git-workflow` rule.
|
|
20
|
+
8. **State the honest limitations** from `reference/honest-limitations.md` in the PR body or to the user.
|
|
21
|
+
9. **Converge** by handing the PR to `autoconverge` by default; use `pr-converge` for paced ticks or `bugteam` for an open-loop audit.
|
|
22
|
+
|
|
23
|
+
## Why the clean room, not a push
|
|
24
|
+
|
|
25
|
+
`code_rules_enforcer` is a write-time Write/Edit gate. Content that lands through `git apply`, `git checkout`, or cherry-pick never passes through it, so pushing the sandbox branch would ship code the rule engine never saw, carrying sandbox scratch along with it. Standards re-engage through the `code-verifier` agent, the `privacy-hygiene` sweep, and the PR review — not through a write-time hook. Steps 4-6 are hard gates: the honest claim on promoted POC code is code-verifier-passed, privacy-swept, review-passed, with TDD ordering waived.
|
|
26
|
+
|
|
27
|
+
The `verified_commit_gate` hook is the backstop under all of this — it refuses a commit or push with no minted verdict — but the clean-room steps are the mechanism, not the gate firing.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Sandbox workflow (Phase 1)
|
|
2
|
+
|
|
3
|
+
Stand up an isolated worktree where a hookless agent builds a proof-of-concept with zero standards friction. Only two safety gates stay live: personal-data blocking and destructive-command blocking.
|
|
4
|
+
|
|
5
|
+
## Step 1 — Isolated worktree
|
|
6
|
+
|
|
7
|
+
Invoke the `fresh-branch` skill to create a worktree off `origin/main`. Keep the returned `worktree_path` and `base_commit` for the promotion phase. If `fresh-branch` is not installed, stop with the refusal line from `SKILL.md`.
|
|
8
|
+
|
|
9
|
+
## Step 2 — Minimal safety settings
|
|
10
|
+
|
|
11
|
+
Run `scripts/build_sandbox_settings.py --out <worktree>/.prototype-sandbox-settings.json`.
|
|
12
|
+
|
|
13
|
+
It reads the live `~/.claude/settings.json`, resolves each safety hook's command (the correct interpreter and absolute path for this machine), and registers it on the matchers the sandbox needs — personal-data on Write, Edit, MultiEdit, and Bash; destructive-command on Bash. The write file carries only those two gates, plus an `env` block that sets `CLAUDE_DESTRUCTIVE_DENY_MODE`, so the destructive gate hard-denies a match. A hard deny holds under `--dangerously-skip-permissions`; an `ask` there is auto-resolved.
|
|
14
|
+
|
|
15
|
+
- Exit 0 → continue with the printed settings path.
|
|
16
|
+
- Exit 2 → one of the two safety hooks could not be resolved from the live settings. Stop; the sandbox cannot be contained without both. Report which one is missing.
|
|
17
|
+
|
|
18
|
+
## Step 3 — Prove containment
|
|
19
|
+
|
|
20
|
+
Run `scripts/probe_sandbox_safety.py --settings <settings path>`.
|
|
21
|
+
|
|
22
|
+
It feeds each safety hook a payload the hook is proven to block and confirms a hard-deny decision — the block that holds even under `--dangerously-skip-permissions`, unlike an `ask` prompt the flag auto-resolves. It runs each hook under the settings' `env` block, so the destructive gate runs in deny mode, the same way the launched session runs it.
|
|
23
|
+
|
|
24
|
+
- Exit 0 → both gates hard-deny their probe; the sandbox is contained.
|
|
25
|
+
- Exit 3 → a gate allowed its probe, returned an `ask`, or errored. Stop; do not launch an uncontained sandbox. This is a runtime check, not a code read (verify-runtime-state) — do not skip it.
|
|
26
|
+
|
|
27
|
+
## Step 4 — Launch the hookless session
|
|
28
|
+
|
|
29
|
+
Run `scripts/launch_sandbox.py --worktree <worktree_path> --settings <settings path> --task-file <task file>`.
|
|
30
|
+
|
|
31
|
+
It starts a headless `claude -p --bare --dangerously-skip-permissions --settings <settings path>` session in the worktree, so every standards gate is skipped and the two safety gates from the settings file are the only containment. Write the proof-of-concept task to the task file first; the sandbox agent cannot invoke other skills, so the task must be self-contained.
|
|
32
|
+
|
|
33
|
+
## Step 5 — Judge the result
|
|
34
|
+
|
|
35
|
+
Read what the sandbox built and decide whether the proof-of-concept proves the idea. On success, move to `promotion.md`. To discard, remove the worktree with `git worktree remove --force <worktree_path>`.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release-notes-html
|
|
3
|
+
description: Build a polished self-contained HTML product launch and release-notes page from work completed in the current session, using available repository state, source-of-truth files, tests, approvals, artifacts, commits, pull requests, previews, and release evidence. Use when the user asks to build release notes, create a launch page, document completed work, produce feature-release HTML, or turn the session into product-facing release notes.
|
|
4
|
+
when_to_use: Invoke for requests such as "build release notes for the work you've done," "create release notes HTML," "make a product launch page," "document this completed feature," or "turn our work into a polished release page."
|
|
5
|
+
disable-model-invocation: false
|
|
6
|
+
user-invocable: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Build a polished, self-contained HTML product launch and release-notes page for the work completed in this session.
|
|
10
|
+
|
|
11
|
+
Use the current conversation, task history, repository state, completed changes, test results, approvals, generated artifacts, plans, handoffs, file paths, commits, pull requests, and other evidence already available in the session as the source of truth.
|
|
12
|
+
|
|
13
|
+
Recover the feature name, purpose, capabilities, specifications, usage instructions, validation results, release status, and first production use directly from the available context. Inspect relevant files and repository artifacts when access is available.
|
|
14
|
+
|
|
15
|
+
Ask one concise clarification question only when the session does not contain enough information to identify the completed feature or its supporting evidence.
|
|
16
|
+
|
|
17
|
+
## Execution
|
|
18
|
+
|
|
19
|
+
Act as the orchestrator.
|
|
20
|
+
|
|
21
|
+
Create a task ledger covering:
|
|
22
|
+
|
|
23
|
+
- Evidence collection
|
|
24
|
+
- Feature and release-state synthesis
|
|
25
|
+
- Page structure
|
|
26
|
+
- HTML creation
|
|
27
|
+
- Evidence audit
|
|
28
|
+
- Visual and browser review
|
|
29
|
+
- Final delivery
|
|
30
|
+
|
|
31
|
+
Assign file inspection and HTML creation to executor workers when worker tools are available. The orchestrator owns the structure, factual acceptance, and final audit.
|
|
32
|
+
|
|
33
|
+
## Evidence rules
|
|
34
|
+
|
|
35
|
+
Use only facts supported by:
|
|
36
|
+
|
|
37
|
+
- The current conversation
|
|
38
|
+
- Current session tasks and results
|
|
39
|
+
- Repository files and git state
|
|
40
|
+
- Named source-of-truth files
|
|
41
|
+
- Generated reports, ledgers, plans, and acceptance packets
|
|
42
|
+
- Explicit user approvals
|
|
43
|
+
- Test and CI output already available
|
|
44
|
+
- Pull request and commit data available to the session
|
|
45
|
+
|
|
46
|
+
Locate the strongest source for each claim.
|
|
47
|
+
|
|
48
|
+
Preserve exact:
|
|
49
|
+
|
|
50
|
+
- Feature and package names
|
|
51
|
+
- File paths
|
|
52
|
+
- Commands
|
|
53
|
+
- Dimensions
|
|
54
|
+
- Flags
|
|
55
|
+
- Identifiers
|
|
56
|
+
- JSON keys
|
|
57
|
+
- Test totals
|
|
58
|
+
- Pull request numbers
|
|
59
|
+
- Branch and release status
|
|
60
|
+
|
|
61
|
+
Place exact technical values inside `<code>` elements.
|
|
62
|
+
|
|
63
|
+
Include previews, approval claims, test counts, merged status, and production-use claims when the available evidence supports them.
|
|
64
|
+
|
|
65
|
+
## Page content
|
|
66
|
+
|
|
67
|
+
Produce one cohesive launch page with a clear hierarchy that a non-engineer can skim.
|
|
68
|
+
|
|
69
|
+
Include the sections that the completed work supports:
|
|
70
|
+
|
|
71
|
+
1. Hero with the feature name and primary benefit
|
|
72
|
+
2. A brief explanation of what the feature enables
|
|
73
|
+
3. Major capability highlights
|
|
74
|
+
4. How to run or use it
|
|
75
|
+
5. Exact specifications
|
|
76
|
+
6. Quality, validation, and safety coverage
|
|
77
|
+
7. First production use, debut project, or approved example
|
|
78
|
+
8. Current availability or completion status
|
|
79
|
+
|
|
80
|
+
Adapt the section names and structure to the actual project. Give every heading a useful takeaway.
|
|
81
|
+
|
|
82
|
+
## Tone
|
|
83
|
+
|
|
84
|
+
Write the page as the launch of a completed new capability.
|
|
85
|
+
|
|
86
|
+
Use present-state product copy focused on:
|
|
87
|
+
|
|
88
|
+
- What it is
|
|
89
|
+
- What the user can accomplish
|
|
90
|
+
- How it works
|
|
91
|
+
- How to use it
|
|
92
|
+
- What guarantees or validations it provides
|
|
93
|
+
- Where it has already been applied
|
|
94
|
+
|
|
95
|
+
Keep implementation history, discarded approaches, debugging chronology, and internal justification outside the page unless they are essential to using the feature.
|
|
96
|
+
|
|
97
|
+
## Voice rules
|
|
98
|
+
|
|
99
|
+
The reader primarily absorbs headings, bolded leads, and the first sentence of each block.
|
|
100
|
+
|
|
101
|
+
1. Every title states a plain-language claim.
|
|
102
|
+
2. Each sentence carries one idea.
|
|
103
|
+
3. Lead with reader meaning, then explain the mechanism.
|
|
104
|
+
4. Explain specialized terms at first use.
|
|
105
|
+
5. Keep exact technical values verbatim inside `<code>` elements.
|
|
106
|
+
6. Limit cards to two sentences.
|
|
107
|
+
7. Limit list items to three sentences.
|
|
108
|
+
8. Give each section a one-sentence subtitle that adds information.
|
|
109
|
+
9. Make the complete story understandable from headings and bolded leads alone.
|
|
110
|
+
10. Use concise, active sentences.
|
|
111
|
+
11. Use present-state language throughout.
|
|
112
|
+
12. Give every important fact one clear location.
|
|
113
|
+
|
|
114
|
+
## Design
|
|
115
|
+
|
|
116
|
+
Create one valid HTML file with self-contained CSS. CDN-hosted fonts are acceptable.
|
|
117
|
+
|
|
118
|
+
Use:
|
|
119
|
+
|
|
120
|
+
- Strong visual hierarchy
|
|
121
|
+
- Spacious typography
|
|
122
|
+
- Scannable cards and sections
|
|
123
|
+
- Responsive desktop and narrow-screen layouts
|
|
124
|
+
- Accessible contrast
|
|
125
|
+
- Clear treatment of code, specifications, and commands
|
|
126
|
+
- An inviting product-launch presentation rather than dense documentation
|
|
127
|
+
|
|
128
|
+
Use an approved preview or product image when one is already available and supported by the session.
|
|
129
|
+
|
|
130
|
+
## Output location
|
|
131
|
+
|
|
132
|
+
Choose the output location from an explicit path already stated in the session.
|
|
133
|
+
|
|
134
|
+
When no output path has been established, write the file beside the project’s existing results, release, report, or acceptance artifacts using a clear name such as:
|
|
135
|
+
|
|
136
|
+
`RELEASE_NOTES.html`
|
|
137
|
+
|
|
138
|
+
Use the operating-system temporary directory only when no project location can be determined safely.
|
|
139
|
+
|
|
140
|
+
Write the file atomically and create its parent directory when required.
|
|
141
|
+
|
|
142
|
+
## Acceptance audit
|
|
143
|
+
|
|
144
|
+
Before delivery:
|
|
145
|
+
|
|
146
|
+
- Verify every factual claim against the available evidence.
|
|
147
|
+
- Review every heading for a clear takeaway.
|
|
148
|
+
- Review every sentence for one idea.
|
|
149
|
+
- Confirm specialized terms receive plain explanations.
|
|
150
|
+
- Confirm exact technical values remain verbatim.
|
|
151
|
+
- Confirm headings and bolded leads communicate the whole story.
|
|
152
|
+
- Confirm the page is readable at desktop and narrow browser widths.
|
|
153
|
+
- Confirm the output is one complete, valid HTML file.
|
|
154
|
+
- Open the completed page in Chrome or the available default browser when the environment supports it.
|
|
155
|
+
- Correct every issue found during the audit.
|
|
156
|
+
|
|
157
|
+
## Delivery
|
|
158
|
+
|
|
159
|
+
Reply with:
|
|
160
|
+
|
|
161
|
+
1. The full absolute path to the HTML file.
|
|
162
|
+
2. One sentence describing what the release-notes page covers.
|
|
163
|
+
|
|
164
|
+
Stop after delivering the completed page.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# skill-builder
|
|
2
2
|
|
|
3
|
-
Orchestrates the skill-building lifecycle: classify type, scaffold folders, write via `skill-writer
|
|
3
|
+
Orchestrates the skill-building lifecycle: classify type, scaffold folders, write via the `skill-writer-agent` agent, enforce modularity (sub-skills / composition), write description as a trigger catalog, require deterministic steps as code, self-audit, and refine from real usage.
|
|
4
4
|
|
|
5
5
|
**Trigger:** build a skill, new skill workflow, improve this skill, optimize skill description, skill development lifecycle, skill modularity, description trigger catalog, deterministic skill scripts.
|
|
6
6
|
|
|
7
7
|
## Purpose
|
|
8
8
|
|
|
9
|
-
Enforces craft standards for new and existing skills. For quick one-off SKILL.md edits,
|
|
9
|
+
Enforces craft standards for new and existing skills. For quick one-off SKILL.md edits, spawn the `skill-writer-agent` agent directly. This skill classifies, scaffolds, gathers context (composition plan, description triggers, deterministic inventory), delegates writing, and self-audits.
|
|
10
10
|
|
|
11
11
|
## Key files
|
|
12
12
|
|
|
@@ -45,5 +45,5 @@ Enforces craft standards for new and existing skills. For quick one-off SKILL.md
|
|
|
45
45
|
|
|
46
46
|
- Every build ends with the self-audit at `references/self-audit-checklist.md`; fix failures before delivery.
|
|
47
47
|
- Modularity items, description trigger-catalog items, and deterministic-element classification are mandatory on every delivery.
|
|
48
|
-
- `skill-builder` orchestrates; `skill-writer` authors. Handoff packet must include type, gap analysis, composition plan, description trigger catalog, deterministic inventory, degree-of-freedom assessment, and constraints.
|
|
48
|
+
- `skill-builder` orchestrates; the `skill-writer-agent` agent authors. Handoff packet must include type, gap analysis, composition plan, description trigger catalog, deterministic inventory, degree-of-freedom assessment, and constraints.
|
|
49
49
|
- Claude A / Claude B: Claude A (this session) designs; Claude B (subagents) tests the built skill on real tasks.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: skill-builder
|
|
3
3
|
description: >-
|
|
4
|
-
Skill lifecycle: classify, scaffold, write via skill-writer, self-audit, compose
|
|
4
|
+
Skill lifecycle: classify, scaffold, write via the skill-writer-agent, self-audit, compose
|
|
5
5
|
sub-skills, polish description triggers, enforce deterministic scripts. Triggers:
|
|
6
6
|
build a skill, new skill workflow, improve this skill, optimize skill description,
|
|
7
7
|
skill development lifecycle, skill modularity, skill composition, description
|
|
@@ -28,9 +28,9 @@ Highest-signal content. Append a bullet each time a skill build fails in a new w
|
|
|
28
28
|
|
|
29
29
|
## When this skill applies
|
|
30
30
|
|
|
31
|
-
Trigger for requests to **build**, **improve**, or **polish** a skill. This skill orchestrates the process — it classifies, scaffolds, gathers context, delegates writing to
|
|
31
|
+
Trigger for requests to **build**, **improve**, or **polish** a skill. This skill orchestrates the process — it classifies, scaffolds, gathers context, delegates writing to the `skill-writer-agent` agent, and self-audits the result.
|
|
32
32
|
|
|
33
|
-
For quick skill syntax questions or one-off SKILL.md edits,
|
|
33
|
+
For quick skill syntax questions or one-off SKILL.md edits, spawn the `skill-writer-agent` agent directly.
|
|
34
34
|
|
|
35
35
|
**Refusal cases — first match wins:**
|
|
36
36
|
|
|
@@ -161,9 +161,9 @@ Also: story-form descriptions; monolith multi-capability skills; silent reimplem
|
|
|
161
161
|
|
|
162
162
|
After every build, improvement, or polish pass, load `${CLAUDE_SKILL_DIR}/references/self-audit-checklist.md`, **register every bullet as a session task**, and complete each with evidence. Every item must pass before delivery. Fix failures, then re-audit.
|
|
163
163
|
|
|
164
|
-
## Delegation to skill-writer
|
|
164
|
+
## Delegation to skill-writer-agent
|
|
165
165
|
|
|
166
|
-
skill-builder orchestrates; skill-writer authors. The handoff packet from Step 4 must include:
|
|
166
|
+
skill-builder orchestrates; the `skill-writer-agent` agent authors. The caller spawns it with `Agent(subagent_type="skill-writer-agent", ...)`. The handoff packet from Step 4 must include:
|
|
167
167
|
|
|
168
168
|
- Skill type and folder structure
|
|
169
169
|
- Gap analysis or observation findings (composition plan + description triggers + deterministic inventory)
|
|
@@ -12,7 +12,7 @@ Best-practice specifications and the mandatory self-audit checklist for the `/sk
|
|
|
12
12
|
| `skill-modularity.md` | Cross-skill modularity: one capability, sub-skills by name, composition plan, anti-monolith. |
|
|
13
13
|
| `description-field.md` | Frontmatter description as trigger catalog (capability stem + Triggers). No story prose. |
|
|
14
14
|
| `deterministic-elements.md` | Classify process steps; deterministic ones ship as code, task seeds, or fixed artifacts under CODE_RULES. |
|
|
15
|
-
| `delegation-map.md` | Subagent handoff patterns and transcript guidance for skill-builder → skill-writer. |
|
|
15
|
+
| `delegation-map.md` | Subagent handoff patterns and transcript guidance for skill-builder → skill-writer-agent. |
|
|
16
16
|
| `thariq-x-post-skills.json` | Source reference data from Anthropic lessons on building Claude Code skills. |
|
|
17
17
|
|
|
18
18
|
## Conventions
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Delegation Map
|
|
2
2
|
|
|
3
|
-
How skill-builder delegates
|
|
3
|
+
How skill-builder delegates authoring to the `skill-writer-agent` agent.
|
|
4
4
|
|
|
5
|
-
## Delegating to skill-writer (Step 4)
|
|
5
|
+
## Delegating to skill-writer-agent (Step 4)
|
|
6
6
|
|
|
7
|
-
skill-builder orchestrates; skill-writer authors the SKILL.md and companion files. The handoff must be structured so
|
|
7
|
+
skill-builder orchestrates; the `skill-writer-agent` agent authors the SKILL.md and companion files. The caller spawns it with `Agent(subagent_type="skill-writer-agent", ...)`. The handoff must be structured so the agent has everything it needs.
|
|
8
8
|
|
|
9
9
|
### New skill handoff
|
|
10
10
|
|
|
@@ -44,7 +44,7 @@ description: >-
|
|
|
44
44
|
|
|
45
45
|
```yaml
|
|
46
46
|
description: >-
|
|
47
|
-
Skill lifecycle: classify, scaffold, write via skill-writer, self-audit, compose sub-skills, polish description triggers. Triggers: build a skill, new skill workflow, improve this skill, optimize skill description, skill development lifecycle, skill modularity.
|
|
47
|
+
Skill lifecycle: classify, scaffold, write via the skill-writer-agent, self-audit, compose sub-skills, polish description triggers. Triggers: build a skill, new skill workflow, improve this skill, optimize skill description, skill development lifecycle, skill modularity.
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
```yaml
|
|
@@ -54,7 +54,7 @@ sibling-skill-a/ # one capability
|
|
|
54
54
|
sibling-skill-b/ # one capability
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
The orchestrator owns sequence and gates. Sub-skills own domain detail. skill-builder itself follows this shape: it orchestrates and delegates writing to
|
|
57
|
+
The orchestrator owns sequence and gates. Sub-skills own domain detail. skill-builder itself follows this shape: it orchestrates and delegates writing to the `skill-writer-agent` agent (spawned via the Agent tool).
|
|
58
58
|
|
|
59
59
|
### Within-skill vs split
|
|
60
60
|
|
|
@@ -85,12 +85,11 @@ In Process or a dedicated **Sub-skills** section:
|
|
|
85
85
|
| Skill | When | Produces |
|
|
86
86
|
|---|---|---|
|
|
87
87
|
| `/reviewer-gates` | Step 1 — gate external reviewers | opt-out, Copilot quota, Bugbot trigger decisions |
|
|
88
|
-
| `/skill-writer` | Step 4 — author SKILL.md | skill package files |
|
|
89
88
|
|
|
90
89
|
If a listed skill is not installed, respond: `[exact refusal or degrade line]`.
|
|
91
90
|
```
|
|
92
91
|
|
|
93
|
-
Self-audit requires this table (or equivalent) whenever the skill composes others.
|
|
92
|
+
Self-audit requires this table (or equivalent) whenever the skill composes others. skill-builder itself delegates SKILL.md authoring to the `skill-writer-agent` agent, spawned via the Agent tool.
|
|
94
93
|
|
|
95
94
|
## Anti-patterns
|
|
96
95
|
|
|
@@ -6,7 +6,7 @@ Step-by-step workflow files for each skill lifecycle phase, loaded on demand by
|
|
|
6
6
|
|
|
7
7
|
| File | Purpose |
|
|
8
8
|
|---|---|
|
|
9
|
-
| `new-skill.md` | Full lifecycle: classify, scaffold, gather (composition + description triggers + deterministic inventory), write via skill-writer, self-audit, deliver. |
|
|
9
|
+
| `new-skill.md` | Full lifecycle: classify, scaffold, gather (composition + description triggers + deterministic inventory), write via the skill-writer-agent agent, self-audit, deliver. |
|
|
10
10
|
| `improve-skill.md` | Observation-first improve: diagnose activation/modularity/quality/deterministic prose, targeted fix, re-audit. |
|
|
11
11
|
| `polish-skill.md` | Description trigger-catalog audit; progressive disclosure + modularity + deterministic audit; task-seeded self-audit. |
|
|
12
12
|
|
|
@@ -83,7 +83,7 @@ For each diagnosis from Step 2:
|
|
|
83
83
|
6. For checkbox/tracker failures: replace markdown `- [ ]` boards with a plain task-seed list and a seed instruction (`TaskCreate` / `TodoWrite`).
|
|
84
84
|
7. Verify the fix doesn’t break anything that was working.
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
Spawn the `skill-writer-agent` agent for larger rewrites, using the refine-skill handoff from delegation-map.md.
|
|
87
87
|
|
|
88
88
|
**Output:** Modified skill files with targeted fixes.
|
|
89
89
|
|
|
@@ -125,11 +125,11 @@ Register each task seed under **Required task seeds** in `deterministic-elements
|
|
|
125
125
|
|
|
126
126
|
**Goal:** Produce the skill package — SKILL.md and companion files.
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
Spawn the `skill-writer-agent` agent (`Agent(subagent_type="skill-writer-agent", ...)`) with the structured handoff from `${CLAUDE_SKILL_DIR}/references/delegation-map.md`.
|
|
129
129
|
|
|
130
130
|
The handoff must include: skill type, folder structure, gap analysis (composition plan + description triggers + deterministic inventory), initial gotchas, degree of freedom, constraints, sub-skills to name in SKILL.md, exact description string to put in frontmatter, script/test paths for every deterministic step.
|
|
131
131
|
|
|
132
|
-
After skill-writer produces the draft:
|
|
132
|
+
After the `skill-writer-agent` agent produces the draft:
|
|
133
133
|
|
|
134
134
|
1. Verify it follows the hub layout (principle → gotchas → when-applies → process → file index → folder map).
|
|
135
135
|
2. Verify SKILL.md body is under 500 lines.
|