SCAR — version control for negative knowledge (deadends, fences, landmines)
Project description
SCAR — Version Control for Negative Knowledge
Git records what your codebase is. Nothing records what it refused to be.
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.
The one-liner
Every codebase is a battlefield where the bodies have been removed. SCAR puts the markers back.
The three primitives
| Type | Meaning | Example |
|---|---|---|
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." |
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." |
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." |
Why now
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.
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.
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.
Agents created the urgency. Agents remove the adoption barrier. That's the wedge.
How it works
.scars/
├── 0001-redis-sessions.deadend.md
├── 0002-vendor-retry-window.fence.md
└── 0003-csv-column-order.landmine.md
- Scars are small structured Markdown files with YAML frontmatter, tracked in git, reviewed in PRs like code.
- Each scar is anchored to code via paths, symbol names, and content fingerprints — not line numbers — so anchors survive refactors.
- Enforcement happens at the moment of action:
scar check <path>... [--diff FILE] --exit-code— CLI gate for humans and CI (non-zero exit when a scar fires)- Agent hook (Claude Code
PreToolUse, etc.) — injects relevant scars into the agent's context before it edits the file. Path-only matches render as one-line hints; the full scar body is injected only when the edit content or a symbol actually trips the scar's pattern — and a body already shown for the same file in the last 4 hours collapses to a one-liner. - A scar can also declare an optional
violation:regex — a post-edit compliance tripwire (Claude CodePostToolUse) that flags when the code an agent just wrote actually does the forbidden thing, andscar check --diff --exit-codegates on the same pattern in CI. scar mcp— local MCP server, so MCP-capable agents can query and draft scars
scar harvest— mines git history (reverts, add-then-remove dependencies, reopened issues) to propose candidate scars for codebases starting from zero.- Scars are advisory, never blocking, by default — and stale knowledge has a lifecycle:
scar challenge <id> --reasondisputes a scar (it still fires, marked as disputed),scar archive <id> --reasonretires it (never fires again;scar whykeeps the history), andscar lint/scar statussurface any scar whosereview_afterdate has passed. Nothing expires automatically — archiving is a human decision, same governance as promotion.
Install
uv tool install scar-cli # or: pipx install scar-cli
The parser and agent hook hot-path are stdlib-only; the human-facing CLI adds
rich + rich-argparse for formatted output. Python ≥3.10.
Quickstart
cd your-repo
scar init # creates .scars/ with template + README
# write your first scar
cp .scars/template.md .scars/candidates/redis-sessions.md
$EDITOR .scars/candidates/redis-sessions.md
scar lint # validate format
scar promote redis-sessions.md # human review gate: candidate -> active
# from then on
scar check src/auth/ # what's anchored here?
scar why src/auth/ # full history of pain for this path
scar harvest # mine git history for candidate scars
Wiring the Claude Code hook (auto-injects scars before any agent edit):
scar hook install
scar hook status
Hooks are advisory and are installed only by this explicit user command. To
stop all automatic injection and drafting while keeping the repository's
.scars/ records:
scar hook uninstall
Recommended (Claude Code): install the plugin so the hooks and the scar-authoring skill arrive together via the marketplace.
Fallback / non-marketplace: scar hook install registers the hooks, and
scar skill install drops the authoring skill into ~/.claude/skills/. Both are
explicit — you run them, nothing is installed as a side effect.
Non-Claude agents: scar agent skill prints the authoring skill for any runtime;
MCP agents get the digest via the scar_draft tool description.
Wiring MCP-capable agents:
scar agent doctor
scar agent config opencode # or: codex, cursor, windsurf
The MCP server runs as:
scar mcp
It exposes scar_query, scar_why, and scar_draft. Drafting writes only to
.scars/candidates/; active enforcement still requires human promotion.
Authoring from any agent
stop_drafter (the Claude Code Stop hook) is transcript-based, so it only
exists inside Claude Code. scar draft-check closes that gap for every other
runtime — Codex, Cursor, opencode, a human at a terminal — with the same
prompt, driven entirely by git evidence instead of a transcript: revert
language in commit messages, actual git revert/reset --hard history, and
files churned across recent commits. Advisory only — it never blocks
anything and always exits 0.
With the hook (any git repo):
scar hook install --git # writes .git/hooks/post-commit
scar hook status --git
scar hook uninstall --git
Every commit runs scar draft-check --from-hook, throttled to at most one
nudge per hour per repo so a commit-heavy session isn't nagged repeatedly. If
hooks are already managed elsewhere (core.hooksPath, husky, lefthook),
install prints the one line to add manually instead of touching anything.
Without the hook: run scar draft-check yourself (or have the agent run
it) before ending a session — scar agent config <target> and AGENTS.md both
carry the instruction to do so. When it trips, follow the same two-branch
contract as stop_drafter: write a short candidate scar, or — if nothing was
actually abandoned — log one line to .scars/candidates/fp-log.txt tagged
draft-check, so false-trigger data from git evidence stays separate from
transcript-based false triggers.
CI / pre-commit
SCAR ships a .pre-commit-hooks.yaml (repo root) for one-line adoption via
pre-commit:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Daily-Nerd/Scar
rev: v0.11.0 # pin a release-please tag; see the repo's releases
hooks:
- id: scar-lint # validates every scar; fails on orphan-detected
- id: scar-check # blocks a commit that touches anchored code (#106 gate)
Both hooks assume .scars/ already exists (scar init) and language: python
installs this package into pre-commit's own isolated venv — no separate
scar install required on the machine running the hook.
SCAR also ships a composite GitHub Action (action.yml, repo root) for
CI without pre-commit:
# .github/workflows/scar.yml
- uses: Daily-Nerd/Scar@main # or pin a tag, e.g. @v0.11.0 (release-please)
with:
fail-orphans: 'true' # default; set 'false' to only fail on parse errors
version: '' # empty = latest scar-cli from PyPI; or pin e.g. '0.11.0'
args: '' # extra args appended to `scar lint`
@main always tracks the latest commit; releases are tagged vX.Y.Z via
release-please, so pin a tag for reproducible CI.
Quality discipline
- Candidates vs active: agents and
scar harvestonly ever write to.scars/candidates/. A human promotes (scar promote) — nothing enters active enforcement without review. - 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.
- 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.
Read more
- IDEA.md — the full pitch: problem, solution, why this, why now, why me
- SPEC.md — scar format, anchoring model, CLI surface, agent integration
- STRESS-TEST.md — adversarial analysis: failure modes, loopholes, objections, premortem
- ROADMAP.md — phased plan from prototype to product
Status & expectations
Working software, shared as-is. CLI v0 is shipped: 15 subcommands, 220 tests, stdlib-only parser/hot-path, 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).
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.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scar_cli-0.15.0.tar.gz.
File metadata
- Download URL: scar_cli-0.15.0.tar.gz
- Upload date:
- Size: 227.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a53b84ede6f1ec08409b9eaf0c756de34f195b23d7383f07b6c758ecd9e2dc80
|
|
| MD5 |
1daa6b4868e862c7c97558dd089b3b7e
|
|
| BLAKE2b-256 |
761616981078e8c23653a870fe0aad6f13da039c5ffa9a29463bf146f121610e
|
Provenance
The following attestation bundles were made for scar_cli-0.15.0.tar.gz:
Publisher:
release.yml on Daily-Nerd/Scar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scar_cli-0.15.0.tar.gz -
Subject digest:
a53b84ede6f1ec08409b9eaf0c756de34f195b23d7383f07b6c758ecd9e2dc80 - Sigstore transparency entry: 2064761038
- Sigstore integration time:
-
Permalink:
Daily-Nerd/Scar@02f6c5c1a5c8e944fa8a466d4539ce680bf38475 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Daily-Nerd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@02f6c5c1a5c8e944fa8a466d4539ce680bf38475 -
Trigger Event:
push
-
Statement type:
File details
Details for the file scar_cli-0.15.0-py3-none-any.whl.
File metadata
- Download URL: scar_cli-0.15.0-py3-none-any.whl
- Upload date:
- Size: 95.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
faf9680f435ba6af1f4154e3550afe40a22c7103b9897c77bdc915d2f32debae
|
|
| MD5 |
cfd7f2f840749db6e4b125fbbb974f48
|
|
| BLAKE2b-256 |
251ea01df6a73d8d4120466d6e0087c05a11a591f8a68067c4a57894c683d3e0
|
Provenance
The following attestation bundles were made for scar_cli-0.15.0-py3-none-any.whl:
Publisher:
release.yml on Daily-Nerd/Scar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scar_cli-0.15.0-py3-none-any.whl -
Subject digest:
faf9680f435ba6af1f4154e3550afe40a22c7103b9897c77bdc915d2f32debae - Sigstore transparency entry: 2064761043
- Sigstore integration time:
-
Permalink:
Daily-Nerd/Scar@02f6c5c1a5c8e944fa8a466d4539ce680bf38475 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Daily-Nerd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@02f6c5c1a5c8e944fa8a466d4539ce680bf38475 -
Trigger Event:
push
-
Statement type: