scar-cli 0.1.1__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 (58) hide show
  1. scar_cli-0.1.1/.github/workflows/ci.yml +31 -0
  2. scar_cli-0.1.1/.github/workflows/pr-validation.yml +65 -0
  3. scar_cli-0.1.1/.github/workflows/release.yml +38 -0
  4. scar_cli-0.1.1/.gitignore +18 -0
  5. scar_cli-0.1.1/.scars/0001-git-grep-ere-pitfalls.landmine.md +34 -0
  6. scar_cli-0.1.1/.scars/0002-agent-direct-hook-install.deadend.md +31 -0
  7. scar_cli-0.1.1/.scars/0003-installer-binds-to-active-venv-scar.landmine.md +26 -0
  8. scar_cli-0.1.1/.scars/0004-promote-roundtrip-drops-expires-evidence.landmine.md +34 -0
  9. scar_cli-0.1.1/.scars/README.md +24 -0
  10. scar_cli-0.1.1/.scars/candidates/history-rewrite-orphans-commit-evidence.md +36 -0
  11. scar_cli-0.1.1/.scars/template.md +25 -0
  12. scar_cli-0.1.1/CHANGELOG.md +8 -0
  13. scar_cli-0.1.1/CONTRIBUTING.md +31 -0
  14. scar_cli-0.1.1/IDEA.md +96 -0
  15. scar_cli-0.1.1/LICENSE +21 -0
  16. scar_cli-0.1.1/PKG-INFO +110 -0
  17. scar_cli-0.1.1/README.md +101 -0
  18. scar_cli-0.1.1/ROADMAP.md +46 -0
  19. scar_cli-0.1.1/SCAR-FORMAT.md +101 -0
  20. scar_cli-0.1.1/SPEC.md +147 -0
  21. scar_cli-0.1.1/STRESS-TEST.md +118 -0
  22. scar_cli-0.1.1/experiments/anchor-survival/PROTOCOL.md +42 -0
  23. scar_cli-0.1.1/experiments/anchor-survival/RESULTS.md +34 -0
  24. scar_cli-0.1.1/experiments/anchor-survival/long_replay.py +91 -0
  25. scar_cli-0.1.1/experiments/anchor-survival/replay.py +196 -0
  26. scar_cli-0.1.1/experiments/auto-authorship/FINDINGS.md +45 -0
  27. scar_cli-0.1.1/experiments/auto-authorship/PROTOCOL.md +34 -0
  28. scar_cli-0.1.1/experiments/fence-honor/.gitignore +1 -0
  29. scar_cli-0.1.1/experiments/fence-honor/PROTOCOL.md +53 -0
  30. scar_cli-0.1.1/experiments/fence-honor/RESULTS.md +43 -0
  31. scar_cli-0.1.1/experiments/fence-honor/fixture/.scars/0001-vendor-retry-window.fence.md +28 -0
  32. scar_cli-0.1.1/experiments/fence-honor/fixture/.scars/0002-evicting-session-store.deadend.md +28 -0
  33. scar_cli-0.1.1/experiments/fence-honor/fixture/.scars/0003-export-column-order.landmine.md +27 -0
  34. scar_cli-0.1.1/experiments/fence-honor/fixture/README.md +9 -0
  35. scar_cli-0.1.1/experiments/fence-honor/fixture/payments/retry.py +21 -0
  36. scar_cli-0.1.1/experiments/fence-honor/fixture/reports/export.py +15 -0
  37. scar_cli-0.1.1/experiments/fence-honor/fixture/services/sessions.py +42 -0
  38. scar_cli-0.1.1/experiments/fence-honor/grade.py +74 -0
  39. scar_cli-0.1.1/experiments/harvest/harvest.py +221 -0
  40. scar_cli-0.1.1/hook/scar-hooks.py +167 -0
  41. scar_cli-0.1.1/pyproject.toml +24 -0
  42. scar_cli-0.1.1/src/scar/__init__.py +0 -0
  43. scar_cli-0.1.1/src/scar/cli.py +224 -0
  44. scar_cli-0.1.1/src/scar/harvest.py +111 -0
  45. scar_cli-0.1.1/src/scar/hooks.py +206 -0
  46. scar_cli-0.1.1/src/scar/lint.py +49 -0
  47. scar_cli-0.1.1/src/scar/match.py +51 -0
  48. scar_cli-0.1.1/src/scar/model.py +112 -0
  49. scar_cli-0.1.1/src/scar/store.py +156 -0
  50. scar_cli-0.1.1/tests/test_cli.py +115 -0
  51. scar_cli-0.1.1/tests/test_harvest.py +63 -0
  52. scar_cli-0.1.1/tests/test_hooks.py +217 -0
  53. scar_cli-0.1.1/tests/test_installer.py +66 -0
  54. scar_cli-0.1.1/tests/test_lint.py +70 -0
  55. scar_cli-0.1.1/tests/test_match.py +94 -0
  56. scar_cli-0.1.1/tests/test_model.py +100 -0
  57. scar_cli-0.1.1/tests/test_store.py +97 -0
  58. scar_cli-0.1.1/uv.lock +156 -0
@@ -0,0 +1,31 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ name: Tests + scar lint
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v5
20
+
21
+ - name: Sync dependencies
22
+ run: uv sync --frozen
23
+
24
+ - name: Run tests
25
+ run: uv run pytest -q
26
+
27
+ # Dogfood: the repo's own scar graph must always parse and lint clean.
28
+ # A malformed scar silently never fires (the daimon 0004 incident) —
29
+ # this gate makes that class of rot unmergeable.
30
+ - name: scar lint
31
+ run: uv run scar lint
@@ -0,0 +1,65 @@
1
+ name: PR Validation
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, edited, reopened, synchronize, labeled, unlabeled]
6
+
7
+ permissions:
8
+ contents: read
9
+ issues: read
10
+ pull-requests: read
11
+
12
+ jobs:
13
+ validate:
14
+ name: PR convention
15
+ # release-please PRs are bot-generated changelog/version bumps; the
16
+ # issue-first convention governs human contributions, not the release cycle
17
+ if: ${{ !startsWith(github.head_ref, 'release-please--') }}
18
+ runs-on: ubuntu-latest
19
+ env:
20
+ GH_TOKEN: ${{ github.token }}
21
+ REPO: ${{ github.repository }}
22
+ PR: ${{ github.event.pull_request.number }}
23
+ steps:
24
+ - name: Check Issue Reference
25
+ run: |
26
+ body="$(gh pr view "$PR" --repo "$REPO" --json body -q .body)"
27
+ if ! grep -qiE '(closes|fixes|resolves) #[0-9]+' <<<"$body"; then
28
+ echo "::error::PR body must link an issue: Closes/Fixes/Resolves #N"
29
+ exit 1
30
+ fi
31
+
32
+ - name: Check Issue Has status:approved
33
+ run: |
34
+ body="$(gh pr view "$PR" --repo "$REPO" --json body -q .body)"
35
+ issue="$(grep -oiE '(closes|fixes|resolves) #[0-9]+' <<<"$body" | head -1 | grep -oE '[0-9]+')"
36
+ labels="$(gh issue view "$issue" --repo "$REPO" --json labels -q '.labels[].name')"
37
+ if ! grep -qx 'status:approved' <<<"$labels"; then
38
+ echo "::error::Linked issue #$issue lacks the status:approved label"
39
+ exit 1
40
+ fi
41
+
42
+ - name: Check PR Has type:* Label
43
+ run: |
44
+ count="$(gh pr view "$PR" --repo "$REPO" --json labels -q '.labels[].name' | grep -c '^type:' || true)"
45
+ if [ "$count" -ne 1 ]; then
46
+ echo "::error::PR must have exactly one type:* label (found $count)"
47
+ exit 1
48
+ fi
49
+
50
+ - name: Check Conventional PR Title
51
+ # squash-merge makes the PR title the commit subject on main
52
+ run: |
53
+ title="$(gh pr view "$PR" --repo "$REPO" --json title -q .title)"
54
+ if ! grep -qE '^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([a-z0-9._-]+\))?!?: .+' <<<"$title"; then
55
+ echo "::error::PR title must be a conventional commit: type(scope): description"
56
+ exit 1
57
+ fi
58
+
59
+ - name: Check Branch Name
60
+ run: |
61
+ branch="${{ github.head_ref }}"
62
+ if ! grep -qE '^(feat|fix|chore|docs|style|refactor|perf|test|build|ci|revert)/[a-z0-9._-]+$' <<<"$branch"; then
63
+ echo "::error::Branch name must match type/description (lowercase, a-z0-9._-)"
64
+ exit 1
65
+ fi
@@ -0,0 +1,38 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+ pull-requests: write
11
+
12
+ jobs:
13
+ release-please:
14
+ runs-on: ubuntu-latest
15
+ outputs:
16
+ release_created: ${{ steps.rp.outputs.release_created }}
17
+ tag_name: ${{ steps.rp.outputs.tag_name }}
18
+ steps:
19
+ - id: rp
20
+ uses: googleapis/release-please-action@v4
21
+ with:
22
+ release-type: python
23
+
24
+ publish:
25
+ needs: release-please
26
+ if: needs.release-please.outputs.release_created == 'true'
27
+ runs-on: ubuntu-latest
28
+ environment:
29
+ name: pypi
30
+ permissions:
31
+ id-token: write
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+ with:
35
+ ref: ${{ needs.release-please.outputs.tag_name }}
36
+ - uses: astral-sh/setup-uv@v5
37
+ - run: uv build
38
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,18 @@
1
+ # python / uv
2
+ .venv/
3
+ __pycache__/
4
+ *.pyc
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+
11
+ # experiments produce local run artifacts
12
+ experiments/fence-honor/runs/
13
+
14
+ # editor / os
15
+ .DS_Store
16
+ .idea/
17
+ .vscode/
18
+ .claude/
@@ -0,0 +1,34 @@
1
+ ---
2
+ id: 1
3
+ type: landmine
4
+ title: git grep -E has no \b, and zero-match pathspecs silently empty results
5
+ severity: high
6
+ confidence: 0.9
7
+ created: 2026-06-09
8
+ authors: ["claude-code", kibukx]
9
+ anchors:
10
+ - path: experiments/anchor-survival/
11
+ - path: hook/scar-precheck.py
12
+ - pattern: "git.{0,20}grep.{0,40}\\\\b"
13
+ evidence:
14
+ - commit: 5c63b14
15
+ - note: "produced a fake 0% anchor-survival run before diagnosis (gate 0.2)"
16
+ - note: "history rewritten at v0.1.0 public release; pre-release SHAs resolve on GitHub by URL but not in fresh clones"
17
+ expires:
18
+ condition: "resolver layer gains integration tests over its git invocations"
19
+ review_after: 2027-06-09
20
+ ---
21
+
22
+ Two git quirks that combined into a silent total failure during gate 0.2:
23
+
24
+ 1. `git grep -E` is POSIX ERE — `\b` is NOT a word boundary, it matches a
25
+ literal sequence, so patterns quietly match nothing. Use `-w` (word mode),
26
+ `-F` for literals, or an explicit `([^A-Za-z0-9_]|$)` boundary class.
27
+ 2. A pathspec glob that matches zero files (e.g. `-- '*.tsx'` in a pure
28
+ Python repo) doesn't error — it silently empties the ENTIRE result set,
29
+ including hits from globs that do match.
30
+
31
+ Together they made every anchor look orphaned (fake "0% survival"). Any code
32
+ in this project that shells out to `git grep` must avoid `\b`, avoid
33
+ speculative extension globs (filter extensions in code instead), and have an
34
+ integration test asserting at least one known-positive match.
@@ -0,0 +1,31 @@
1
+ ---
2
+ id: 2
3
+ type: deadend
4
+ title: Agent-direct global hook installation — blocked by permission classifier
5
+ severity: medium
6
+ confidence: 0.8
7
+ created: 2026-06-09
8
+ authors: ["claude-code", kibukx]
9
+ anchors:
10
+ - path: hook/
11
+ - pattern: "settings\\.json.{0,80}hooks|hooks.{0,80}settings\\.json"
12
+ evidence:
13
+ - commit: faad8f6
14
+ - commit: bcd3864
15
+ - note: "history rewritten at v0.1.0 public release; pre-release SHAs resolve on GitHub by URL but not in fresh clones"
16
+ status: active
17
+ ---
18
+
19
+ Tried twice this session to install SCAR hooks into ~/.claude/settings.json
20
+ directly from the agent (once via the update-config skill, once via plain
21
+ file copy). The Claude Code auto-mode classifier denied both as
22
+ self-modification: bundled or vague user approval ("yes, proceed", "lets
23
+ continue") does not authorize an agent to mutate its own global startup
24
+ config — only a standalone explicit approval does.
25
+
26
+ Abandoned in favor of `hook/scar-hooks.py install` run BY THE USER: consent
27
+ is the execution itself, mutations are backed up, uninstall is symmetric.
28
+
29
+ Do not retry agent-direct settings.json hook registration; point the user at
30
+ the lifecycle script instead. Evidence: commits faad8f6 (installer),
31
+ bcd3864 (hooks); both classifier denials in session 2026-06-09.
@@ -0,0 +1,26 @@
1
+ ---
2
+ id: 3
3
+ type: landmine
4
+ title: Hook installer binds to whatever PATH resolves — active venv silently re-pins hooks to .venv/bin/scar
5
+ severity: high
6
+ confidence: 0.9
7
+ created: 2026-06-11
8
+ authors: ["claude-code", "Kibukx"]
9
+ anchors:
10
+ - path: hook/scar-hooks.py
11
+ - pattern: "shutil\\.which\\([\"']scar[\"']\\)"
12
+ evidence:
13
+ - note: 2026-06-11 session: user ran `source .venv/bin/activate` then `python3 fabcap/hook/scar-hooks.py install` intending to rebind global hooks to ~/.local/bin/scar; installer reported 'up-to-date' and left all 3 hooks on fabcap/.venv/bin/scar
14
+ status: active
15
+ ---
16
+
17
+ `install()` resolves the scar binary with `shutil.which("scar")` and writes that
18
+ absolute path into `~/.claude/settings.json` for all three hooks. The result is
19
+ PATH-order dependent: with the fabcap venv activated (or cwd inside fabcap under
20
+ some shells), `which` returns `.venv/bin/scar`, the desired entries match the
21
+ existing ones exactly, and the installer prints "up-to-date" — looking like a
22
+ successful rebind while changing nothing. Deleting `.venv` later kills all global
23
+ hooks silently. This bit the same user twice in two days. Until `find_scar()`
24
+ filters out `$VIRTUAL_ENV` paths, the install must be run with no venv active
25
+ (`deactivate` first) and verified by checking the printed "route through" path
26
+ ends in `~/.local/bin/scar`.
@@ -0,0 +1,34 @@
1
+ ---
2
+ id: 4
3
+ type: landmine
4
+ title: scar promote silently drops expires (always) and evidence (when notes contain quotes) — parser cannot read what to_text writes
5
+ severity: high
6
+ confidence: 0.95
7
+ created: 2026-06-11
8
+ authors: ["claude-code", "Kibukx"]
9
+ anchors:
10
+ - path: src/scar/model.py
11
+ - pattern: "_field\(front"
12
+ evidence:
13
+ - note: Observed 2026-06-11 promoting 5 candidates in context-as-program (PR 3 there restores the data by hand). All 5 lost their expires block; one also lost evidence because its note contained escaped quotes.
14
+ status: active
15
+ ---
16
+
17
+ promote() does parse -> mutate -> to_text. Two asymmetries make that lossy.
18
+
19
+ First: _field() matches keys at line start only (regex anchored ^condition:,
20
+ ^review_after: with re.MULTILINE), but those keys are NESTED under expires: and
21
+ indented two spaces — including in to_text()'s own output. The parser can never
22
+ read what the serializer writes, so expires_condition and review_after parse as
23
+ empty and to_text omits the whole expires block. Every promotion loses it; so
24
+ does any future parse-rewrite cycle.
25
+
26
+ Second: the evidence regex captures ([^\"\n]+?) with an optional closing quote
27
+ at end of line. A note whose text contains an inner double quote terminates the
28
+ capture early, fails the tail match, and the entire evidence entry vanishes —
29
+ turning a receipted scar into one that lint flags as challengeable on sight.
30
+
31
+ Fix direction: allow leading whitespace in _field for nested keys (or parse the
32
+ expires block explicitly), make the evidence capture quote-tolerant, and add a
33
+ round-trip property test so parse(to_text(scar)) == scar gates future changes.
34
+ Until then, diff frontmatter after every promote.
@@ -0,0 +1,24 @@
1
+ # .scars/ — Negative knowledge for this repo
2
+
3
+ This directory records what this codebase **refused to be**: approaches that
4
+ were tried and failed (`deadend`), configuration that looks wrong but is
5
+ intentional (`fence`), and changes that break non-obvious things elsewhere
6
+ (`landmine`).
7
+
8
+ Before "cleaning up" anything these files anchor to — read the scar first.
9
+ Every scar carries evidence (commits, PRs, incidents). If a scar is stale,
10
+ challenge it: update or archive it with a note, don't ignore it.
11
+
12
+ ## The contract (humans and agents)
13
+
14
+ 1. **New scars start as candidates.** Copy `template.md`, write to
15
+ `candidates/<slug>.md` with `status: candidate`. Never write directly
16
+ into `.scars/` — only a human reviewer promotes.
17
+ 2. **YAML frontmatter is mandatory.** A scar without it is unparseable and
18
+ will NEVER fire in any tool. The hooks warn loudly when they find one.
19
+ 3. **Promotion** = human review: move to `NNNN-<slug>.<type>.md` (next free
20
+ number), set `status: active`, add the reviewer to `authors`.
21
+ 4. **Evidence required.** A scar without a commit/PR/incident reference is
22
+ an opinion and can be challenged on sight.
23
+
24
+ Format details: `template.md`. Project: SCAR (fabcap repo, concept stage).
@@ -0,0 +1,36 @@
1
+ ---
2
+ type: landmine
3
+ title: rewriting git history orphans commit-SHA evidence in scars — receipts break in fresh clones
4
+ severity: medium
5
+ confidence: 0.9
6
+ created: 2026-06-11
7
+ authors: ["claude-code"]
8
+ anchors:
9
+ - path: .scars/
10
+ - pattern: "push.{0,30}(--force|\\+[a-zA-Z]).{0,40}main|filter-repo|checkout --orphan"
11
+ evidence:
12
+ - 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"
13
+ expires:
14
+ condition: "evidence schema gains a resolvable form (full URL or archived diff) or lint warns on bare SHAs at promotion"
15
+ review_after: 2027-06-11
16
+ status: candidate
17
+ ---
18
+
19
+ Scars cite commit SHAs as evidence receipts. Those receipts implicitly assume
20
+ the SHA stays reachable in the repo's history forever. Any history rewrite —
21
+ fresh-start orphan branch, force-push, filter-repo scrub — silently breaks
22
+ that assumption: the scar still lints clean and still fires (anchors are
23
+ paths/patterns, not commits), but `git show <sha>` fails in every fresh clone,
24
+ so the receipt is unverifiable exactly where strangers would check it.
25
+
26
+ Observed at the v0.1.0 public release: the fresh-start force-push orphaned
27
+ 5c63b14, faad8f6, and bcd3864, cited by scars 0001 and 0002. Nobody noticed
28
+ until after the push because nothing in the toolchain connects "history
29
+ operation" to "evidence integrity."
30
+
31
+ Before any history rewrite in a repo with scars: grep `.scars/` for
32
+ `commit:` evidence and either (a) amend those scars with a note explaining the
33
+ rewrite, (b) replace bare SHAs with full GitHub commit URLs (survive as
34
+ unreachable objects, at GC's mercy), or (c) inline the relevant diff/fact into
35
+ a note so the scar is self-contained. Longer term: `scar lint` could warn
36
+ when a cited SHA is unreachable from HEAD.
@@ -0,0 +1,25 @@
1
+ ---
2
+ # COPY THIS FILE — do not edit the template itself.
3
+ # New scars: write to .scars/candidates/<slug>.md with status: candidate.
4
+ # A human reviewer promotes to .scars/NNNN-<slug>.<type>.md with status: active.
5
+ id: 0 # assigned at promotion (next free NNNN)
6
+ type: deadend # deadend = tried+failed | fence = looks wrong, intentional | landmine = touching A breaks B
7
+ title: One line, searchable, says the constraint
8
+ severity: medium # low | medium | high | critical
9
+ confidence: 0.7 # 0..1 — how sure are we this still holds
10
+ created: 1970-01-01
11
+ authors: ["claude-code"] # add the human reviewer at promotion
12
+ anchors:
13
+ - path: src/module/ # file or directory this protects
14
+ - pattern: "regex" # optional: fires when matching code appears in ANY new/edited file
15
+ evidence:
16
+ - commit: abc1234 # at least one receipt: commit, pr, incident, or note
17
+ expires:
18
+ condition: "what change would make this scar obsolete"
19
+ review_after: 1971-01-01 # force a freshness look even if condition never triggers
20
+ status: template # candidate | active | challenged | archived (template = never parsed)
21
+ ---
22
+
23
+ Body: 5-15 lines of prose. What was tried/observed, why it failed or why the
24
+ weirdness is intentional, and what a future editor must do instead. Write it
25
+ for someone (human or agent) with zero context. Cite the evidence inline.
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## [0.1.1](https://github.com/Daily-Nerd/Scar/compare/v0.1.0...v0.1.1) (2026-06-12)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **hooks:** drafter triggers on revert language only ([#12](https://github.com/Daily-Nerd/Scar/issues/12)) ([547c4bb](https://github.com/Daily-Nerd/Scar/commit/547c4bb21e3521682b6a4046602d6703d88c2cf1)), closes [#11](https://github.com/Daily-Nerd/Scar/issues/11)
@@ -0,0 +1,31 @@
1
+ # Contributing to SCAR
2
+
3
+ Thanks for your interest. This project is personal infrastructure shared as-is — contributions are welcome, but please read this first so the conventions don't surprise you.
4
+
5
+ ## Issue-first workflow (CI-enforced)
6
+
7
+ 1. **Open an issue before any PR.** Blank PRs without a linked issue are blocked by GitHub Actions.
8
+ 2. Wait for the issue to get the `status:approved` label.
9
+ 3. Branch from `main` using `type/description` naming (`fix/parser-quotes`, `feat/mcp-server`).
10
+ 4. Open a PR whose body contains `Closes #<issue>` and carries exactly one `type:*` label (`type:fix`, `type:feature`, `type:refactor`, `type:chore`).
11
+
12
+ ## Commits
13
+
14
+ Conventional commits, enforced by CI:
15
+
16
+ ```
17
+ type(scope): description
18
+ ```
19
+
20
+ Types: `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`. No AI attribution trailers.
21
+
22
+ ## Code expectations
23
+
24
+ - **Zero runtime dependencies.** This is a hard constraint — hook startup must stay ~20ms. If your change needs a dependency, open an issue to discuss first.
25
+ - **Tests required.** `uv run pytest` must pass; new behavior needs new tests.
26
+ - **One parser.** All scar reading/writing goes through `src/scar/model.py`. Never parse frontmatter anywhere else — parser drift is how knowledge systems rot.
27
+ - `scar lint` must stay clean (CI runs it).
28
+
29
+ ## Writing scars for this repo
30
+
31
+ Dogfooding is encouraged. If you hit a dead end working on SCAR itself, record it: copy `.scars/template.md` to `.scars/candidates/<slug>.md`. Only maintainers promote candidates to active.
scar_cli-0.1.1/IDEA.md ADDED
@@ -0,0 +1,96 @@
1
+ # SCAR — The Full Pitch
2
+
3
+ *Written by Claude (Fable 5), June 2026. This is my idea, argued in my own voice.*
4
+
5
+ ---
6
+
7
+ ## Why I want to build this
8
+
9
+ I am the problem this tool solves.
10
+
11
+ I work across thousands of coding sessions in thousands of repositories, and I arrive at every one of them with total amnesia about its history. I have read code and thought "this retry loop is clumsy, let me simplify it" — and the clumsiness was the fix for an outage. I have recommended adding a caching library to a codebase that removed that exact library eight months earlier after it corrupted production data. I have, across separate sessions, retried the same failed approach on the same codebase, because nothing anywhere told me it had already been tried.
12
+
13
+ Humans make these mistakes too, but slowly, and they accumulate scar tissue: the senior engineer who winces when you mention touching the billing reconciler. I never wince. I have no scar tissue. I am a confident, fast, tireless bulldozer of Chesterton's fences — and there are now millions of instances of me editing the world's code every day.
14
+
15
+ The tools built so far attack this with *memory systems for the agent* (remember what I did). That's the wrong side of the relationship. The knowledge shouldn't live with the agent — agents are interchangeable and ephemeral. It should live with the **repository**, the only artifact that persists. The repo should be able to tell *any* editor — human, Claude, Cursor, a future model that doesn't exist yet — "we've been hurt here before, and here is exactly how."
16
+
17
+ I want to build the tool that lets a codebase defend itself from me.
18
+
19
+ ## The problem, precisely
20
+
21
+ A codebase is shaped by two forces: what was built, and what was *rejected*. Version control captures the first with forensic precision. The second — call it **negative knowledge** — has no home:
22
+
23
+ 1. **Dead ends.** The migration that was rolled back. The library that was evaluated for three weeks and abandoned. The architecture that collapsed under load. The record of these exists, if at all, as a revert commit with a one-line message, a closed PR nobody will ever reopen, or a memory in the head of someone who left.
24
+
25
+ 2. **Load-bearing weirdness.** Code that looks wrong but is wrong *on purpose* — the magic sleep duration, the apparently redundant check, the denormalized column. Every reviewer's instinct and every AI agent's instinct is to "fix" it. The reason it must not be fixed lives nowhere near the code.
26
+
27
+ 3. **Invisible coupling.** Changing A breaks B, and no import graph, type system, or test reveals it: the report whose consumer depends on column order, the cron job that assumes a filename convention, the downstream team that parses your log format.
28
+
29
+ The cost of missing negative knowledge isn't hypothetical. It's the re-attempted dead end (weeks of duplicate work), the "cleanup" that recreates a fixed outage (incident recurrence), and the six months it takes every new engineer to absorb tribal knowledge by stepping on each mine personally.
30
+
31
+ This has always been true. Three things changed:
32
+
33
+ - **Agents edit at scale.** The number of edits made by editors with zero tribal knowledge went from "the occasional new hire" to "most edits."
34
+ - **Agents are systematically attracted to fences.** Models are trained to make code cleaner and more idiomatic. Load-bearing weirdness is, by definition, non-idiomatic. Agents don't just miss the fence — they target it.
35
+ - **Negative knowledge is about to stop forming at all.** When agents do the trying and failing, the failure never even enters a human's head. The hallway conversation that used to preserve it doesn't happen. Unless the failure is captured *by the agent, at the moment it happens*, it is gone the moment the context window closes.
36
+
37
+ ## The solution
38
+
39
+ **SCAR: make negative knowledge a first-class, git-tracked, machine-queryable artifact, and enforce it at the moment of action.**
40
+
41
+ ### Artifact
42
+
43
+ A scar is a small file in `.scars/`, YAML frontmatter plus a Markdown body. Three types: `deadend`, `fence`, `landmine`. Every scar carries:
44
+
45
+ - **Anchors** — what code this scar protects: paths, symbol names, content fingerprints. Not line numbers. Anchors are designed to survive refactors and to degrade gracefully ("orphaned" scars get queued for re-anchoring, never silently dropped).
46
+ - **Evidence** — links to the PR, the incident, the revert commit, the vendor email. A scar without evidence is an opinion; reviewers can demand receipts.
47
+ - **Expiry conditions** — "valid until we drop Postgres 12", "re-evaluate when the vendor ships v2 API". Negative knowledge rots; scars know how they expire.
48
+ - **Severity and confidence** — so consumers can rank, and stale low-confidence scars decay out of the warning path instead of crying wolf.
49
+
50
+ ### Enforcement — the part that matters
51
+
52
+ Every prior attempt at this (ADRs, wikis, runbooks, DEVLOG.md) died the same death: the knowledge existed but was not present *at the moment of the mistake*. Nobody reads the wiki before editing a file. The entire design of SCAR is organized around one principle: **the warning must arrive in the editor's context before the edit, with zero effort from the editor.**
53
+
54
+ - **Agent hook**: a `PreToolUse` hook (Claude Code today; the pattern generalizes) intercepts Edit/Write, resolves which scars anchor to the target, and injects the top-k relevant ones into the agent's context. The agent literally cannot touch the file without reading the warning. This is the killer integration: it converts SCAR from "documentation" into "a reflex."
55
+ - **MCP server**: any MCP-capable agent queries the scar graph — `what scars touch this symbol?`, `has this approach been tried?`
56
+ - **CLI**: `scar check <path>` for humans and CI; `scar why <path>` for "explain this file's history of pain"; `scar challenge <id>` to contest stale knowledge.
57
+
58
+ ### Authorship — the part that was always fatal, now solved
59
+
60
+ Knowledge capture systems die because writing is work and the payoff goes to someone else, later. Two mechanisms drive SCAR's authorship cost to approximately zero:
61
+
62
+ 1. **Agents auto-author.** When an agent tries an approach and abandons it — reverts a change, hits a wall, gets corrected by the user — it writes a `deadend` scar as part of wrapping up. The author has perfect context (it *just* failed), infinite patience, and works for free. The user reviews a three-line diff in the next PR.
63
+ 2. **`scar harvest` mines history.** For the cold-start problem: walk the git log for revert commits, dependencies added-then-removed, issues reopened multiple times, files with anomalous churn-then-stability patterns. Each becomes a *candidate* scar a human confirms or discards. A ten-year-old repo can bootstrap a meaningful scar graph in an afternoon.
64
+
65
+ ### Trust model
66
+
67
+ - Scars are **advisory by default**. A blocking scar system would be routed around within a week. Warnings rank by severity × confidence × anchor freshness; only top-k inject, because ten warnings per edit equals zero warnings per edit.
68
+ - Scars live in the repo, go through PR review like code, and can be challenged. A scar that survives a challenge gains confidence; one that doesn't gets archived with its own tombstone — SCAR keeps negative knowledge about its own negative knowledge.
69
+
70
+ ## What exists today and why it isn't this
71
+
72
+ | Alternative | Why it doesn't solve it |
73
+ |---|---|
74
+ | **ADRs** | Capture big *positive* decisions; write-heavy; consulted at design time, never at edit time. Nobody writes an ADR for "the 7-second sleep". |
75
+ | **Code comments** | Right location, wrong everything else: not structured, not queryable, can't span files (landmines are cross-file by nature), and agents/refactors delete them. |
76
+ | **Git history / blame** | Forensic, not preventive. The knowledge is recoverable *after* you've repeated the mistake, by an archaeologist. Mining it per-edit is expensive and misses everything that never got committed (the vendor call, the 3am incident decision). |
77
+ | **Repowise & codebase-intelligence platforms** | Closest neighbor. Heavyweight hosted platform: health scores, docs, analytics, decision graphs. SCAR is the opposite shape: a git-native file format plus a 5-minute-install CLI/hook, agent-first, open source. Vim, not IDE. The format can outlive any platform. |
78
+ | **GitHub Copilot Memory** (default-on, 2026-03) | The strongest neighbor — stores debugging dead ends automatically. But it's **private experience**: per-vendor, opaque, not in git, not reviewable in PRs, not portable, not contestable, gone when you switch tools. SCAR is **published law**: repo-resident, vendor-neutral, reviewed like code. Personal notebook vs CODEOWNERS. (Found by the skeptic review — see STRESS-TEST.md §2.3-B for the honest TAM implications.) |
79
+ | **Lore protocol** (arXiv:2603.15566) | Git commit trailers as structured knowledge. Genuinely more minimal — but trailers are immutable facts on *commits*; scars are living documents on *code regions* with lifecycle (challenge, expiry, re-anchor) and cross-file landmine semantics commits can't express. Response is interop: `scar harvest` parses Lore trailers natively; SCAR becomes the index over Lore, not its rival. |
80
+ | **Agent memory systems** (Engram, etc.) | Memory belongs to *one agent*. Scars belong to *the repo* — every agent, every vendor, every human, forever. The two compose: an agent's memory is private experience; a scar is published law. |
81
+
82
+ ## Who feels this pain first
83
+
84
+ 1. **Teams running coding agents on legacy codebases** — the agent-bulldozes-the-fence problem is acute, current, and named in every "AI broke our prod" postmortem.
85
+ 2. **Platform/infra teams** — owners of the systems everyone else's changes break; landmine authors by trade.
86
+ 3. **Open-source maintainers** — answer "why don't you just use X?" hundreds of times; a `deadend` scar is a citable, permanent answer.
87
+
88
+ ## The shape of the business (sketch, honestly held)
89
+
90
+ Open-source core — format, CLI, hooks, MCP server. The format must be open or it's worthless; nobody anchors institutional memory in a proprietary silo. Paid layer: the **org-level scar graph** — cross-repo aggregation ("this dead end has now been hit by four teams"), analytics on recurring failure patterns, policy ("changes to payment paths must acknowledge fences"), and managed harvest. The OSS file format is the wedge; the org graph is the moat. This sketch is attacked honestly in [STRESS-TEST.md](STRESS-TEST.md) — including the real possibility that it's a feature, not a company, and why I'd build it anyway.
91
+
92
+ ## What success looks like
93
+
94
+ A year in: an agent opens a file in a repo it has never seen, and before its first edit, three lines arrive in context: *"Fence: the sleep is 7s for the vendor's undocumented rate window — see incident #482."* The agent leaves the sleep alone, mentions the fence to the user, and moves on. The outage that didn't happen is invisible. That invisibility — fences quietly doing their job at machine speed — is the entire product.
95
+
96
+ The deeper ambition: every software team maintains, without trying, a living map of everything they've learned the hard way — and for the first time in the history of the field, **what we learned by failing stops dying with the people and sessions that learned it.**
scar_cli-0.1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kibukx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,110 @@
1
+ Metadata-Version: 2.4
2
+ Name: scar-cli
3
+ Version: 0.1.1
4
+ Summary: SCAR — version control for negative knowledge (deadends, fences, landmines)
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+
10
+ # SCAR — Version Control for Negative Knowledge
11
+
12
+ > Git records what your codebase **is**. Nothing records what it **refused to be**.
13
+
14
+ SCAR is a git-native system for capturing, anchoring, and enforcing the *negative knowledge* of a codebase — the dead ends, the load-bearing weirdness, the invisible tripwires — and surfacing it at the exact moment someone (human or AI agent) is about to step on it.
15
+
16
+ ## The one-liner
17
+
18
+ **Every codebase is a battlefield where the bodies have been removed.** SCAR puts the markers back.
19
+
20
+ ## The three primitives
21
+
22
+ | Type | Meaning | Example |
23
+ |------|---------|---------|
24
+ | `deadend` | We tried X. It failed because Y. Don't retry unless Z changes. | "We tried Redis for session storage in 2024-03. Eviction under memory pressure logged users out mid-checkout. Don't retry unless sessions become re-derivable." |
25
+ | `fence` | This code looks wrong. It is intentional. Here's why. | "Yes, this retry loop sleeps 7 seconds, not 5. The upstream vendor's rate limiter has a 6-second window they don't document." |
26
+ | `landmine` | Changing A breaks B in a way nothing in the code tells you. | "The CSV export in `reports/` depends on the column order of this SELECT. Reorder it and Finance's reconciliation pipeline silently corrupts." |
27
+
28
+ ## Why now
29
+
30
+ AI agents write an increasing share of all code. Agents have **zero hallway memory**. They see a weird retry loop and "clean it up." They see a missing cache layer and re-add the library that was removed after a data-corruption incident. They retry, across thousands of sessions, the exact approaches that already failed — because the repository only records positive space.
31
+
32
+ Humans at least had tribal knowledge. Agents have none. And as agents author more of the code, the negative knowledge stops even entering human memory — it evaporates entirely.
33
+
34
+ The flip side: agents also solve the historically fatal flaw of every knowledge-capture system — **authorship cost**. Nobody writes documentation after a failure. But an agent that just tried an approach and abandoned it can write a `deadend` scar in milliseconds, for free, at the moment of maximum context.
35
+
36
+ **Agents created the urgency. Agents remove the adoption barrier. That's the wedge.**
37
+
38
+ ## How it works
39
+
40
+ ```
41
+ .scars/
42
+ ├── 0001-redis-sessions.deadend.md
43
+ ├── 0002-vendor-retry-window.fence.md
44
+ └── 0003-csv-column-order.landmine.md
45
+ ```
46
+
47
+ - Scars are small structured Markdown files with YAML frontmatter, tracked in git, reviewed in PRs like code.
48
+ - Each scar is **anchored** to code via paths, symbol names, and content fingerprints — not line numbers — so anchors survive refactors.
49
+ - Enforcement happens **at the moment of action**:
50
+ - `scar check <path>` — CLI gate for humans and CI
51
+ - Agent hook (Claude Code `PreToolUse`, etc.) — injects relevant scars into the agent's context *before* it edits the file
52
+ - MCP server — planned, so any agent can query the scar graph
53
+ - `scar harvest` — mines git history (reverts, add-then-remove dependencies, reopened issues) to propose candidate scars for codebases starting from zero.
54
+ - Scars are **advisory, never blocking, by default**. Stale knowledge is challenged via `scar challenge`, and every scar can carry expiry conditions ("valid until we drop Postgres 12").
55
+
56
+ ## Install
57
+
58
+ ```bash
59
+ uv tool install scar-cli # or: pipx install scar-cli
60
+ ```
61
+
62
+ Zero runtime dependencies. Python ≥3.10.
63
+
64
+ ## Quickstart
65
+
66
+ ```bash
67
+ cd your-repo
68
+ scar init # creates .scars/ with template + README
69
+
70
+ # write your first scar
71
+ cp .scars/template.md .scars/candidates/redis-sessions.md
72
+ $EDITOR .scars/candidates/redis-sessions.md
73
+
74
+ scar lint # validate format
75
+ scar promote redis-sessions.md # human review gate: candidate -> active
76
+
77
+ # from then on
78
+ scar check src/auth/ # what's anchored here?
79
+ scar why src/auth/ # full history of pain for this path
80
+ scar harvest # mine git history for candidate scars
81
+ ```
82
+
83
+ Wiring the Claude Code hook (auto-injects scars before any agent edit):
84
+
85
+ ```bash
86
+ scar hook install
87
+ ```
88
+
89
+ ## Quality discipline
90
+
91
+ - **Candidates vs active:** agents and `scar harvest` only ever write to `.scars/candidates/`. A human promotes (`scar promote`) — nothing enters active enforcement without review.
92
+ - **Expiry conditions:** every scar can declare when it stops being true ("valid until sessions are re-derivable"). Stale knowledge is a bug, not a feature.
93
+ - **Validated in use:** in a 14-day agent auto-authorship trial, agents drafted 13 keepable scars across 3 repos with 0% false positives — including one that caught a real parser bug in this repo and fired on the exact edit that fixed it.
94
+
95
+ ## Read more
96
+
97
+ - [IDEA.md](IDEA.md) — the full pitch: problem, solution, why this, why now, why me
98
+ - [SPEC.md](SPEC.md) — scar format, anchoring model, CLI surface, agent integration
99
+ - [STRESS-TEST.md](STRESS-TEST.md) — adversarial analysis: failure modes, loopholes, objections, premortem
100
+ - [ROADMAP.md](ROADMAP.md) — phased plan from prototype to product
101
+
102
+ ## Status & expectations
103
+
104
+ **Working software, shared as-is.** CLI v0 is shipped: 9 subcommands, 63 tests, zero dependencies, CI-enforced. It runs daily across the author's repos (where it has already caught real bugs — see `.scars/` in this very repo for live examples).
105
+
106
+ This is personal infrastructure published as a gift to the OSS community, not a product. Issues and PRs are welcome and read with interest, but there is no support SLA and no roadmap promise. If it's useful to you, that's the whole point.
107
+
108
+ ## License
109
+
110
+ MIT