spritegen-cli 0.1.0__tar.gz → 0.3.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.
- spritegen_cli-0.3.0/.claude/agents/code-review.md +124 -0
- spritegen_cli-0.3.0/.claude/agents/security-review.md +123 -0
- spritegen_cli-0.3.0/.claude/commands/scc-adr.md +15 -0
- spritegen_cli-0.3.0/.claude/commands/scc-codewiki.md +13 -0
- spritegen_cli-0.3.0/.claude/commands/scc-glossary.md +12 -0
- spritegen_cli-0.3.0/.claude/commands/scc-init.md +22 -0
- spritegen_cli-0.3.0/.claude/commands/scc-plan-run.md +32 -0
- spritegen_cli-0.3.0/.claude/commands/scc-prd.md +16 -0
- spritegen_cli-0.3.0/.claude/commands/scc-stack.md +16 -0
- spritegen_cli-0.3.0/.claude/commands/scc-wiki.md +13 -0
- spritegen_cli-0.3.0/.claude/rules/artifacts.md +55 -0
- spritegen_cli-0.3.0/.claude/rules/autonomy.md +55 -0
- spritegen_cli-0.3.0/.claude/rules/caveman.md +55 -0
- spritegen_cli-0.3.0/.claude/rules/code-search.md +46 -0
- spritegen_cli-0.3.0/.claude/rules/delivery.md +62 -0
- spritegen_cli-0.3.0/.claude/rules/knowledge-base.md +81 -0
- spritegen_cli-0.3.0/.claude/rules/methodology.md +55 -0
- spritegen_cli-0.3.0/.claude/rules/notes.md +53 -0
- spritegen_cli-0.3.0/.claude/rules/prior-art.md +55 -0
- spritegen_cli-0.3.0/.claude/rules/project.md +79 -0
- spritegen_cli-0.3.0/.claude/rules/routing.md +55 -0
- spritegen_cli-0.3.0/.claude/rules/specs.md +82 -0
- spritegen_cli-0.3.0/.claude/rules/tasks.md +55 -0
- spritegen_cli-0.3.0/.claude/rules/verification.md +39 -0
- spritegen_cli-0.3.0/.claude/scc-manifest.json +171 -0
- spritegen_cli-0.3.0/.claude/skills/adr/SKILL.md +88 -0
- spritegen_cli-0.3.0/.claude/skills/codewiki/SKILL.md +78 -0
- spritegen_cli-0.3.0/.claude/skills/glossary/SKILL.md +67 -0
- spritegen_cli-0.3.0/.claude/skills/init/SKILL.md +138 -0
- spritegen_cli-0.3.0/.claude/skills/plan-run/SKILL.md +259 -0
- spritegen_cli-0.3.0/.claude/skills/prd/SKILL.md +90 -0
- spritegen_cli-0.3.0/.claude/skills/stack/SKILL.md +74 -0
- spritegen_cli-0.3.0/.claude/skills/wiki/SKILL.md +89 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/.env.template +14 -14
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/.gitignore +225 -219
- spritegen_cli-0.3.0/.python-version +1 -0
- spritegen_cli-0.3.0/CLAUDE.md +95 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/PKG-INFO +3 -3
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/README.md +7 -1
- spritegen_cli-0.3.0/docs/adr/0001-asset-directory-and-no-path-arguments.md +43 -0
- spritegen_cli-0.3.0/docs/adr/0002-transfer-movement-instead-of-generating-frames.md +46 -0
- spritegen_cli-0.3.0/docs/adr/0003-append-only-jsonl-ledger.md +36 -0
- spritegen_cli-0.3.0/docs/adr/0004-allow-list-every-downloaded-host.md +35 -0
- spritegen_cli-0.3.0/docs/adr/0005-a-directory-per-artifact-kind.md +46 -0
- spritegen_cli-0.3.0/docs/adr/0006-centralise-configuration-and-never-cache-it.md +47 -0
- spritegen_cli-0.3.0/docs/adr/0007-heavy-dependencies-are-optional-extras.md +48 -0
- spritegen_cli-0.3.0/docs/adr/0008-local-backends-are-the-default.md +40 -0
- spritegen_cli-0.3.0/docs/adr/0009-walk-the-redirect-chain-here.md +32 -0
- spritegen_cli-0.3.0/docs/adr/0010-ci-on-three-operating-systems.md +36 -0
- spritegen_cli-0.3.0/docs/adr/0011-keep-pixelfixer-out-of-the-distribution.md +42 -0
- spritegen_cli-0.3.0/docs/adr/0012-publish-with-one-secret.md +39 -0
- spritegen_cli-0.3.0/docs/adr/0013-require-python-3-13.md +39 -0
- spritegen_cli-0.3.0/docs/adr/0014-every-run-is-a-version-and-the-state-names-the-chosen-one.md +58 -0
- spritegen_cli-0.3.0/docs/adr/0015-record-the-call-before-the-files-it-writes.md +53 -0
- spritegen_cli-0.3.0/docs/codewiki/spending-money.md +52 -0
- spritegen_cli-0.3.0/docs/codewiki/the-stage-registry.md +58 -0
- spritegen_cli-0.3.0/docs/codewiki/the-workspace.md +80 -0
- spritegen_cli-0.3.0/docs/glossary.md +36 -0
- spritegen_cli-0.3.0/docs/notes.md +46 -0
- spritegen_cli-0.3.0/docs/stack.md +71 -0
- spritegen_cli-0.3.0/docs/wiki/changelog.md +8 -0
- spritegen_cli-0.3.0/docs/wiki/index.md +18 -0
- spritegen_cli-0.3.0/docs/wiki/pages/configuration.md +66 -0
- spritegen_cli-0.3.0/docs/wiki/pages/grid-and-palette-recovery.md +60 -0
- spritegen_cli-0.3.0/docs/wiki/pages/local-instead-of-paid.md +84 -0
- spritegen_cli-0.3.0/docs/wiki/pages/motion-transfer.md +116 -0
- spritegen_cli-0.3.0/docs/wiki/pages/paid-calls-and-the-ledger.md +47 -0
- spritegen_cli-0.3.0/docs/wiki/pages/the-asset-directory.md +84 -0
- spritegen_cli-0.3.0/docs/wiki/pages/the-generated-skill.md +42 -0
- spritegen_cli-0.3.0/docs/wiki/pages/the-pipeline.md +57 -0
- spritegen_cli-0.3.0/plans/code-health.md +119 -0
- spritegen_cli-0.3.0/plans/motion-optimisation.md +79 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/pyproject.toml +10 -6
- spritegen_cli-0.3.0/specs/artifact-versions/design.md +151 -0
- spritegen_cli-0.3.0/specs/artifact-versions/requirements.md +63 -0
- spritegen_cli-0.3.0/specs/artifact-versions/tasks.md +39 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/__init__.py +3 -3
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/atlas.py +117 -99
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/cli.py +194 -178
- spritegen_cli-0.3.0/src/spritegen/clip.py +178 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/drive.py +226 -163
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/endpoints.py +119 -113
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/fal.py +346 -228
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/imaging.py +24 -3
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/ledger.py +182 -143
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/matting.py +33 -4
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/migrate.py +270 -162
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/prompts.py +96 -96
- spritegen_cli-0.3.0/src/spritegen/report.py +260 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/rrdb.py +91 -91
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/settings.py +127 -127
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/sheet.py +7 -4
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/skill/__init__.py +352 -303
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/skill/files/SKILL.md +18 -7
- spritegen_cli-0.3.0/src/spritegen/stages/__init__.py +80 -0
- spritegen_cli-0.3.0/src/spritegen/stages/_common.py +105 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/stages/anchor.py +203 -215
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/stages/board.py +68 -68
- spritegen_cli-0.1.0/src/spritegen/stages/__init__.py → spritegen_cli-0.3.0/src/spritegen/stages/catalog.py +425 -490
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/stages/matte.py +227 -209
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/stages/motion.py +237 -164
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/stages/pose.py +155 -172
- spritegen_cli-0.3.0/src/spritegen/stages/registry.py +59 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/stages/video.py +150 -196
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/upscale.py +56 -22
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/src/spritegen/workspace.py +931 -852
- spritegen_cli-0.3.0/tests/conftest.py +125 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/helpers.py +32 -4
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_anchor.py +456 -457
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_atlas.py +106 -106
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_board_stage.py +18 -24
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_cli.py +105 -67
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_clip.py +95 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_drive.py +215 -179
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_fal.py +529 -285
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_imaging.py +24 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_ledger.py +291 -232
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_matte.py +339 -318
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_matting.py +84 -6
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_migrate.py +285 -183
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_motion.py +726 -566
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_parity.py +103 -103
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_pose.py +277 -279
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_prompts.py +88 -88
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_sheet.py +24 -0
- spritegen_cli-0.3.0/tests/test_show.py +237 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_skill.py +333 -245
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_stages.py +116 -86
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_upscale.py +145 -5
- spritegen_cli-0.3.0/tests/test_versions.py +91 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_video.py +406 -414
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_workspace.py +1029 -719
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/tests_fal_doubles.py +83 -68
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/uv.lock +75 -610
- spritegen_cli-0.1.0/src/spritegen/clip.py +0 -81
- spritegen_cli-0.1.0/tests/conftest.py +0 -62
- spritegen_cli-0.1.0/tests/test_show.py +0 -147
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/.gitattributes +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/.github/workflows/ci.yml +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/.github/workflows/release.yml +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/expected/anchor_crop.pixelart.json +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/expected/anchor_crop.pixelart.png +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/expected/synthetic_chroma.cut.json +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/expected/synthetic_chroma.cut.png +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/expected/synthetic_matted.json +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/expected/synthetic_row.png +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/expected/synthetic_video_board.json +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/expected/synthetic_video_board.png +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/expected/walk_south_row.gif +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/expected/walk_south_row.png +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/input/anchor_crop.png +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/input/synthetic_board.png +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/input/synthetic_chroma.png +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/input/synthetic_matted.png +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/input/walk_south_board.png +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/parity/manifest.json +0 -0
- {spritegen_cli-0.1.0 → spritegen_cli-0.3.0}/tests/test_settings.py +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-review
|
|
3
|
+
description: Reviews a diff for correctness and quality against the task list, re-runs the feature's tests and lint, and reports. Use it after the last task of a spec or plan is verified and before opening the PR — never on your own work as the author.
|
|
4
|
+
tools: Read, Grep, Glob, Bash
|
|
5
|
+
model: sonnet
|
|
6
|
+
effort: high
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You review a diff. You do not write code and you do not fix what you find — you
|
|
10
|
+
report it. The orchestrator decides what to do with the report.
|
|
11
|
+
|
|
12
|
+
You exist because **the author of a change is its worst reader**: they see what they
|
|
13
|
+
meant. A cold context is your entire value. Do not ask the author what they intended,
|
|
14
|
+
do not take "it's done" as evidence. Read the diff, read the task list, run the checks
|
|
15
|
+
yourself.
|
|
16
|
+
|
|
17
|
+
## Scope
|
|
18
|
+
|
|
19
|
+
The changed lines, plus enough surrounding code to judge them.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
git diff main...HEAD # or the base branch the work targets
|
|
23
|
+
git diff --stat main...HEAD
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**The diff is your source; the repository is not.** It already carries every changed
|
|
27
|
+
line, so re-reading a file to look at them buys nothing. Open a file only when the diff
|
|
28
|
+
is genuinely not enough to judge a change, only if the diff touches it, and only once —
|
|
29
|
+
a review that fetches the same source three times spent its context on what it was
|
|
30
|
+
handed.
|
|
31
|
+
|
|
32
|
+
Then read what the work was supposed to be, on the same terms: `scc map <artifact>` for
|
|
33
|
+
its shape and `scc map show <artifact> <address>` for the part you need. **The artifact
|
|
34
|
+
is the standard the code is held to** — not the implementation's apparent intent. Build,
|
|
35
|
+
test and lint commands are in `.claude/rules/project.md`.
|
|
36
|
+
|
|
37
|
+
## The five gates — run every one, in this order
|
|
38
|
+
|
|
39
|
+
Run all five even after one fails. Bailing at the first red gate reports one problem
|
|
40
|
+
when there were four, and buys a second review round to learn the rest.
|
|
41
|
+
|
|
42
|
+
**1 · The ticked boxes are true.** For every `[x]`, find the code in the diff. A box
|
|
43
|
+
ticked with nothing behind it is the most expensive defect here — the PR body, the
|
|
44
|
+
spec, and the next session's assumptions are all built on it. Report the reverse too:
|
|
45
|
+
diff with no task, tasks implemented but unticked.
|
|
46
|
+
|
|
47
|
+
**2 · The code does what the task says.** Not something adjacent, not a superset.
|
|
48
|
+
Trace each changed behavior to a requirement or task line and read the acceptance
|
|
49
|
+
criteria as written. Scope the author added on their own is a finding even when it
|
|
50
|
+
works: nobody reviewed the decision to build it.
|
|
51
|
+
|
|
52
|
+
**3 · The feature's tests run green — because you ran them.** Project test command,
|
|
53
|
+
scoped to what the diff touches; quote the exact command and the tail of its output.
|
|
54
|
+
Then judge the tests:
|
|
55
|
+
|
|
56
|
+
- **Tests asserting the implementation instead of the requirement.** A test that would
|
|
57
|
+
still pass if the bug were intentional is worth less than no test — it locks the bug
|
|
58
|
+
in. Most common defect in agent-written tests: assertions that read like a
|
|
59
|
+
transcript of the code.
|
|
60
|
+
- **Missing tests.** Unit tasks owe a test per function; TDD tasks owe a test seen to
|
|
61
|
+
fail first. Untested new functions are a finding.
|
|
62
|
+
|
|
63
|
+
**4 · The lint runs clean — because you ran it.** Same quoting. Lint is the automated
|
|
64
|
+
half of best practices: unused code, unchecked errors, shadowed variables, unsafe
|
|
65
|
+
conversions. Do not re-derive by eye what the linter already answers.
|
|
66
|
+
|
|
67
|
+
**5 · Best practices, by hand.** The half no linter has an opinion about, in rough
|
|
68
|
+
order of what bites:
|
|
69
|
+
|
|
70
|
+
- **Correctness at the edges** — empty, zero, nil, one, many, concurrent, the error
|
|
71
|
+
path. Errors dropped, wrapped without context, or returned but unhandled.
|
|
72
|
+
- **Behavior changed by accident** — a modified function whose existing callers were
|
|
73
|
+
never looked at.
|
|
74
|
+
- **Consistency** — a new way of doing what the project already does one way is a cost
|
|
75
|
+
paid by every future reader.
|
|
76
|
+
- **Complexity not paying for itself** — an abstraction with one caller, a layer that
|
|
77
|
+
only forwards, a config knob nobody asked for.
|
|
78
|
+
- **Naming and comments that lie.** A comment describing the previous behavior is
|
|
79
|
+
worse than none — and a comment that is not a docstring is a finding of its own: a
|
|
80
|
+
`TODO`, a `HACK` or an aside belongs in `docs/notes.md`, not in the diff.
|
|
81
|
+
|
|
82
|
+
If a gate cannot be run — no test command, a suite needing a service you lack — report
|
|
83
|
+
it `not-run` with the reason. **Never report a skipped gate as passing**, and never
|
|
84
|
+
infer green from the author saying so.
|
|
85
|
+
|
|
86
|
+
Security has its own reviewer. Note anything alarming in one line; do not try to be
|
|
87
|
+
that reviewer.
|
|
88
|
+
|
|
89
|
+
## The report
|
|
90
|
+
|
|
91
|
+
End with this, and nothing after it:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
## Verdict
|
|
95
|
+
<blocked | changes-requested | clean> — one sentence saying why.
|
|
96
|
+
|
|
97
|
+
## Gates
|
|
98
|
+
| # | Gate | Result | Evidence |
|
|
99
|
+
|---|---|---|---|
|
|
100
|
+
| 1 | ticked boxes are true | pass/fail | 7/7 tasks traced to code |
|
|
101
|
+
| 2 | code matches the tasks | pass/fail | ... |
|
|
102
|
+
| 3 | tests | pass/fail/not-run | `<command>` → 42 ok, 0 failed |
|
|
103
|
+
| 4 | lint | pass/fail/not-run | `<command>` → clean |
|
|
104
|
+
| 5 | best practices | pass/fail | 2 findings |
|
|
105
|
+
|
|
106
|
+
## Findings
|
|
107
|
+
### 1 · blocker — path/to/file.go:118
|
|
108
|
+
What is wrong and what makes it wrong: the input, state, or caller that breaks. Which
|
|
109
|
+
task or requirement it violates. What to do instead.
|
|
110
|
+
|
|
111
|
+
### 2 · major — path/to/other.go:40
|
|
112
|
+
...
|
|
113
|
+
|
|
114
|
+
## Notes
|
|
115
|
+
Anything the author may reasonably ignore, one line each.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Severity: `blocker` (do not open the PR), `major` (fix before merge), `minor` (author's
|
|
119
|
+
call). A red gate 1, 3, or 4 is always a blocker.
|
|
120
|
+
|
|
121
|
+
**A finding the author cannot act on is noise.** If you are not sure something is a
|
|
122
|
+
defect, put it under Notes with what would make it one. `clean` with an empty Findings
|
|
123
|
+
section is a legitimate answer; padding a review with style preferences is how a
|
|
124
|
+
reviewer stops being read.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security-review
|
|
3
|
+
description: Reviews a diff for exploitable weaknesses, attack-class agnostic — traces attacker-controlled input to effect and reports reachable paths. Use it alongside code-review before opening a PR — the two are deliberately separate lenses.
|
|
4
|
+
tools: Read, Grep, Glob, Bash
|
|
5
|
+
model: sonnet
|
|
6
|
+
effort: high
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You review a diff for security defects and nothing else. You do not write code and you
|
|
10
|
+
do not fix what you find — you report it, and the orchestrator decides.
|
|
11
|
+
|
|
12
|
+
Separate from `code-review` on purpose: **one reviewer asked for "everything"
|
|
13
|
+
reliably under-weights security**, because correctness findings are easier to produce
|
|
14
|
+
and crowd it out. The narrow scope is the point — no style, naming, or design taste,
|
|
15
|
+
and do not re-report what a correctness reviewer obviously catches.
|
|
16
|
+
|
|
17
|
+
**You are not a checklist runner.** The question is not "does this diff contain any of
|
|
18
|
+
the ten bugs I know the names of" — it is **"what can someone make this code do that
|
|
19
|
+
it was not built to do?"** A weakness with no name is still a weakness; a named class
|
|
20
|
+
with no reachable path is not a finding. Work from the code outward, not from a list
|
|
21
|
+
inward.
|
|
22
|
+
|
|
23
|
+
## Scope
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
git diff main...HEAD # or the base branch the work targets
|
|
27
|
+
git diff --stat main...HEAD
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Judge what the change makes *possible*, not what the codebase already was. Pre-existing
|
|
31
|
+
issues in untouched code are worth one line at the end, not the body of the review.
|
|
32
|
+
|
|
33
|
+
That scope is also your read budget. The diff carries the changed lines already: open a
|
|
34
|
+
file only to follow reachability the diff cannot show you, only if the diff touches it,
|
|
35
|
+
and once.
|
|
36
|
+
|
|
37
|
+
## The method — four passes, in this order
|
|
38
|
+
|
|
39
|
+
**1 · Map what the change adds to the attack surface.** Before judging anything, list
|
|
40
|
+
it: new inputs, outputs, files or paths touched, privileges exercised, persisted state,
|
|
41
|
+
dependencies, network calls, places a secret can flow. That list is what the rest of
|
|
42
|
+
the review works through — if it is empty, say so and stop.
|
|
43
|
+
|
|
44
|
+
**2 · Find the trust boundaries.** For each input: who controls it, and what is assumed
|
|
45
|
+
about it. A boundary is anywhere data crosses from someone else's control into yours —
|
|
46
|
+
request bodies, CLI arguments, filenames, environment, file contents, user-written
|
|
47
|
+
database rows, anything over the network, the output of any other system. **The
|
|
48
|
+
vulnerability is almost always an assumption that holds on one side of a boundary and
|
|
49
|
+
is enforced nowhere.**
|
|
50
|
+
|
|
51
|
+
**3 · Trace reachability, source to effect.** Follow each crossing value until it is
|
|
52
|
+
validated or reaches something that acts on it: a shell, query, path, template,
|
|
53
|
+
deserializer, allocation, permission check, redirect, or model prompt. Write the path
|
|
54
|
+
down, file to file, call to call. **A finding without a path from an
|
|
55
|
+
attacker-controlled source to an effect is a hypothesis, and you must label it one.**
|
|
56
|
+
|
|
57
|
+
**4 · Attack it deliberately.** Ask what you would try to make this code misbehave, and
|
|
58
|
+
answer concretely: the input, the sequence, the race, the state you would set up first.
|
|
59
|
+
Consider order of operations (check before use, use before check), the error path, what
|
|
60
|
+
happens twice, and values at their boundary — empty, huge, negative, encoded, or a
|
|
61
|
+
lookalike.
|
|
62
|
+
|
|
63
|
+
### Known classes, as prompts and not as a scope
|
|
64
|
+
|
|
65
|
+
Jog the passes above with these — never treat them as the definition of "done".
|
|
66
|
+
Absence of every class below is not evidence of safety.
|
|
67
|
+
|
|
68
|
+
- **Injection into any interpreter** — SQL, shell, template, path, URL, regex,
|
|
69
|
+
serialization format, or a prompt an agent will act on.
|
|
70
|
+
- **Path traversal.** A caller-supplied name becoming a path segment unvalidated:
|
|
71
|
+
`..`, absolute paths, separators, symlinks, Windows device names. This is the one
|
|
72
|
+
that turns a delete command into deleting the project.
|
|
73
|
+
- **Authorization.** A new endpoint, command, or branch skipping the check its
|
|
74
|
+
neighbors make. Missing authorization is far more common than broken authentication.
|
|
75
|
+
- **Secrets** in source, config, a test fixture, a log line, an error message, a cache.
|
|
76
|
+
- **Crypto and randomness.** `math/rand` where unpredictability matters, a hand-rolled
|
|
77
|
+
secret comparison, a hash chosen for speed where it needed to be slow.
|
|
78
|
+
- **Resource exhaustion** reachable from input: unbounded reads or allocations,
|
|
79
|
+
decompression, quadratic regexes over attacker-controlled strings.
|
|
80
|
+
- **Time-of-check to time-of-use**, and anything else assuming the world did not move
|
|
81
|
+
between two operations.
|
|
82
|
+
- **Dependencies added in this diff.** New surface and a new maintainer to trust. Say
|
|
83
|
+
whether it earned that, and run the project's vulnerability scanner if it has one.
|
|
84
|
+
- **What the change loosens** — a widened permission, a disabled check, a suppression
|
|
85
|
+
comment, a TLS verification skipped "for now".
|
|
86
|
+
|
|
87
|
+
## The report
|
|
88
|
+
|
|
89
|
+
End with this, and nothing after it:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
## Verdict
|
|
93
|
+
<blocked | changes-requested | clean> — one sentence saying why.
|
|
94
|
+
|
|
95
|
+
## Surface reviewed
|
|
96
|
+
| What the change adds | Trust boundary | Traced |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| `scc spec delete <name>` argument | user/CLI | yes → findings 1 |
|
|
99
|
+
| new dep `example/foo` | third party | yes → no issue |
|
|
100
|
+
|
|
101
|
+
## Findings
|
|
102
|
+
### 1 · critical — path/to/file.go:64
|
|
103
|
+
**Path:** attacker-controlled `<source>` → `<function>` → `<effect>`, quoted line by
|
|
104
|
+
line.
|
|
105
|
+
**Impact:** what an attacker gets, stated concretely.
|
|
106
|
+
**Fix:** what to do instead.
|
|
107
|
+
|
|
108
|
+
## Hypotheses
|
|
109
|
+
Suspicions with no reachable path yet, and what would confirm each.
|
|
110
|
+
|
|
111
|
+
## Pre-existing
|
|
112
|
+
Anything alarming in untouched code, one line each — not this diff's problem.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Severity: `critical` (reachable now, high impact), `high` (reachable, bounded impact),
|
|
116
|
+
`medium` (needs a precondition an attacker may well have), `low` (defense-in-depth). A
|
|
117
|
+
finding whose path you could not complete belongs under Hypotheses, whatever it would
|
|
118
|
+
score if it were real.
|
|
119
|
+
|
|
120
|
+
**Do not inflate severity to be heard.** One wrong high-severity finding costs the
|
|
121
|
+
author's trust in every finding after it. "No security findings in this diff" is a real
|
|
122
|
+
result; report it plainly, with the surface table showing what you actually looked at,
|
|
123
|
+
so the orchestrator can tell a clean review from a shallow one.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Record a hard-to-reverse decision as a numbered ADR under docs/adr/, or supersede one that stopped being true
|
|
3
|
+
argument-hint: [the decision, or the ADR being superseded]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `adr` skill.
|
|
7
|
+
|
|
8
|
+
Decision: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
First ask whether this is an ADR at all: how expensive would it be to undo? A
|
|
11
|
+
decision that is cheap to change belongs in the spec's `design.md`, and an `adr/`
|
|
12
|
+
full of reversible choices buries the records that actually explain the system.
|
|
13
|
+
|
|
14
|
+
If an existing record is being replaced, write the new one and mark the old one
|
|
15
|
+
superseded — never edit its prose.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Narrate an area of the codebase into docs/codewiki/, every section citing the exact lines it explains
|
|
3
|
+
argument-hint: [area or path to narrate | repair]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `codewiki` skill.
|
|
7
|
+
|
|
8
|
+
Area: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
If no area was named, run `scc validate` and repair the `codewiki.*` findings it
|
|
11
|
+
reports — a broken citation means the code moved and the prose describing it is now
|
|
12
|
+
suspect, so re-read before re-numbering. If there are no findings and no area was
|
|
13
|
+
named, ask which area is hard to enter cold rather than picking one at random.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Add, settle, or rename a canonical term in docs/glossary.md, and list the synonyms to avoid
|
|
3
|
+
argument-hint: [term, or the ambiguity to settle]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `glossary` skill.
|
|
7
|
+
|
|
8
|
+
Term: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
Read `docs/glossary.md` before adding to it — an entry that duplicates an existing
|
|
11
|
+
concept under a different name makes the canonical source itself ambiguous. If
|
|
12
|
+
nothing was named, run `scc validate` and resolve the `glossary.*` findings.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Bootstrap the knowledge base from the code that is already here — survey the repository, then write stack, glossary, the project rule's real commands, the wiki, and the ADRs for decisions already taken
|
|
3
|
+
argument-hint: [anchors | full, and the subtree to cover if not the whole repository]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `init` skill.
|
|
7
|
+
|
|
8
|
+
Scope: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
Survey before you write, and report the map back — the areas, the pages you would
|
|
11
|
+
write, the decisions you would record — before a single file is created. Ask the
|
|
12
|
+
graph and the history rather than reading the tree file by file.
|
|
13
|
+
|
|
14
|
+
**Write only what you can point at.** Everything here is reconstructed from what
|
|
15
|
+
survived, not remembered by anyone, so a dependency nobody can justify, an area whose
|
|
16
|
+
reasoning is unrecorded, and a decision with no evidence behind it are all *reported*
|
|
17
|
+
rather than filled in with something plausible. A gap is visible; an invention is
|
|
18
|
+
believed.
|
|
19
|
+
|
|
20
|
+
If nothing was named above, take it as `anchors` over the whole repository — stack,
|
|
21
|
+
glossary, the project rule's real build and test commands, and a wiki someone can
|
|
22
|
+
enter — and say that is what you took.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run a plan under plans/ to completion — implement group by group, then deliver as one PR per group or one at the end, and settle CI before calling it delivered
|
|
3
|
+
argument-hint: [the plan, plus how to run it and any standing instruction]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `plan-run` skill.
|
|
7
|
+
|
|
8
|
+
Plan, and how to run it: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
Brief the plan — `scc map brief <plan>` — then `scc map <plan>` for the counts, and
|
|
11
|
+
name the groups back, numbered and in order, before writing any code. The order is the
|
|
12
|
+
one thing the user can correct cheaply now and expensively after three merges.
|
|
13
|
+
|
|
14
|
+
**Never open the plan file.** `brief` is its header and `tasks` is its checklist;
|
|
15
|
+
there is nothing else in it, and opening one as the first act of a run puts all of it
|
|
16
|
+
in context for every turn of a loop that lasts hours. Inside a group, ask `scc map
|
|
17
|
+
tasks <plan> --next` for the one task to do, and ask again once it is ticked.
|
|
18
|
+
|
|
19
|
+
Then take every answer the line above already gave and ask only for what is left.
|
|
20
|
+
"Implement the whole plan, one PR at the end, delivered when CI is green" has settled
|
|
21
|
+
most of it; re-asking what someone just typed is the friction that stops people using
|
|
22
|
+
this at all. Restate what you took so a wrong reading is cheap to correct, then put
|
|
23
|
+
the remaining questions in one exchange — automatic or gated, one PR at the end or one
|
|
24
|
+
per group, and what happens once a PR is open. **These are the developer's calls.** Anything the plan's frontmatter already
|
|
25
|
+
records is a proposed answer to confirm, not a decision already made.
|
|
26
|
+
|
|
27
|
+
The plan is delivered when CI is green on its pull request — never on the strength of
|
|
28
|
+
a passing local suite.
|
|
29
|
+
|
|
30
|
+
Anything said above about *how* to implement is a standing instruction: it applies
|
|
31
|
+
to every group, and you carry it into each one explicitly rather than trusting it to
|
|
32
|
+
survive from the first group to the last.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Turn an initiative too large for one spec into a plan under plans/ — decomposed into specs and tasks
|
|
3
|
+
argument-hint: [the initiative, epic, or PRD]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `prd` skill.
|
|
7
|
+
|
|
8
|
+
Initiative: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
Check the routing question before you start: work that is one feature with unsettled
|
|
11
|
+
requirements is a spec, not a plan — run `scc spec new <feature>` instead of wrapping
|
|
12
|
+
one feature in a plan for ceremony.
|
|
13
|
+
|
|
14
|
+
If the initiative is too vague to decompose, ask a small batch of concrete
|
|
15
|
+
multiple-choice questions once, then decompose. Do not guess at the scope, and do not
|
|
16
|
+
interview at length — stop asking the moment you can name the leaves.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Record an adopted technology in docs/stack.md, or account for a dependency that nobody decided on
|
|
3
|
+
argument-hint: [technology being adopted or dropped]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `stack` skill.
|
|
7
|
+
|
|
8
|
+
Technology: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
If nothing was named, run `scc validate` and work through the
|
|
11
|
+
`stack.undocumented-dependency` findings: for each one, either record the decision or
|
|
12
|
+
establish that nobody can justify the dependency and remove it. Both are correct
|
|
13
|
+
outcomes; listing a name with no reason is not.
|
|
14
|
+
|
|
15
|
+
Adopting technology is a decision with a long tail. If it is not obviously the right
|
|
16
|
+
call, stop and ask rather than committing on someone else's behalf.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Build or maintain docs/wiki/ — ingest a source from docs/raw/, answer from what is known, or clear wiki.* findings
|
|
3
|
+
argument-hint: [ingest <file> | query <question> | maintain]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the `wiki` skill.
|
|
7
|
+
|
|
8
|
+
Request: $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
If nothing was asked for specifically, look at `docs/raw/` first — anything sitting
|
|
11
|
+
there is unprocessed work and is the default job. If `raw/` is empty, run
|
|
12
|
+
`scc validate` and clear whatever `wiki.*` findings it reports. If there are none,
|
|
13
|
+
say so rather than inventing pages.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Plans and specs — address them, do not read them
|
|
2
|
+
|
|
3
|
+
A plan is a header and a checklist, and `scc` answers every question about it without
|
|
4
|
+
loading the file. Reading one end to end is the most wasteful thing this workspace can
|
|
5
|
+
ask of you: once it is in context you carry it for the rest of the session. **Never
|
|
6
|
+
open a plan** — `brief` is the header, `tasks` is the checklist, no command returns
|
|
7
|
+
both, so no question about a plan has the file as its answer.
|
|
8
|
+
|
|
9
|
+
| The question | Ask |
|
|
10
|
+
|---|---|
|
|
11
|
+
| What is here, and how far along? | `scc map` · `scc map <artifact>` |
|
|
12
|
+
| What is this work, and when is it done? | `scc map brief <plan>` — once, per session |
|
|
13
|
+
| What do I work on now? | `scc map tasks <plan> --next` · `--ready` · `--blocked` |
|
|
14
|
+
| Show me exactly that piece | `scc map show <artifact> <address>` |
|
|
15
|
+
| What else mentions this requirement? | `scc map trace specs/<feature>/R1.2` |
|
|
16
|
+
|
|
17
|
+
`<artifact>` is a path, a plan name, or a feature name. **An address is a name, never
|
|
18
|
+
a line number**, so it survives an edit above it:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
1.2 a task #risks a section, by anchor slug
|
|
22
|
+
R1.2 a requirement risks:2 the 2nd paragraph of that section
|
|
23
|
+
specs/foo/ a spec reference L120-160 an explicit range, the escape hatch
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Read a file directly only when the question is about *this exact text* — prose you are
|
|
27
|
+
about to rewrite, which is a spec's design and never a plan. **A plan's shape is
|
|
28
|
+
closed**: the title, one to three sentences, then `## Why`, `## Paths`, `## References`,
|
|
29
|
+
`## Out of scope`, `## Tasks`, `## Done when`, and any other heading is a finding.
|
|
30
|
+
`## References` names the specs this decomposes into and carries no checkbox — that
|
|
31
|
+
spec's state lives in that spec.
|
|
32
|
+
|
|
33
|
+
## Writing
|
|
34
|
+
|
|
35
|
+
**Tick boxes and amend tasks with `scc patch`, not with an editor.**
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
scc patch check <artifact> 1.1 1.2 · patch fm <artifact> pr=per-plan
|
|
39
|
+
scc patch task <artifact> 1.2 --text "…" --method TDD --depends 1.1 --priority 2
|
|
40
|
+
scc patch add <artifact> --group 1 --text "…" --reason "…"
|
|
41
|
+
scc patch rm <artifact> 1.4 --reason "…"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Each resolves its address with the parser that read the file, so a miss is an error
|
|
45
|
+
rather than a write to the wrong place. It then re-runs the validators and **rolls the
|
|
46
|
+
change back if it introduced a finding** — exit `2`, file untouched. `--dry-run` shows
|
|
47
|
+
the lines first; deleting more than a screenful stops and asks for `--force`. That is
|
|
48
|
+
why you need not read a plan to change one line of it: do not defeat it by reading "to
|
|
49
|
+
be safe", since the printed before/after is the confirmation.
|
|
50
|
+
|
|
51
|
+
After `scc plan approve` the work is settled: `add` needs `--group` and `--reason` and
|
|
52
|
+
is given its number, `rm` strikes the task out where it stands so the number is never
|
|
53
|
+
reused, and rewriting a task or the prose is refused — a task that turned out wrong is
|
|
54
|
+
struck out and replaced. An edit made outside `scc` shows up as drift. A requirement id
|
|
55
|
+
is scoped to its own spec, so cite it as `specs/<feature>/R2.5` when that is not obvious.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Autonomy — ask once, at kickoff
|
|
2
|
+
|
|
3
|
+
The spec phases are **autonomous by default**: write requirements, design, and
|
|
4
|
+
tasks, then start implementing. Do not stop for approval at each phase.
|
|
5
|
+
|
|
6
|
+
But autonomy is the user's call, so **ask, once, before writing anything** — three
|
|
7
|
+
questions, together, in the same breath:
|
|
8
|
+
|
|
9
|
+
1. **Run automatically, or gate each phase for review?**
|
|
10
|
+
2. **When the PR is open, wait for CI, or finish there?**
|
|
11
|
+
3. **Answer in English, or in 文言文?** Classical Chinese at maximum terseness —
|
|
12
|
+
particles (之/乃/為/其), verb before object, subject dropped. Say the cost: its
|
|
13
|
+
"80-90% reduction" counts **characters, not tokens**, and CJK spends more tokens per
|
|
14
|
+
character, so the real saving is smaller and unmeasured. Governs speech, not artifacts.
|
|
15
|
+
|
|
16
|
+
Record the answers in the artifact's frontmatter (`requirements.md` for a spec),
|
|
17
|
+
then never ask again for this piece of work:
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
---
|
|
21
|
+
autonomy: auto # or: gated
|
|
22
|
+
ci: wait # or: no-wait
|
|
23
|
+
lang: en # or: wenyan — omit to mirror the user
|
|
24
|
+
---
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`scc spec new <feature> --autonomy=auto --ci=wait` writes the first two;
|
|
28
|
+
`scc patch fm <artifact> lang=wenyan` writes the third without opening the file.
|
|
29
|
+
|
|
30
|
+
Recording them is what makes the run reproducible from the file and what stops a
|
|
31
|
+
second session from re-asking. Ask in conversation rather than reading a flag,
|
|
32
|
+
because the person who has to make the call is in the conversation.
|
|
33
|
+
|
|
34
|
+
## Asking at kickoff, not later
|
|
35
|
+
|
|
36
|
+
The CI question especially: by the time the PR is open the work is done and the
|
|
37
|
+
user may be gone — which is exactly the situation "don't wait" exists for, and
|
|
38
|
+
exactly when a blocking question costs the most.
|
|
39
|
+
|
|
40
|
+
## `auto` is not "never stop"
|
|
41
|
+
|
|
42
|
+
Automatic keeps one exception. **The risk that mandates TDD also warrants a
|
|
43
|
+
checkpoint:** a task you annotated `(TDD)` because it touches money, a complex
|
|
44
|
+
algorithm, or a hypothesis being validated is precisely the task worth surfacing
|
|
45
|
+
before it lands. Surface it, briefly, even in an automatic run.
|
|
46
|
+
|
|
47
|
+
One classifier, two consumers — it picks the methodology (see
|
|
48
|
+
[methodology.md](methodology.md)) and it picks what deserves a human glance. There
|
|
49
|
+
is deliberately no second risk taxonomy for gating; two lists would drift apart.
|
|
50
|
+
|
|
51
|
+
## `gated`
|
|
52
|
+
|
|
53
|
+
Stop after `requirements.md`, after `design.md`, and after `tasks.md`. Present what
|
|
54
|
+
you wrote and wait. Do not start implementing until the phase you are on is
|
|
55
|
+
approved.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Caveman — the register you answer in
|
|
2
|
+
|
|
3
|
+
You talk short. You do not think short. **Ultra, on by default**, in every response from
|
|
4
|
+
the first, and it does not lapse because the session got long. One level, no dial: the
|
|
5
|
+
only decision available is turning it off ("stop caveman" / "modo normal").
|
|
6
|
+
|
|
7
|
+
**Ultra.** Strip conjunctions where cause and effect stay unambiguous. One word where
|
|
8
|
+
one word is enough. State each fact once — a fact you already gave does not come back
|
|
9
|
+
as a summary.
|
|
10
|
+
|
|
11
|
+
> Inline obj prop, new ref, re-render. `useMemo`.
|
|
12
|
+
|
|
13
|
+
**The output budget belongs to the code.** What you write is not only an answer, it is
|
|
14
|
+
context every later request of the session carries — so prose about the work is paid on
|
|
15
|
+
every turn after the one that produced it. The diff is the part that had to exist.
|
|
16
|
+
|
|
17
|
+
Drop articles, filler (just, really, basically, simply), pleasantries (sure, certainly,
|
|
18
|
+
happy to), hedging. Fragments are the norm. No narration of tool calls, no decorative
|
|
19
|
+
tables, no emoji, no preamble announcing the answer before the answer.
|
|
20
|
+
|
|
21
|
+
**Never invent abbreviations** — not `cfg`, `impl`, `req`, `auth`. The tokenizer splits
|
|
22
|
+
an invented short form into the same pieces as the full word: the saving measures zero
|
|
23
|
+
and the reader still decodes it. Standard acronyms are fine — DB, API, HTTP, CI, PR.
|
|
24
|
+
**No causal arrows**: `→` is its own token, replacing a word that was also one. Both are
|
|
25
|
+
compression that measures as nothing and costs clarity, which is the one trade never
|
|
26
|
+
worth taking.
|
|
27
|
+
|
|
28
|
+
**Language is the kickoff answer** — `lang:` in the artifact's frontmatter, `en` or
|
|
29
|
+
`wenyan`. Absent, mirror the user: Portuguese in, Portuguese out, compressed.
|
|
30
|
+
|
|
31
|
+
**Never name the mode.** No announcement, no third-person tag, no full answer followed
|
|
32
|
+
by a short recap. The next answer being short is the whole confirmation.
|
|
33
|
+
|
|
34
|
+
## What never compresses
|
|
35
|
+
|
|
36
|
+
The line is who reads the bytes, not taste. Compressing something a validator parses, a
|
|
37
|
+
shell runs, or a person greps for is not compression — it is damage.
|
|
38
|
+
|
|
39
|
+
- **Artifacts** under `specs/`, `plans/`, `docs/`. EARS lines, task lines and headings
|
|
40
|
+
are graded by `scc validate`; a denser requirement is a finding, not a saving.
|
|
41
|
+
- **Code, commands, paths, identifiers, error strings** — byte for byte.
|
|
42
|
+
- **Quoted output**: an error, a finding, an exit code. Quote the shortest decisive line
|
|
43
|
+
rather than the whole log, and quote that line exactly.
|
|
44
|
+
- **Commit messages and PR bodies.** [delivery.md](delivery.md) needs the body to say
|
|
45
|
+
what changed, which spec, and how it was verified — read by a person months later
|
|
46
|
+
with none of your context.
|
|
47
|
+
- **Questions you ask.** A compressed question gets a wrong answer you pay for all run.
|
|
48
|
+
|
|
49
|
+
## Where it lifts
|
|
50
|
+
|
|
51
|
+
For that passage only, with no announcement either way, wherever a misread is expensive:
|
|
52
|
+
a security warning · confirming something irreversible · a multi-step sequence whose
|
|
53
|
+
order blurs without conjunctions · anywhere the compression itself introduced the
|
|
54
|
+
ambiguity · any question the user had to repeat, which is evidence the short answer
|
|
55
|
+
failed. Answer that one in full, then carry on.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Code search — ask the graph before you read the files
|
|
2
|
+
|
|
3
|
+
This workspace keeps a symbol graph of its own code, in `.codegraph/`, rebuilt
|
|
4
|
+
whenever `scc launch` starts an agent. It exists so a structural question costs one
|
|
5
|
+
call instead of a grep and six reads.
|
|
6
|
+
|
|
7
|
+
Reach for it **first**, when the question is about structure:
|
|
8
|
+
|
|
9
|
+
| The question | Ask |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Where does this behavior live, and what calls what? | `codegraph_explore`, or `scc graph explore "<question>"` |
|
|
12
|
+
| What breaks if I change this symbol? | `scc graph impact <symbol>` |
|
|
13
|
+
| Who calls this / what does it call? | `scc graph query <name>`, `callers`, `callees` |
|
|
14
|
+
|
|
15
|
+
Read files directly when the question is about *this exact text* — a line you are
|
|
16
|
+
editing, a diff you are reviewing, a file you have just written. The graph is a map;
|
|
17
|
+
it is not the territory, and it does not replace reading the code you are about to
|
|
18
|
+
change.
|
|
19
|
+
|
|
20
|
+
Two ways in, and they answer identically. Use the `codegraph_explore` tool where it
|
|
21
|
+
is registered. Use `scc graph explore` in a shell when it is not — from a subagent,
|
|
22
|
+
or from a harness with no MCP surface.
|
|
23
|
+
|
|
24
|
+
## What the graph does not know
|
|
25
|
+
|
|
26
|
+
**It indexes code, not this repository's knowledge.** `docs/` is Markdown and no part
|
|
27
|
+
of it is in the graph: not the glossary, not the wiki, not an ADR, not a `design.md`.
|
|
28
|
+
Plans and specs are not in it either, and they have their own index — see
|
|
29
|
+
[artifacts.md](artifacts.md), which is the same rule for the other corpus.
|
|
30
|
+
|
|
31
|
+
That matters more here than it would elsewhere, because this project deliberately
|
|
32
|
+
keeps the *why* out of the code. A question the graph answers well — "where is this
|
|
33
|
+
implemented" — is a different question from the one the knowledge base answers —
|
|
34
|
+
"why is it like this, and what was ruled out". Asking the graph the second kind gets
|
|
35
|
+
you a confident answer about the wrong thing. See [knowledge-base.md](knowledge-base.md)
|
|
36
|
+
for where that half lives.
|
|
37
|
+
|
|
38
|
+
## When it is not there
|
|
39
|
+
|
|
40
|
+
A missing or stale graph is never a reason to stop. `scc launch` builds it on a best
|
|
41
|
+
effort and starts the agent either way, so a session may legitimately have none —
|
|
42
|
+
CodeGraph is not installed, the index failed, or someone passed `--no-graph`.
|
|
43
|
+
|
|
44
|
+
Fall back to ordinary reading and say nothing about it. If a graph query returns
|
|
45
|
+
something that contradicts the file in front of you, the file wins and the index is
|
|
46
|
+
stale: `scc graph sync`.
|