Audits changes for additive bias and Iron Law compliance. Use when reviewing completed work before merging or after AI-assisted implementation.
npx skills add https://github.com/athola/claude-night-market --skill justify
> The simplest change that fixes the problem is the
> safest change to merge.
> Adding code is easy. Removing the need for code is
> engineering.
AI models are trained to be helpful, which creates
a systematic bias toward *adding* code rather than
*fixing* root causes:
| AI Default Behavior | Correct Behavior |
|---------------------|------------------|
| Add a workaround | Fix the root cause |
| Modify test expectations | Fix the implementation |
| Create a new helper | Use an existing one |
| Add error handling | Prevent the error |
| Add a compatibility shim | Remove the old code |
| Wrap in try/catch | Fix the exception source |
This skill audits changes for these patterns and
requires explicit justification for each.
imbue:karpathy-principles)
imbue:scope-guard)# Determine base branch
base=$(git merge-base master HEAD 2>/dev/null \
|| git merge-base main HEAD 2>/dev/null)
# Get change statistics
git diff "$base" --stat
git diff "$base" --shortstat
git diff "$base" --diff-filter=A --name-only # new files
git diff "$base" --diff-filter=M --name-only # modified files
git diff "$base" --diff-filter=D --name-only # deleted files
Score each dimension 0-3 (0 = clean, 3 = high bias):
| Signal | Weight | How to Measure |
|--------|--------|----------------|
| Line ratio | 2x | additions / max(deletions, 1) |
| New files | 2x | Count of --diff-filter=A |
| Test logic changes | 3x | Test assertion/expectation diffs |
| New abstractions | 1x | New classes, functions, modules |
| Workaround patterns | 2x | Try/catch, if/else guards added |
Line Ratio Scoring:
| Ratio | Score | Interpretation |
|-------|-------|----------------|
| < 2:1 | 0 | Balanced change |
| 2:1 to 5:1 | 1 | Mildly additive |
| 5:1 to 10:1 | 2 | Additive bias likely |
| > 10:1 | 3 | Strong additive bias |
Aggregate Score:
bias_score = sum(signal_score * weight) / sum(weights)
| Aggregate | Zone | Action |
|-----------|------|--------|
| 0.0 - 0.5 | GREEN | Proceed |
| 0.5 - 1.5 | YELLOW | Justify each signal |
| 1.5 - 2.5 | RED | Rethink approach |
| 2.5+ | STOP | Likely wrong approach |
The Iron Law states: tests drive implementation, not
the other way around. Check for violations:
# Find test files that were modified
git diff "$base" --name-only | rg "test_|_test\.|spec\." \
|| git diff "$base" --name-only | grep -E "test_|_test\.|spec\."
# For each modified test file, check what changed
git diff "$base" -- <test_file> | rg "^[-+].*assert|^[-+].*expect|^[-+].*should"
Violation patterns (test logic was tampered):
@skip or @pytest.mark.skip addedEach violation requires explicit justification:
> "I changed this test assertion because the
> *requirement* changed, not because my implementation
> couldn't meet the original requirement."
If the requirement didn't change, the test should not
change. Fix the implementation instead.
For each changed file, answer:
Could the goal be achieved without touching this file?
Could fewer lines achieve the same result?
New functions, classes, or control flow = added
complexity that needs justification.
Could removing code fix the problem instead of
adding code?
Changes can be minimal and still catastrophically wrong
if they silently revise a load-bearing design decision.
For each changed file, check whether it touches a design
invariant:
What counts as an invariant:
separation, data flow direction)
normalized vs denormalized)
actor model, shared-nothing)
Detection heuristic:
# Check for structural changes (new modules, moved
# boundaries, changed interfaces)
git diff "$base" --name-only | rg "(interface|abstract|base|core|types|schema|model)" \
|| git diff "$base" --name-only | grep -E "(interface|abstract|base|core|types|schema|model)"
# Check for pattern-breaking changes
git diff "$base" -U5 | rg "(TODO.*refactor|HACK|WORKAROUND|XXX)" \
|| git diff "$base" -U5 | grep -E "(TODO.*refactor|HACK|WORKAROUND|XXX)"
When an invariant conflict is detected:
Do NOT silently pick a resolution. Present the three
options to the human:
| Option | Description | When Right |
|--------|-------------|------------|
| Preserve | Don't add the feature; the invariant pays dividends | Invariant simplifies many things; feature is marginal |
| Layer | Add feature inelegantly on top | Feature is needed; invariant is still valuable; imperfection is acceptable |
| Revise | Change the invariant itself | Genuine new learning invalidates the original decision |
Add to Justification Report:
### Invariant Impact: NONE / DETECTED
[If DETECTED:]
- **Invariant**: [name the design decision]
- **Conflict**: [what change clashes with it]
- **Option chosen**: Preserve / Layer / Revise
- **Justification**: [why this option, not the others]
- **Human reviewed**: YES / NO — if NO, flag as
requiring review before merge
Compounding risk warning: Bad invariant decisions
accumulate. If this branch has multiple invariant
revisions, flag the entire branch for architectural
review. Each silent invariant change multiplies the
probability of an unsalvageable codebase.
Output a structured report:
## Justification Report
**Branch**: feature/xyz
**Base**: master
**Delta**: +N/-M lines, X files changed
### Additive Bias Score: X.X (ZONE)
| Signal | Score | Detail |
|--------|-------|--------|
| Line ratio | N | +A/-D = R:1 |
| New files | N | [list] |
| Test changes | N | [list] |
| New abstractions | N | [list] |
| Workarounds | N | [list] |
### Iron Law Compliance: PASS/FAIL
[List any test logic modifications with justification]
### Change-by-Change Justification
#### file.py (+N/-M)
- **What**: [description]
- **Why**: [root cause this addresses]
- **Alternatives considered**: [what else could work]
- **Why this is minimal**: [why fewer changes won't work]
#### test_file.py (+N/-M)
- **What**: [description]
- **Justification**: [why test logic changed, if it did]
- **Iron Law status**: PASS/VIOLATION
### Risk Assessment
| Factor | Rating |
|--------|--------|
| Lines changed | LOW/MED/HIGH |
| Files touched | LOW/MED/HIGH |
| Test modifications | NONE/JUSTIFIED/VIOLATION |
| New abstractions | NONE/JUSTIFIED/UNNECESSARY |
| Overall merge risk | LOW/MED/HIGH |
### Recommendations
[List any changes that should be reconsidered,
simpler alternatives, or unnecessary additions]
When evaluating competing approaches, weight
these factors:
| Factor | Weight | Rationale |
|--------|--------|-----------|
| Fewer lines changed | HIGH | Less risk, easier review |
| No new files | HIGH | No new maintenance burden |
| No test logic changes | HIGH | Iron Law compliance |
| Root cause fix | HIGH | Prevents recurrence |
| Removes code | BONUS | Reduces maintenance surface |
| Adds abstraction | PENALTY | Only justified at 3rd use |
| Adds error handling | NEUTRAL | Only at system boundaries |
The Subtraction Test: Before accepting any change,
ask: "Could I achieve this by *removing* code instead
of *adding* it?" If yes, prefer the subtractive approach.
Justify extends proof-of-work with change-level
accountability:
Both are required before claiming work is complete.
Run proof-of-work first, then justify.
Changing test expectations to match broken code.
Fix: Revert the test change, fix the implementation.
Adding code in many files for a single-concern fix.
Fix: Find the single point of change.
Adding try/catch, null checks, or validation for
scenarios that can't happen in practice.
Fix: Trust internal code. Only validate at boundaries.
Creating a helper/utility/base class for one use case.
Fix: Inline the code. Abstract at the 3rd use.
Adding backward-compatibility code instead of
updating callers.
Fix: Update callers directly. Delete dead paths.
Changing an architectural pattern, data structure
choice, or API contract without acknowledging
that a design invariant is being revised.
Fix: Name the invariant. Present the 3 options
(preserve, layer, revise) to a human. Do not make
the judgment call yourself: models default to the
"average" of training data, and wrong invariant
decisions compound into unsalvageable codebases.
Before justifying any change, apply these questions.
If the answer to questions 4 and 5 is not concrete
evidence, the change is unjustified.
current priority?
juncture?
solution exist?
(not assumed)?
The default stance is: **this addition should not
exist.** The change must prove its necessity, not the
reviewer must prove it unnecessary.
When generating the Justification Report (Step 5), add
a Burden of Proof section:
| Change | Scrutiny Q4 Answer | Scrutiny Q5 Answer | Verdict |
|--------|--------------------|--------------------|---------|
| file.py | [evidence] | [consequence] | justified/needs_evidence/unjustified |
Changes with unjustified verdict MUST be removed or
reworked before the report passes.
When this step settles a decision with real alternatives, record it to
docs/tradeoffs.md while the reasoning is live (draft and confirm):
Skill(leyline:decision-journal) and appenda tradeoff entry (the decision, the options weighed, and what was
sacrificed; set phase to review). Show the draft; append on
confirmation.
docs/tradeoffs.md using the in-fileENTRY TEMPLATE; assign the next TR-NNN id.
> Is what you are doing a deviation of your priority?
> Is it critical to implement at this juncture?
> Rely less on AI and initial lines of thinking.
> Challenge yourself to be better, to think of a more
> elegant implementation or a simpler solution.
is reported.
modified test logic.
unjustified); no unjustified verdict survives in the final report.
human-review flag.
docs/tradeoffs.md (orthe in-file template) before the report passes.
imbue:karpathy-principles - "Surgical Changes" and"Goal-Driven Execution" principles invoke this audit
from a higher-level synthesis
leyline:additive-bias-defense - the contract thisaudit enforces in detail
imbue:proof-of-work - the validation layer thisaudit complements (proof-of-work asks "did it work?",
justify asks "did it need to exist?")
docs/quality-gates.md#skill-level-quality-gate-compositionfor the full gate-skill federation graph
Integration with protocols.io API for managing scientific protocols. This skill should be used when working with protocols.io to search, create, update, or publish protocols; manage protocol steps and materials; handle discussions and comments; organize workspaces; upload and manage files; or integrate protocols.io functionality into workflows. Applicable for protocol discovery, collaborative protocol development, experiment tracking, lab protocol management, and scientific documentation.
Analyzes job descriptions and generates tailored resumes that highlight relevant experience, skills, and achievements to maximize interview chances
Generate Excalidraw diagrams from natural language descriptions. Use when asked to "create a diagram", "make a flowchart", "visualize a process", "draw a system architecture", "create a mind map", or "generate an Excalidraw file". Supports flowcharts, relationship diagrams, mind maps, and system architecture diagrams. Outputs .excalidraw JSON files that can be opened directly in Excalidraw.
Build and distribute Expo development clients locally or via TestFlight
Use when you have a written implementation plan to execute in a separate session with review checkpoints
Data structure for annotated matrices in single-cell analysis. Use when working with .h5ad files or integrating with the scverse ecosystem. This is the data format skill—for analysis workflows use scanpy; for probabilistic models use scvi-tools; for population-scale queries use cellxgene-census.
Benchling R&D platform integration. Access registry (DNA, proteins), inventory, ELN entries, workflows via API, build Benchling Apps, query Data Warehouse, for lab data management automation.
Comprehensive molecular biology toolkit. Use for sequence manipulation, file parsing (FASTA/GenBank/PDB), phylogenetics, and programmatic NCBI/PubMed access (Bio.Entrez). Best for batch processing, custom bioinformatics pipelines, BLAST automation. For quick lookups use gget; for multi-service integration use bioservices.
Take athola/justify from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.