scar-cli 0.22.0__tar.gz → 0.24.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. scar_cli-0.24.0/.release-please-manifest.json +3 -0
  2. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0005-history-rewrite-orphans-commit-evidence.landmine.md +5 -0
  3. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0006-yaml-pattern-anchor-over-escaping.landmine.md +2 -1
  4. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0008-rich-output-nontty-must-bypass-rich.landmine.md +2 -2
  5. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0011-lint-compile-check-lets-redos-anchors-hang-hotpath.landmine.md +2 -2
  6. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0017-codex-pretool-context-can-replay-apply-patch.landmine.md +0 -1
  7. scar_cli-0.22.0/.scars/candidates/one-directional-health-check-leaves-flattering-direction-unwatched.md → scar_cli-0.24.0/.scars/0020-one-directional-health-check-leaves-flattering-direction-unwatched.landmine.md +6 -2
  8. scar_cli-0.22.0/.scars/candidates/posttool-fix-in-hooks-does-not-reach-codex-or-cascade.md → scar_cli-0.24.0/.scars/0021-posttool-fix-in-hooks-does-not-reach-codex-or-cascade.landmine.md +5 -3
  9. scar_cli-0.22.0/.scars/candidates/codex-hook-delivery-needs-user-file-and-trust.md → scar_cli-0.24.0/.scars/0022-codex-hook-delivery-needs-user-file-and-trust.landmine.md +4 -3
  10. scar_cli-0.24.0/.scars/candidates/host-detection-must-not-read-the-process-home.md +40 -0
  11. scar_cli-0.24.0/.scars/candidates/one-plugin-hook-manifest-two-hosts-two-root-variables.md +30 -0
  12. scar_cli-0.24.0/.scars/candidates/path-anchor-breadth-drives-the-review-due-threshold.md +37 -0
  13. {scar_cli-0.22.0 → scar_cli-0.24.0}/AGENTS.md +5 -2
  14. {scar_cli-0.22.0 → scar_cli-0.24.0}/CHANGELOG.md +24 -0
  15. {scar_cli-0.22.0 → scar_cli-0.24.0}/PKG-INFO +8 -12
  16. {scar_cli-0.22.0 → scar_cli-0.24.0}/README.md +7 -11
  17. {scar_cli-0.22.0 → scar_cli-0.24.0}/SCAR-FORMAT.md +1 -1
  18. {scar_cli-0.22.0 → scar_cli-0.24.0}/SPEC.md +6 -0
  19. {scar_cli-0.22.0 → scar_cli-0.24.0}/plugin/plugin.json +1 -1
  20. {scar_cli-0.22.0 → scar_cli-0.24.0}/pyproject.toml +1 -1
  21. {scar_cli-0.22.0 → scar_cli-0.24.0}/release-please-config.json +1 -0
  22. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/cli.py +241 -63
  23. scar_cli-0.24.0/src/scar/firing_log.py +71 -0
  24. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/hooks.py +8 -10
  25. scar_cli-0.24.0/src/scar/hosts.py +221 -0
  26. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/installer.py +79 -10
  27. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/lint.py +6 -2
  28. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_cli.py +127 -1
  29. scar_cli-0.24.0/tests/test_firing_log.py +113 -0
  30. scar_cli-0.24.0/tests/test_hosts.py +404 -0
  31. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_installer.py +408 -22
  32. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_lint.py +26 -0
  33. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_plugin.py +11 -23
  34. {scar_cli-0.22.0 → scar_cli-0.24.0}/uv.lock +1 -1
  35. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/docs/agents.md +33 -6
  36. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/static/llms.txt +1 -1
  37. scar_cli-0.22.0/.release-please-manifest.json +0 -3
  38. scar_cli-0.22.0/plugin/hooks/hooks.json +0 -43
  39. {scar_cli-0.22.0 → scar_cli-0.24.0}/.claude-plugin/marketplace.json +0 -0
  40. {scar_cli-0.22.0 → scar_cli-0.24.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  41. {scar_cli-0.22.0 → scar_cli-0.24.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  42. {scar_cli-0.22.0 → scar_cli-0.24.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  43. {scar_cli-0.22.0 → scar_cli-0.24.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  44. {scar_cli-0.22.0 → scar_cli-0.24.0}/.github/workflows/ci.yml +0 -0
  45. {scar_cli-0.22.0 → scar_cli-0.24.0}/.github/workflows/docs.yml +0 -0
  46. {scar_cli-0.22.0 → scar_cli-0.24.0}/.github/workflows/pr-validation.yml +0 -0
  47. {scar_cli-0.22.0 → scar_cli-0.24.0}/.github/workflows/release.yml +0 -0
  48. {scar_cli-0.22.0 → scar_cli-0.24.0}/.gitignore +0 -0
  49. {scar_cli-0.22.0 → scar_cli-0.24.0}/.pre-commit-config.yaml +0 -0
  50. {scar_cli-0.22.0 → scar_cli-0.24.0}/.pre-commit-hooks.yaml +0 -0
  51. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0001-git-grep-ere-pitfalls.landmine.md +0 -0
  52. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0002-agent-direct-hook-install.deadend.md +0 -0
  53. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0003-installer-binds-to-active-venv-scar.landmine.md +0 -0
  54. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0004-promote-roundtrip-drops-expires-evidence.landmine.md +0 -0
  55. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0007-release-please-config-change-skips-open-pr.landmine.md +0 -0
  56. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0009-anchor-survival-harness-measures-symbol-not-path-anchors.deadend.md +0 -0
  57. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0010-git-returncode-128-vs-empty-tracked-set.landmine.md +0 -0
  58. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0012-firing-log-readers-need-blanket-guards.landmine.md +0 -0
  59. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0013-docusaurus-future-v4-requires-faster-dep.landmine.md +0 -0
  60. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0014-inject-flag-dest-collides-with-subcommand-dispatch.landmine.md +0 -0
  61. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0015-zero-checkruns-means-approval-gate-not-workflow-bug.deadend.md +0 -0
  62. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0016-hook-ownership-must-be-kind-scoped.landmine.md +0 -0
  63. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0018-cli-subparsers-register-through-_add-wrapper.landmine.md +0 -0
  64. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/0019-token-in-scar-body-cannot-prove-hook-delivery.deadend.md +0 -0
  65. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/README.md +0 -0
  66. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/candidates/cascade-block-exit-collides-with-argparse.md +0 -0
  67. {scar_cli-0.22.0 → scar_cli-0.24.0}/.scars/template.md +0 -0
  68. {scar_cli-0.22.0 → scar_cli-0.24.0}/CONTRIBUTING.md +0 -0
  69. {scar_cli-0.22.0 → scar_cli-0.24.0}/IDEA.md +0 -0
  70. {scar_cli-0.22.0 → scar_cli-0.24.0}/LICENSE +0 -0
  71. {scar_cli-0.22.0 → scar_cli-0.24.0}/ROADMAP.md +0 -0
  72. {scar_cli-0.22.0 → scar_cli-0.24.0}/STRESS-TEST.md +0 -0
  73. {scar_cli-0.22.0 → scar_cli-0.24.0}/action.yml +0 -0
  74. {scar_cli-0.22.0 → scar_cli-0.24.0}/codecov.yml +0 -0
  75. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/anchor-survival/PROTOCOL.md +0 -0
  76. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/anchor-survival/RESULTS.md +0 -0
  77. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/anchor-survival/long_replay.py +0 -0
  78. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/anchor-survival/replay.py +0 -0
  79. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/anchor-survival/replay_shipped.py +0 -0
  80. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/anchor-survival/test_replay_shipped.py +0 -0
  81. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/auto-authorship/FINDINGS.md +0 -0
  82. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/auto-authorship/PROTOCOL.md +0 -0
  83. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/.gitignore +0 -0
  84. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/PROTOCOL.md +0 -0
  85. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/RESULTS.md +0 -0
  86. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/fixture/.scars/0001-vendor-retry-window.fence.md +0 -0
  87. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/fixture/.scars/0002-evicting-session-store.deadend.md +0 -0
  88. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/fixture/.scars/0003-export-column-order.landmine.md +0 -0
  89. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/fixture/README.md +0 -0
  90. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/fixture/payments/retry.py +0 -0
  91. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/fixture/reports/export.py +0 -0
  92. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/fixture/services/sessions.py +0 -0
  93. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/fence-honor/grade.py +0 -0
  94. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/harvest/PROTOCOL.md +0 -0
  95. {scar_cli-0.22.0 → scar_cli-0.24.0}/experiments/harvest/harvest.py +0 -0
  96. {scar_cli-0.22.0 → scar_cli-0.24.0}/hook/scar-hooks.py +0 -0
  97. {scar_cli-0.22.0 → scar_cli-0.24.0}/plugin/hooks/run.sh +0 -0
  98. {scar_cli-0.22.0 → scar_cli-0.24.0}/plugin/skills/scar-authoring/SKILL.md +0 -0
  99. {scar_cli-0.22.0 → scar_cli-0.24.0}/plugin/skills/scar-authoring/assets/template.md +0 -0
  100. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/__init__.py +0 -0
  101. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/agent.py +0 -0
  102. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/cascade.py +0 -0
  103. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/codex.py +0 -0
  104. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/draftcheck.py +0 -0
  105. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/evidence.py +0 -0
  106. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/gc.py +0 -0
  107. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/harvest.py +0 -0
  108. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/match.py +0 -0
  109. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/mcp.py +0 -0
  110. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/model.py +0 -0
  111. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/orphan.py +0 -0
  112. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/output.py +0 -0
  113. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/reanchor.py +0 -0
  114. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/renames.py +0 -0
  115. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/render.py +0 -0
  116. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/review.py +0 -0
  117. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/skills/scar-authoring/SKILL.md +0 -0
  118. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/skills/scar-authoring/assets/template.md +0 -0
  119. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/store.py +0 -0
  120. {scar_cli-0.22.0 → scar_cli-0.24.0}/src/scar/symbols.py +0 -0
  121. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/conftest.py +0 -0
  122. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_action_yml.py +0 -0
  123. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_anchor_kind.py +0 -0
  124. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_block_capability.py +0 -0
  125. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_cascade.py +0 -0
  126. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_codex.py +0 -0
  127. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_context_size.py +0 -0
  128. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_docs.py +0 -0
  129. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_draftcheck.py +0 -0
  130. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_evidence.py +0 -0
  131. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_gc.py +0 -0
  132. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_git_hook.py +0 -0
  133. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_harvest.py +0 -0
  134. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_hooks.py +0 -0
  135. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_json_contract.py +0 -0
  136. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_lifecycle.py +0 -0
  137. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_match.py +0 -0
  138. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_mcp.py +0 -0
  139. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_model.py +0 -0
  140. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_orphan.py +0 -0
  141. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_output.py +0 -0
  142. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_precommit_hooks.py +0 -0
  143. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_reanchor.py +0 -0
  144. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_renames.py +0 -0
  145. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_render.py +0 -0
  146. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_review.py +0 -0
  147. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_skill.py +0 -0
  148. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_store.py +0 -0
  149. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_symbols.py +0 -0
  150. {scar_cli-0.22.0 → scar_cli-0.24.0}/tests/test_verdict_observability.py +0 -0
  151. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/.gitignore +0 -0
  152. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/docs/concepts.md +0 -0
  153. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/docs/index.md +0 -0
  154. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/docs/methodology.md +0 -0
  155. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/docs/quickstart.md +0 -0
  156. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/docusaurus.config.ts +0 -0
  157. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/package-lock.json +0 -0
  158. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/package.json +0 -0
  159. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/scripts/sync-changelog.mjs +0 -0
  160. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/sidebars.ts +0 -0
  161. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/src/css/custom.css +0 -0
  162. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/static/img/favicon.svg +0 -0
  163. {scar_cli-0.22.0 → scar_cli-0.24.0}/website/tsconfig.json +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.24.0"
3
+ }
@@ -8,8 +8,13 @@ created: 2026-06-11
8
8
  authors: ["claude-code", "Kibukx"]
9
9
  anchors:
10
10
  - path: .scars/
11
+ - command: "git push.*--force"
12
+ - command: "git rebase"
13
+ - command: "git filter-repo|git filter-branch"
14
+ - command: "git commit.*--amend"
11
15
  violation: "commit: [0-9a-f]{7,40}"
12
16
  evidence:
17
+ - note: "2026-09-05 anchors: path .scars/ KEPT on purpose. The violation tripwire commit: [0-9a-f]{7,40} only evaluates on files an anchor matched, so dropping it to cut firings would silently disarm the scar. Command anchors added instead, so the history-rewrite half fires on the act rather than on any scar edit"
13
18
  - note: v0.1.0 public release (2026-06-11): fresh-start force-push orphaned 3 commit SHAs cited by scars 0001 and 0002; SHAs still resolve on GitHub by URL but fail in any fresh clone, and GitHub may GC them eventually
14
19
  expires:
15
20
  condition: "evidence schema gains a resolvable form (full URL or archived diff) or lint warns on bare SHAs at promotion"
@@ -9,8 +9,9 @@ authors: ["claude-code", "kibukx"]
9
9
  anchors:
10
10
  - path: src/scar/orphan.py
11
11
  - path: src/scar/match.py
12
- - path: .scars/
12
+ - pattern: "\n\s*-\s*pattern:"
13
13
  evidence:
14
+ - note: "2026-09-05 anchors: path .scars/ replaced by a pattern matching a scar frontmatter pattern: entry. The directory anchor fired on every scar edit, while the hazard only exists when a pattern anchor is being authored"
14
15
  - pr: 40
15
16
  - note: scar 1 grep pattern matched only its own body, never experiments/anchor-survival/RESULTS.md
16
17
  expires:
@@ -7,10 +7,10 @@ confidence: 0.9
7
7
  created: 2026-06-30
8
8
  authors: ["claude-code", "kibukx"]
9
9
  anchors:
10
- - path: src/scar/cli.py
11
10
  - path: src/scar/output.py
12
- - pattern: "output\.render\("
11
+ - pattern: "def plain\(\):"
13
12
  evidence:
13
+ - note: "2026-09-05 anchors: path src/scar/cli.py dropped, it is 3000+ lines and the tty gate is 17 of them. The 18 output.render( call sites only invoke the already-safe dispatcher, so that pattern is replaced by def plain():, which marks the 14 non-tty contract closures this scar actually protects"
14
14
  - issue: 78
15
15
  - note: 187-test suite asserts plain substrings like '0001-bad.deadend.md' and long anchor paths on main([...]) under capsys
16
16
  expires:
@@ -7,11 +7,11 @@ confidence: 0.9
7
7
  created: 2026-06-30
8
8
  authors: ["claude-code", "Kibukx"]
9
9
  anchors:
10
- - path: src/scar/lint.py
11
- - path: src/scar/match.py
12
10
  - pattern: "rx\.search\("
13
11
  - pattern: "MAX_ANCHOR_SCAN"
12
+ - pattern: "_is_redos_prone"
14
13
  evidence:
14
+ - note: "2026-09-05 anchors: both whole-file path anchors dropped, lint.py and match.py serve many concerns beyond ReDoS. _is_redos_prone added so the GATE itself stays anchored, since the body says the gate is the defense and the 64 KiB cap is not"
15
15
  - issue: 88
16
16
  expires:
17
17
  condition: "lint gains full regex-safety analysis OR the matcher runs on a hardened regex engine with a hard timeout"
@@ -8,7 +8,6 @@ created: 2026-08-28
8
8
  authors: ["codex", "Kibukx"]
9
9
  anchors:
10
10
  - path: src/scar/codex.py
11
- - path: plugin/hooks/hooks.json
12
11
  evidence:
13
12
  - issue: 243
14
13
  - note: live codex-cli 0.147.0 A/B emitted two tool_use_ids for one identical apply_patch after the first PreToolUse context injection
@@ -1,21 +1,25 @@
1
1
  ---
2
- id: 0
2
+ id: 20
3
3
  type: landmine
4
4
  title: A health check that watches one direction of pipeline failure leaves the flattering direction unwatched
5
5
  severity: high
6
6
  confidence: 0.9
7
7
  created: 2026-08-30
8
8
  authors: ["claude-code"]
9
+ promoted_by: Kibukx
10
+ promoted_by_source: git-config
9
11
  anchors:
10
12
  - path: src/scar/cli.py
11
13
  - path: src/scar/hooks.py
14
+ - path: src/scar/codex.py
15
+ - path: src/scar/cascade.py
12
16
  - pattern: "instrument_disconnected|posttool_silent|verdict_observed"
13
17
  evidence:
14
18
  - issue: 277
15
19
  - issue: 237
16
20
  expires:
17
21
  condition: "the pipeline stops having two independently-installable halves"
18
- status: candidate
22
+ status: active
19
23
  ---
20
24
 
21
25
  The precheck and posttool hooks install separately and fail separately. #237
@@ -1,16 +1,17 @@
1
1
  ---
2
- id: 0
2
+ id: 21
3
3
  type: landmine
4
4
  title: A posttool change in hooks.py does not reach codex.py or cascade.py, which carry their own copy of the same logic
5
5
  severity: high
6
6
  confidence: 0.8
7
7
  created: 2026-09-02
8
8
  authors: ["claude-code"]
9
+ promoted_by: Kibukx
10
+ promoted_by_source: git-config
9
11
  anchors:
10
12
  - path: src/scar/hooks.py
11
13
  - path: src/scar/codex.py
12
14
  - path: src/scar/cascade.py
13
- violation: "if not violations:"
14
15
  evidence:
15
16
  - issue: 277
16
17
  - issue: 293
@@ -18,7 +19,8 @@ evidence:
18
19
  expires:
19
20
  condition: "the three posttool paths share one implementation, or the adapters delegate to hooks.posttool"
20
21
  review_after: 2026-12-01
21
- status: candidate
22
+ violation: "if not violations:"
23
+ status: active
22
24
  ---
23
25
 
24
26
  The posttool verdict logic exists three times: `hooks.posttool` for Claude
@@ -1,13 +1,14 @@
1
1
  ---
2
- id: 0
2
+ id: 22
3
3
  type: landmine
4
4
  title: Codex plugin hooks are not materialized, and untrusted Codex hooks are skipped silently
5
5
  severity: high
6
6
  confidence: 0.9
7
7
  created: 2026-08-28
8
8
  authors: ["claude-code"]
9
+ promoted_by: Kibukx
10
+ promoted_by_source: git-config
9
11
  anchors:
10
- - path: plugin/hooks/hooks.json
11
12
  - path: src/scar/codex.py
12
13
  - pattern: "hooks/hooks\.json|CODEX_HOME|codex-(pretool|posttool|session-notice)"
13
14
  evidence:
@@ -17,7 +18,7 @@ evidence:
17
18
  expires:
18
19
  condition: "Codex materializes a plugin's hooks/hooks.json into the installed cache AND surfaces an error for untrusted hooks"
19
20
  review_after: 2027-02-28
20
- status: candidate
21
+ status: active
21
22
  ---
22
23
 
23
24
  Shipping a Codex hook through a plugin's `hooks/hooks.json` does not deliver it,
@@ -0,0 +1,40 @@
1
+ ---
2
+ id: 0
3
+ type: deadend
4
+ title: Host detection must take home from installer.CLAUDE_DIR, never Path.home() — a bare call passes locally and fails every other machine
5
+ severity: high
6
+ confidence: 0.9
7
+ created: 2026-09-07
8
+ authors: ["claude-code"]
9
+ anchors:
10
+ - pattern: "detect_hosts\("
11
+ - symbol: src/scar/cli.py::_detect
12
+ evidence:
13
+ - issue: 318
14
+ - note: "2026-09-07, during the multi-host skill install work: the skill-install refusal resolved home with Path.home(). Under HOME=empty the suite went 1031 passed / 2 FAILED, both PRE-EXISTING tests, printing 'claude not detected on this machine, nothing written'. Fixed by reusing _detect(). Branch SHAs deliberately omitted: scar #5 fired on the amend that wrote this, and squash-merge would orphan them."
15
+ expires:
16
+ condition: "detect_hosts takes home from one injected seam no caller can bypass"
17
+ review_after: 2027-03-08
18
+ status: candidate
19
+ ---
20
+
21
+ `Path.home()` in a detection path looks obviously right and is a trap. Tests
22
+ patch `installer.CLAUDE_DIR`, not the environment, and `_detect()` derives
23
+ home from `installer.CLAUDE_DIR.parent`. A bare call reads the author's real
24
+ home, finds their real `~/.claude`, and passes. On any machine without one,
25
+ every CI runner included, detection returns nothing and the caller refuses.
26
+
27
+ The failure is invisible where it is introduced: the suite was fully green on
28
+ the authoring machine, and the tests that finally failed were pre-existing
29
+ ones nobody had touched. Use `_detect(kind)`, or `installer.CLAUDE_DIR.parent`
30
+ exactly as `_detect` does. Never add a second answer to where home is.
31
+
32
+ Two anchors on purpose. `cli.py` is 143 KiB and its first `detect_hosts(` sits
33
+ at byte ~123,000, past the 64 KiB `MAX_ANCHOR_SCAN` bound, so the pattern is
34
+ blind to the very file the defect landed in. The `symbol:` anchor covers it,
35
+ at the cost of needing `scar-cli[symbols]`. Lint reports neither gap: the
36
+ pattern matches `hosts.py`, so the scar reads live while blind where it counts.
37
+
38
+ Not armed. The obvious tripwire is `Path\.home\(\)`, but `cli.py` carries that
39
+ string in a warning comment and `installer.py` uses it correctly for module
40
+ constants, so it would fire on prose and on correct code.
@@ -0,0 +1,30 @@
1
+ ---
2
+ id: 0
3
+ type: landmine
4
+ title: A plugin hook manifest is read by every host that installs the plugin, and hosts expand different root variables
5
+ severity: high
6
+ confidence: 0.9
7
+ created: 2026-09-03
8
+ authors: ["claude-code"]
9
+ anchors:
10
+ - path: plugin/
11
+ - path: src/scar/installer.py
12
+ - pattern: "PLUGIN_ROOT"
13
+ evidence:
14
+ - issue: 303
15
+ - issue: 244
16
+ expires:
17
+ condition: "the plugin format gains per-host scoping for hook files"
18
+ review_after: 2026-12-01
19
+ status: candidate
20
+ ---
21
+
22
+ Claude Code merges plugin.json hooks with hooks/hooks.json and defines only
23
+ CLAUDE_PLUGIN_ROOT. Codex reads the same file and defines both PLUGIN_ROOT
24
+ and CLAUDE_PLUGIN_ROOT. A hooks/hooks.json written for Codex with
25
+ ${PLUGIN_ROOT} therefore ran on every Claude session start and Bash call as
26
+ "/hooks/run.sh": No such file or directory, on every machine with the plugin
27
+ (#244 introduced it, #303 removed it). There is no way to mark a plugin
28
+ hook file as one host's only. Ship one manifest per plugin, on
29
+ ${CLAUDE_PLUGIN_ROOT}, and deliver host-specific hooks through
30
+ `scar hook install --runtime <host>`, whose files live outside the plugin.
@@ -0,0 +1,37 @@
1
+ ---
2
+ id: 0
3
+ type: landmine
4
+ title: A whole-file or whole-directory path anchor makes the review-due threshold report anchor breadth, not code hazard
5
+ severity: medium
6
+ confidence: 0.8
7
+ created: 2026-09-04
8
+ authors: ["claude-code"]
9
+ anchors:
10
+ - path: SCAR-FORMAT.md
11
+ - pattern: "review_after_firings"
12
+ evidence:
13
+ - issue: 312
14
+ - note: "triage of all five over-threshold scars in this repo on 2026-09-04: four were over-anchored, one was a real code fix"
15
+ expires:
16
+ condition: "lint reports what share of a scar's firings touched the hazard, so the review-due warning can distinguish breadth from recurrence"
17
+ review_after: 2027-03-04
18
+ status: candidate
19
+ ---
20
+
21
+ `scar lint` warns past `review_after_firings` that either the guarded code
22
+ merits the fix or the scar merits revision. Read literally that sends you to
23
+ the code first. It is usually the anchor.
24
+
25
+ A `path:` anchor is a repo-relative PREFIX, so it fires on every edit beneath
26
+ it. Scar #8 guards a 17-line tty branch inside a 52-line module but anchored
27
+ the whole 3,090-line `src/scar/cli.py`; roughly nine of every ten of its 47
28
+ firings touched nothing related. Scar #5 guards against history rewrites and
29
+ anchored all of `.scars/`, so it fired on 22 routine promotions and zero
30
+ force-pushes, which is zero of its actual trigger events.
31
+
32
+ A firing count therefore measures anchor breadth first and hazard recurrence
33
+ second, and the two are not separable from the log. Before reading a
34
+ review-due warning as evidence that code needs fixing, check what share of the
35
+ firings touched the hazard at all. Then narrow the anchor to the smallest file
36
+ holding the branching, or switch to a `command:` anchor when the trigger is an
37
+ action rather than a file (#312 is the one case here that really was the code).
@@ -26,8 +26,11 @@ The full authoring contract — qualification criteria, the candidates-only writ
26
26
  path, mandatory YAML frontmatter, and the regex over-escaping trap — is packaged
27
27
  as the `scar-authoring` skill.
28
28
 
29
- - **Claude Code:** install the plugin (recommended) or `scar skill install` to
30
- drop the skill into `~/.claude/skills/`. It auto-loads on trigger.
29
+ - **Claude Code, Codex, Cursor, opencode, Windsurf:** `scar skill install`
30
+ detects which of those hosts are on the machine and writes the skill to each
31
+ one's native skills directory. On Claude Code the plugin is the recommended
32
+ route and carries the same skill. The per-host destination table is in
33
+ [website/docs/agents.md](website/docs/agents.md).
31
34
  - **MCP agents (Cursor/Windsurf/opencode):** the `scar_draft` tool enforces the
32
35
  candidates-only path and lints before writing; its description carries the
33
36
  digest.
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.24.0](https://github.com/Daily-Nerd/Scar/compare/v0.23.0...v0.24.0) (2026-09-08)
4
+
5
+
6
+ ### Features
7
+
8
+ * **firing-log:** one shared validated reader for the firing log ([#313](https://github.com/Daily-Nerd/Scar/issues/313)) ([d316922](https://github.com/Daily-Nerd/Scar/commit/d31692205715e63380b8ac104643de4ceac0338d))
9
+ * **skill:** install the authoring skill to every detected host ([#320](https://github.com/Daily-Nerd/Scar/issues/320)) ([1d9c985](https://github.com/Daily-Nerd/Scar/commit/1d9c985e3e5815ba67d222defa86d549886c7e94))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * **promote:** record whether a promotion happened at a terminal ([#315](https://github.com/Daily-Nerd/Scar/issues/315)) ([f28e8eb](https://github.com/Daily-Nerd/Scar/commit/f28e8eb90a5fb3161aa40565dbfb218d1b9b4160)), closes [#308](https://github.com/Daily-Nerd/Scar/issues/308)
15
+
16
+ ## [0.23.0](https://github.com/Daily-Nerd/Scar/compare/v0.22.0...v0.23.0) (2026-09-03)
17
+
18
+
19
+ ### ⚠ BREAKING CHANGES
20
+
21
+ * **install:** with no --runtime, no terminal, and more than one detected host, scar hook install and scar skill install write nothing and print the commands to run instead of installing Claude Code by default.
22
+
23
+ ### Features
24
+
25
+ * **install:** detect installed hosts and the channel that already serves each ([#304](https://github.com/Daily-Nerd/Scar/issues/304)) ([180cf6f](https://github.com/Daily-Nerd/Scar/commit/180cf6f53ab671e6fb9ce6636fe718aabead1c7c))
26
+
3
27
  ## [0.22.0](https://github.com/Daily-Nerd/Scar/compare/v0.21.0...v0.22.0) (2026-09-03)
4
28
 
5
29
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: scar-cli
3
- Version: 0.22.0
3
+ Version: 0.24.0
4
4
  Summary: SCAR — version control for negative knowledge (deadends, fences, landmines)
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -75,20 +75,16 @@ cp .scars/template.md .scars/candidates/redis-sessions.md
75
75
  $EDITOR .scars/candidates/redis-sessions.md
76
76
  scar lint # validate format
77
77
  scar promote redis-sessions.md # human review gate: candidate -> active
78
- scar hook install # Claude Code: inject scars before agent edits
79
- scar skill install # Claude Code: authoring skill into ~/.claude/skills/
80
- scar hook install --runtime windsurf # Windsurf/Cascade: block-once injection
78
+ scar hook install # detects installed hosts, asks which to wire (--all, --runtime X)
79
+ scar skill install # same detection for the scar-authoring skill
80
+ scar hook status # every host with the channel that serves it (settings, plugin, none)
81
81
  ```
82
82
 
83
- Claude Code users: the marketplace **plugin** ships the hooks and the
84
- scar-authoring skill together; the two commands above are the manual fallback.
85
- Re-run `scar skill install` after upgrading — the installed skill is a static copy.
83
+ `scar skill install` writes the scar-authoring skill to a native path for Claude Code, Codex, Cursor, opencode, or Windsurf. Claude Code is the one confirmed to load it, and the rest are written per vendor documentation but unverified: see the [per-host table](https://daily-nerd.github.io/Scar/agents#where-scar-skill-install-writes) for which is which.
86
84
 
87
- Codex users: install and enable the Scar plugin, then open `/hooks` to review
88
- and trust its current hook definitions. The native plugin hooks push matching
89
- scars before `Bash` and `apply_patch` calls and report post-patch `violation:`
90
- tripwires without blocking or rewriting the action. Plugin updates that change
91
- the hook definitions require trust review again.
85
+ Claude Code users: the marketplace **plugin** ships the hooks and the scar-authoring skill together. `scar hook install` and `scar skill install` see the plugin and skip Claude unless you pass `--runtime claude --force`. Re-run `scar skill install` after upgrading a manual install; the installed skill is a static copy.
86
+
87
+ Codex users: run `scar hook install --runtime codex`, then open `/hooks` in Codex to review and trust the entries. The hooks push matching scars before `Bash` and `apply_patch` calls and report post-patch `violation:` tripwires without blocking. The plugin no longer carries Codex hook definitions; the installer is the one path.
92
88
 
93
89
  Full walkthrough, lifecycle commands, and agent wiring (Claude Code plugin,
94
90
  Codex native hooks, Windsurf/Cascade hooks, MCP server, `scar draft-check`):
@@ -60,20 +60,16 @@ cp .scars/template.md .scars/candidates/redis-sessions.md
60
60
  $EDITOR .scars/candidates/redis-sessions.md
61
61
  scar lint # validate format
62
62
  scar promote redis-sessions.md # human review gate: candidate -> active
63
- scar hook install # Claude Code: inject scars before agent edits
64
- scar skill install # Claude Code: authoring skill into ~/.claude/skills/
65
- scar hook install --runtime windsurf # Windsurf/Cascade: block-once injection
63
+ scar hook install # detects installed hosts, asks which to wire (--all, --runtime X)
64
+ scar skill install # same detection for the scar-authoring skill
65
+ scar hook status # every host with the channel that serves it (settings, plugin, none)
66
66
  ```
67
67
 
68
- Claude Code users: the marketplace **plugin** ships the hooks and the
69
- scar-authoring skill together; the two commands above are the manual fallback.
70
- Re-run `scar skill install` after upgrading — the installed skill is a static copy.
68
+ `scar skill install` writes the scar-authoring skill to a native path for Claude Code, Codex, Cursor, opencode, or Windsurf. Claude Code is the one confirmed to load it, and the rest are written per vendor documentation but unverified: see the [per-host table](https://daily-nerd.github.io/Scar/agents#where-scar-skill-install-writes) for which is which.
71
69
 
72
- Codex users: install and enable the Scar plugin, then open `/hooks` to review
73
- and trust its current hook definitions. The native plugin hooks push matching
74
- scars before `Bash` and `apply_patch` calls and report post-patch `violation:`
75
- tripwires without blocking or rewriting the action. Plugin updates that change
76
- the hook definitions require trust review again.
70
+ Claude Code users: the marketplace **plugin** ships the hooks and the scar-authoring skill together. `scar hook install` and `scar skill install` see the plugin and skip Claude unless you pass `--runtime claude --force`. Re-run `scar skill install` after upgrading a manual install; the installed skill is a static copy.
71
+
72
+ Codex users: run `scar hook install --runtime codex`, then open `/hooks` in Codex to review and trust the entries. The hooks push matching scars before `Bash` and `apply_patch` calls and report post-patch `violation:` tripwires without blocking. The plugin no longer carries Codex hook definitions; the installer is the one path.
77
73
 
78
74
  Full walkthrough, lifecycle commands, and agent wiring (Claude Code plugin,
79
75
  Codex native hooks, Windsurf/Cascade hooks, MCP server, `scar draft-check`):
@@ -43,7 +43,7 @@ is deliberate: consumers in hook hot-paths parse with zero dependencies.
43
43
  | `created` | yes | ISO date | |
44
44
  | `authors` | yes | inline list | who drafted it: agents as `"claude-code"` etc. The reviewer is no longer appended here |
45
45
  | `promoted_by` | active scars | string | the human who promoted it. Written only by `scar promote`, which overwrites anything a candidate carried. Empty on scars promoted before the field existed, and never inferred from `authors` |
46
- | `promoted_by_source` | optional | `explicit` \| `git-config` | whether `promoted_by` came from `--reviewer` or from `git config user.name`. Written only alongside `promoted_by`, never on its own. Absent on scars promoted before the field existed |
46
+ | `promoted_by_source` | optional | `explicit` \| `git-config-interactive` \| `git-config` | how strongly `promoted_by` is evidenced. `explicit` = a name was typed with `--reviewer`. `git-config-interactive` = no name typed, but `promote` ran at a terminal, so a person was there. `git-config` = no name typed and no terminal recorded, which is the unattended shape `lint` warns on. Written only alongside `promoted_by`, never on its own. Absent on scars promoted before the field existed, and plain `git-config` on scars promoted before interactivity was recorded, so neither absence proves an agent did it |
47
47
  | `anchors` | yes, ≥1 | list of `- path:`, `- pattern:`, `- symbol:`, and/or `- command:` | §4 |
48
48
  | `evidence` | recommended | list of `- commit:`/`- pr:`/`- issue:`/`- incident:`/`- note:`/`- url:` | absent ⇒ challengeable on sight; `issue:`/`url:` are durable forms that survive squash-merge |
49
49
  | `expires.condition` | recommended | quoted string | what change obsoletes this scar |
@@ -464,3 +464,9 @@ just as well as edit rows do.
464
464
  command output, and asserts the nullable semantics of §9.2. A guarantee no
465
465
  test enforces is an untestable assertion, and untestable assertions are the
466
466
  ones that reach `main` wrong.
467
+
468
+ ### 9.10 Install detection
469
+
470
+ `scar hook install` and `scar skill install` without `--runtime` detect hosts (claude, codex, windsurf, cursor, opencode) by config directory or binary on PATH, and resolve for each the channel that already serves it: `settings` (Scar's own entries in the host's hook file), `plugin` (the scar marketplace plugin installed and not disabled), or `none`. windsurf is repo-scoped: its hooks file is written into the working repo, so the binary on PATH counts only when that repo is inside a git repository. On a terminal, one question per present, wirable, unserved host, default no. Without a terminal, exactly one such host is installed; zero or several means the commands are printed and nothing is written. Zero detected hosts says so, rather than naming the plugin. `--all` wires every such host. `--runtime claude` on a Claude Code already served by the plugin refuses unless `--force`. `--all` and `--force` apply to `install` only, and `--force` applies to `--runtime claude` only. A missing or unreadable plugin registry never counts as `plugin`.
471
+
472
+ Two rules differ for the skill kind. windsurf is not repo-scoped there: its global skills live under home (`~/.codeium/windsurf/skills`), so the binary on PATH counts on its own, with no git-repo guard. And `scar skill install --runtime <host>` refuses, exit 1, when detection does not find that host on the machine, rather than creating a skill directory nothing reads. Every destination resolves through the same home the detection pass used, and the Codex destination honours `$CODEX_HOME`, so a reported success always names a directory the detected host actually reads.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scar",
3
- "version": "0.22.0",
3
+ "version": "0.24.0",
4
4
  "description": "SCAR — version control for negative knowledge (deadends, fences, landmines)",
5
5
  "hooks": {
6
6
  "PreToolUse": [
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "scar-cli"
3
- version = "0.22.0"
3
+ version = "0.24.0"
4
4
  description = "SCAR — version control for negative knowledge (deadends, fences, landmines)"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -3,6 +3,7 @@
3
3
  "packages": {
4
4
  ".": {
5
5
  "release-type": "python",
6
+ "bump-minor-pre-major": true,
6
7
  "extra-files": [
7
8
  {
8
9
  "type": "json",