@renzrollon/interlock 1.0.0
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.
- package/.claude-plugin/marketplace.json +19 -0
- package/.claude-plugin/plugin.json +58 -0
- package/CHANGELOG.md +380 -0
- package/LICENSE +21 -0
- package/README.md +358 -0
- package/agents/ping.md +8 -0
- package/agents/worker.md +8 -0
- package/bin/interlock +2655 -0
- package/bin/interlock-graph +6 -0
- package/bin/interlock-run +508 -0
- package/bin/interlock-ship-acp +39 -0
- package/hooks/_shared.mjs +162 -0
- package/hooks/guard-commit.mjs +77 -0
- package/hooks/guard-tasks.mjs +107 -0
- package/hooks/guard-tests.mjs +63 -0
- package/hooks/preflight.mjs +107 -0
- package/lib/artifacts.mjs +316 -0
- package/lib/autonomy.mjs +149 -0
- package/lib/conformance.mjs +132 -0
- package/lib/doctor.mjs +1176 -0
- package/lib/drift.mjs +409 -0
- package/lib/eval-history.mjs +304 -0
- package/lib/evals-calibrate.mjs +317 -0
- package/lib/evals-capture.mjs +437 -0
- package/lib/evals-promote.mjs +257 -0
- package/lib/evals-triage.mjs +216 -0
- package/lib/findings.mjs +340 -0
- package/lib/graph/cli.mjs +266 -0
- package/lib/graph/extract/config-json.mjs +74 -0
- package/lib/graph/extract/create-extractor.mjs +35 -0
- package/lib/graph/extract/memory.mjs +99 -0
- package/lib/graph/extract/openspec.mjs +80 -0
- package/lib/graph/extract/python.mjs +137 -0
- package/lib/graph/extract/regex-fallback.mjs +187 -0
- package/lib/graph/extract/shell.mjs +71 -0
- package/lib/graph/extract/typescript.mjs +217 -0
- package/lib/graph/extract/walk.mjs +272 -0
- package/lib/graph/format.mjs +51 -0
- package/lib/graph/graph/build.mjs +374 -0
- package/lib/graph/graph/query.mjs +249 -0
- package/lib/graph/graph/report.mjs +122 -0
- package/lib/graph/graph/update.mjs +47 -0
- package/lib/graph/paths.mjs +66 -0
- package/lib/graph/retrieve/context.mjs +86 -0
- package/lib/graph/retrieve/docs-index.mjs +116 -0
- package/lib/graph/retrieve/markdown.mjs +246 -0
- package/lib/host/acp.mjs +551 -0
- package/lib/host/claude-cli.mjs +285 -0
- package/lib/host/codex.mjs +231 -0
- package/lib/host/model-map.mjs +129 -0
- package/lib/host/qwen.mjs +176 -0
- package/lib/host/registry.mjs +213 -0
- package/lib/host.mjs +393 -0
- package/lib/ledger.mjs +444 -0
- package/lib/limits.mjs +525 -0
- package/lib/locators.mjs +99 -0
- package/lib/merge-lanes.mjs +148 -0
- package/lib/metrics.mjs +99 -0
- package/lib/notify.mjs +229 -0
- package/lib/outcomes.mjs +560 -0
- package/lib/plan-fingerprint.mjs +570 -0
- package/lib/project-slug.mjs +18 -0
- package/lib/prompts/commit.mjs +26 -0
- package/lib/prompts/dimensions.mjs +70 -0
- package/lib/prompts/handoff.mjs +86 -0
- package/lib/prompts/implementer.mjs +150 -0
- package/lib/prompts/index.mjs +250 -0
- package/lib/prompts/planner.mjs +70 -0
- package/lib/prompts/remediate.mjs +137 -0
- package/lib/prompts/replan.mjs +23 -0
- package/lib/prompts/review.mjs +107 -0
- package/lib/prompts/schemas.mjs +206 -0
- package/lib/prompts/stage.mjs +48 -0
- package/lib/prompts/verify.mjs +88 -0
- package/lib/ready.mjs +812 -0
- package/lib/receipt.mjs +434 -0
- package/lib/remediate.mjs +275 -0
- package/lib/report-html.mjs +623 -0
- package/lib/report.mjs +1124 -0
- package/lib/review-core.mjs +713 -0
- package/lib/risk.mjs +370 -0
- package/lib/run-log.mjs +1004 -0
- package/lib/run-paths.mjs +239 -0
- package/lib/run.mjs +2921 -0
- package/lib/ship-stage.mjs +223 -0
- package/lib/spill.mjs +150 -0
- package/lib/surface.mjs +195 -0
- package/lib/verify.mjs +1074 -0
- package/lib/waves.mjs +2661 -0
- package/package.json +40 -0
- package/shared/CONTEXT-HYGIENE.md +84 -0
- package/shared/DECISION-LEDGER.md +141 -0
- package/shared/EXPLORE-BRIEF.md +96 -0
- package/shared/INVARIANT-SWEEP.md +57 -0
- package/shared/SESSION-SHAPES.md +261 -0
- package/shared/SKILL-CANDIDATE-BRIEF.md +106 -0
- package/shared/TEST-PROFILE.md +204 -0
- package/shared/TOOL-ECONOMY.md +155 -0
- package/skills/bootstrap/SKILL.md +226 -0
- package/skills/commit/SKILL.md +99 -0
- package/skills/dispatch/SKILL.md +78 -0
- package/skills/docs-digest/SKILL.md +109 -0
- package/skills/evals/SKILL.md +160 -0
- package/skills/explain-code/SKILL.md +42 -0
- package/skills/explain-code/commit-teachin.md +136 -0
- package/skills/explain-code/module-walkthrough.md +358 -0
- package/skills/explore/SKILL.md +159 -0
- package/skills/fix-tests/SKILL.md +120 -0
- package/skills/graph/SKILL.md +136 -0
- package/skills/manual-test-plan/SKILL.md +121 -0
- package/skills/mr/SKILL.md +170 -0
- package/skills/report/SKILL.md +121 -0
- package/skills/review-artifacts/SKILL.md +127 -0
- package/skills/review-code/REVIEW.template.md +49 -0
- package/skills/review-code/SKILL.md +156 -0
- package/skills/review-code/dimensions/architecture.md +10 -0
- package/skills/review-code/dimensions/devops.md +12 -0
- package/skills/review-code/dimensions/language.md +12 -0
- package/skills/review-code/dimensions/qa.md +12 -0
- package/skills/review-code/dimensions/security.md +12 -0
- package/skills/review-code/dimensions/technical-lead.md +19 -0
- package/skills/ship/SKILL.md +67 -0
- package/skills/spec/SKILL.md +264 -0
- package/skills/spec/continuity.md +66 -0
- package/workflows/ship.js +565 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Tool Economy — Locate Before You Read, Batch Your Bash, Read State Don't Re-Derive It
|
|
2
|
+
|
|
3
|
+
Shared discipline for all interlock skills that investigate a codebase or
|
|
4
|
+
gather project state. Companion to `CONTEXT-HYGIENE.md` and `INVARIANT-SWEEP.md`.
|
|
5
|
+
|
|
6
|
+
## Rule 0 — Query the graph before you Grep (when it exists)
|
|
7
|
+
|
|
8
|
+
If `.claude/graph/graph.json` exists, treat it as the first locator for
|
|
9
|
+
structural questions — “where is X”, “who uses Y”, “how does A reach B”:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
interlock-graph query "<tokens>" --budget 1500
|
|
13
|
+
interlock-graph consumers <symbol-or-file>
|
|
14
|
+
interlock-graph path <A> <B>
|
|
15
|
+
interlock-graph explain <node>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
(`interlock-graph` is on PATH whenever this plugin is enabled — never probe for it.)
|
|
19
|
+
|
|
20
|
+
Read `.claude/graph/GRAPH_REPORT.md` once for hubs/modules when scoping a
|
|
21
|
+
fan-out. Then Grep/Read only for detail the graph lacks (dynamic imports,
|
|
22
|
+
stringly keys, generated code, languages outside the graph walk).
|
|
23
|
+
|
|
24
|
+
If the graph is missing and the session will do heavy exploration, prefer
|
|
25
|
+
`interlock-graph build .` (or `/interlock:graph rebuild`) once over repeated blind greps.
|
|
26
|
+
Do **not** rebuild on every query when the graph already exists — use
|
|
27
|
+
`interlock-graph update` after large merges.
|
|
28
|
+
|
|
29
|
+
## Rule 0.5 — Budgeted documentation retrieval (don't preload `docs/`)
|
|
30
|
+
|
|
31
|
+
Do **not** read all `docs/*.md` or concatenate OpenSpec markdown into context
|
|
32
|
+
upfront. Prefer the agent-only digest, then retrieve cited excerpts on demand.
|
|
33
|
+
|
|
34
|
+
**Digest-first ladder**
|
|
35
|
+
|
|
36
|
+
1. If `.claude/graph/DOCS_DIGEST.md` exists → Read it **once** as the default docs
|
|
37
|
+
primer (bounded agent-only file; prose twin of `GRAPH_REPORT.md`). Do not also
|
|
38
|
+
preload raw `docs/`.
|
|
39
|
+
2. Task-specific drill-down → budgeted retrieve:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
interlock-graph context "<task tokens>" --budget 2000 --changed path/a.ts,path/b.ts
|
|
43
|
+
interlock-graph docs "<domain terms>" --budget 800
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
3. If digest missing/stale and the session needs domain prose → run `/interlock:docs-digest`
|
|
47
|
+
(rebuilds via `interlock-graph docs-index` + compress), else proceed with `context` only.
|
|
48
|
+
4. Fallback when retrieve is empty (at most one query rewrite, then stop sprawl):
|
|
49
|
+
- broaden terms once (`auth` → `authentication session`)
|
|
50
|
+
- `grep` headings in `docs/` / `openspec/`, then Read spans
|
|
51
|
+
- if graph missing: `docs` only, or read `docs/architecture.md` headings via grep
|
|
52
|
+
|
|
53
|
+
> **Widening is a deliberate position, not an oversight.** [The Spec Growth
|
|
54
|
+
> Engine](https://arxiv.org/abs/2606.27045) §5.3 argues the opposite: *"the
|
|
55
|
+
> default repair for an insufficient context is to fix the spec graph, not to
|
|
56
|
+
> widen the context."* That is right when every module is required to carry a
|
|
57
|
+
> machine-readable contract — an empty retrieval then means the architecture has
|
|
58
|
+
> a hole, and widening hides it. Interlock targets brownfield repos where the
|
|
59
|
+
> spec graph is incomplete by construction, and "fix the spec graph" is not an
|
|
60
|
+
> action available mid-task. So we widen once, bounded, and stop. Take the
|
|
61
|
+
> paper's repair instead whenever the spec genuinely should have covered it.
|
|
62
|
+
|
|
63
|
+
**Default budgets**
|
|
64
|
+
|
|
65
|
+
| Command | Budget | Role |
|
|
66
|
+
|---------|--------|------|
|
|
67
|
+
| `DOCS_DIGEST.md` | ~2500 soft / ~3200 hard | Agent-only prose bootstrap (via `/interlock:docs-digest`) |
|
|
68
|
+
| `context` | 2000 tokens | Combined structural + documentation bundle |
|
|
69
|
+
| `docs` | 800 tokens | Prose/domain context only |
|
|
70
|
+
| `query` / `consumers` | 1500 tokens | Structural navigation |
|
|
71
|
+
| `docs-index` | (index JSON) | Deterministic TOC/hashes for digest rebuild |
|
|
72
|
+
|
|
73
|
+
**Provenance** — every excerpt must cite `file:heading (Lstart-Lend)`.
|
|
74
|
+
Treat graph `INFERRED` edges as hints; verify with Read spans before claims.
|
|
75
|
+
|
|
76
|
+
**Authoritative artifact exception** — when implementing against an active OpenSpec
|
|
77
|
+
change, still read **all** of `proposal.md`, `design.md`, `tasks.md`, and delta
|
|
78
|
+
specs for that change first. Rule 0.5 replaces exploratory preload, not the
|
|
79
|
+
implementation contract leash (`/interlock:ship`).
|
|
80
|
+
|
|
81
|
+
**Batch gathers** — a non-interactive run that needs project prose should pull a
|
|
82
|
+
single bounded bundle via `interlock-graph context`, never `find docs -exec cat`.
|
|
83
|
+
If `context` fails, prefer `.claude/graph/DOCS_DIGEST.md` over reading the head
|
|
84
|
+
of an architecture doc.
|
|
85
|
+
|
|
86
|
+
## Rule 1 — Locate before you Read
|
|
87
|
+
|
|
88
|
+
Use `grep` / the Grep tool to find the file and line first, then Read with
|
|
89
|
+
`offset`/`limit` around the hit. Do **not** Read whole files sequentially to
|
|
90
|
+
discover where something lives. Read a file in full only once you know it's the
|
|
91
|
+
one you need. When Rule 0 applies, graph query/consumers counts as “locate.”
|
|
92
|
+
|
|
93
|
+
## Rule 2 — Batch and background your Bash
|
|
94
|
+
|
|
95
|
+
- **Independent read-only commands** go in one message (multiple tool calls) or
|
|
96
|
+
joined with `;` — not `&&`. `&&` short-circuits: if an early command exits
|
|
97
|
+
non-zero, the later ones never run and their output is silently lost. For a
|
|
98
|
+
status sweep (`git branch`, `git status`, `git log`, `openspec status`) you
|
|
99
|
+
want them all regardless, so batch them.
|
|
100
|
+
- **Reserve `&&` for dependency-ordered chains** where a later step is meaningless
|
|
101
|
+
if an earlier one failed — e.g. `npm run typecheck && npm run lint && npm test
|
|
102
|
+
&& npm run build`.
|
|
103
|
+
- **Quote shell globs** in filter arguments (`--include='*.ts'`,
|
|
104
|
+
`--glob '*.ts'`) so zsh does not expand them before the command sees them.
|
|
105
|
+
Prefer the Grep tool for `--include`-style file filtering when available.
|
|
106
|
+
- **Background the long-running.** Builds, full test suites, and installs run with
|
|
107
|
+
`run_in_background` so you can continue other work while they execute.
|
|
108
|
+
|
|
109
|
+
## Rule 3 — Read state, don't re-derive it
|
|
110
|
+
|
|
111
|
+
At session start, current-task context comes from a few cheap, authoritative
|
|
112
|
+
sources — `git log --oneline`, `git status --short`, `openspec status --json`,
|
|
113
|
+
an open-task grep over `openspec/changes/*/tasks.md`, and the latest handoff.
|
|
114
|
+
Front-load these in one pass. Read them,
|
|
115
|
+
then act. Do not re-traverse the tree to reconstruct what they already tell you.
|
|
116
|
+
|
|
117
|
+
**Explore brief as Rule-3 state:** when `/interlock:spec` runs after explore
|
|
118
|
+
(especially after `/clear` or prompt-cache expiry), read the latest matching
|
|
119
|
+
`.claude/handoff/explore-*.md` first (see `EXPLORE-BRIEF.md`).
|
|
120
|
+
Prefer the brief’s recommendations over re-deriving discovery from the codebase
|
|
121
|
+
or chat. Reopen code only for gaps or contradictions. Writing that brief in
|
|
122
|
+
autonomous explore is how explore pays forward — spec should not re-pay.
|
|
123
|
+
|
|
124
|
+
## Rule 4 — Spilled verify output: locator then Read spans, never the whole file
|
|
125
|
+
|
|
126
|
+
`interlock verify spill` writes a command's full stdout/stderr to
|
|
127
|
+
`.claude/ship/spill/<runId>/<seq>-<kind>.log` once it passes
|
|
128
|
+
`LIMITS.verifySpillBytes`, and hands back `{ locator, preview, bytes, sha256 }`.
|
|
129
|
+
The `preview` is already a head-and-tail slice bounded by
|
|
130
|
+
`LIMITS.verifyPreviewChars` — read it from the result, do not re-open the
|
|
131
|
+
locator to get what the preview already gives you.
|
|
132
|
+
|
|
133
|
+
Only reopen the locator when the preview genuinely does not answer the
|
|
134
|
+
question (a failure whose stack trace was in the omitted middle). Then Read it
|
|
135
|
+
the same way Rule 1 says: with `offset`/`limit` around the span you need, not
|
|
136
|
+
the whole file. A spilled suite log can be hundreds of KB — reading it in full
|
|
137
|
+
defeats the reason it was spilled instead of pasted into the result.
|
|
138
|
+
|
|
139
|
+
Never paste spilled bytes back into a verify result field (`detail`,
|
|
140
|
+
`cliStdout`, `reason`, `stdout`, `stderr`, `output`, or a `failures[]` entry).
|
|
141
|
+
`interlock verify judge` / `verify unit` check every one of those fields
|
|
142
|
+
against the preview budget and reject the result outright — "oversized result
|
|
143
|
+
field(s)" — if any exceeds it. The locator is not a courtesy; the anti-swallow
|
|
144
|
+
check enforces it.
|
|
145
|
+
|
|
146
|
+
## When NOT to apply
|
|
147
|
+
|
|
148
|
+
This targets *wasted* exploration, not legitimate reconnaissance:
|
|
149
|
+
|
|
150
|
+
- Genuine cross-subsystem investigation still warrants a fan-out
|
|
151
|
+
(`/interlock:explore`). Rule 1 applies *within* each investigator; the
|
|
152
|
+
decision to fan out is unchanged.
|
|
153
|
+
- The artifact leash still holds: when you're about to implement against a
|
|
154
|
+
proposal/design/tasks set, read all of it first (see `/interlock:ship`).
|
|
155
|
+
That is not the sprawl this file is about.
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bootstrap
|
|
3
|
+
description: Onboard a brownfield project into OpenSpec — analyze the existing codebase with parallel explorer agents, write an initial architecture document, then generate one spec per discovered feature describing what is already built. Use when adopting spec-driven development on a repo that has code but no specs.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Requires the openspec CLI. Node.js >= 18 for the bundled interlock-graph CLI.
|
|
6
|
+
argument-hint: "[--quick] [--scope <path>]"
|
|
7
|
+
allowed-tools: Bash(openspec *) Bash(interlock-graph *) Bash(git check-ignore *) Agent Read Write Glob Grep
|
|
8
|
+
metadata:
|
|
9
|
+
type: discovery
|
|
10
|
+
outputs:
|
|
11
|
+
- openspec/initial-architecture.md
|
|
12
|
+
- openspec/specs/<feature>/spec.md
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
Document what a codebase **already is**, in OpenSpec form, so that every later change has something to change *from*.
|
|
16
|
+
|
|
17
|
+
This is archaeology, not design. Every spec you write describes behavior that exists in the code today. If you cannot point at the code that implements a requirement, it does not belong in the spec.
|
|
18
|
+
|
|
19
|
+
| Flag | Effect |
|
|
20
|
+
|------|--------|
|
|
21
|
+
| `--quick` | Sequential, single-context. For small repos (< ~50 source files). |
|
|
22
|
+
| `--scope <path>` | Restrict the whole run to a subdirectory. |
|
|
23
|
+
| *(none)* | Full parallel run. |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 0. Pre-flight
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Initialize OpenSpec if this repo has never been initialized.
|
|
31
|
+
# `openspec init` creates openspec/config.yaml, so its absence is the real signal.
|
|
32
|
+
test -f openspec/config.yaml || openspec init --tools claude
|
|
33
|
+
|
|
34
|
+
# Build the structural graph once — it seeds every explorer below.
|
|
35
|
+
# Never swallow the outcome: stderr stays visible, and both failure modes
|
|
36
|
+
# (build errored / nothing indexable) get a banner.
|
|
37
|
+
graph_log=$(interlock-graph build .)
|
|
38
|
+
graph_status=$?
|
|
39
|
+
printf '%s\n' "$graph_log"
|
|
40
|
+
if [ "$graph_status" -ne 0 ]; then
|
|
41
|
+
echo "GRAPH UNAVAILABLE: build errored (exit $graph_status) — explorers fall back to grep and will be slower"
|
|
42
|
+
elif printf '%s' "$graph_log" | grep -q 'nodes=0'; then
|
|
43
|
+
echo "GRAPH UNAVAILABLE: nothing indexable found — explorers fall back to grep and will be slower"
|
|
44
|
+
fi
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**A graph failure is not a stop.** Bootstrap works without it — docs and OpenSpec indexing still happen — so print the banner, carry it to the final report, and continue with degraded expectations: the explorers grep instead of following edges, and they are slower for it.
|
|
48
|
+
|
|
49
|
+
`nodes=0` is the ordinary case for a repo the graph doesn't structurally index (Go, Rust, Java, Ruby — structural indexing covers JavaScript/TypeScript, Python and shell). Say which of the two reasons applied rather than presenting either as a defect.
|
|
50
|
+
|
|
51
|
+
When the build did produce a graph, **read `.claude/graph/GRAPH_REPORT.md` before spawning anything**. Its hub nodes and module boundaries tell the explorers where to look, so they don't rediscover the tree from scratch.
|
|
52
|
+
|
|
53
|
+
Then check whether `openspec/specs/` already has content. If it does:
|
|
54
|
+
|
|
55
|
+
> "This project already has N specs. Bootstrap will ADD specs for undocumented features but will never overwrite an existing one. Continue?"
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 1. DISCOVER — parallel exploration
|
|
60
|
+
|
|
61
|
+
Spawn five explorer subagents via the Agent tool (`subagent_type: "Explore"`), or run them in sequence under `--quick`. Each returns structured JSON.
|
|
62
|
+
|
|
63
|
+
**Before writing the prompts, establish the stack.** Read the dependency manifest (`package.json`, `pyproject.toml`, `go.mod`, `Cargo.toml`, `pom.xml`, `Gemfile`, …) and the top-level layout. Then phrase each prompt in that stack's vocabulary. The categories below are universal; examples in your head are *illustrative only* — replace them with the frameworks this repo actually uses. Asking a Go service about React hooks wastes a whole agent.
|
|
64
|
+
|
|
65
|
+
Shared skeleton — fill `{role}`, `{task}`, `{schema}` from the table:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
You are the {role} explorer for this repo. Phrase findings in this stack's vocabulary.
|
|
69
|
+
{task}
|
|
70
|
+
Prefer GRAPH_REPORT.md / interlock-graph when a graph exists; otherwise grep.
|
|
71
|
+
Return JSON only: {schema}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
| Role | Task | JSON schema |
|
|
75
|
+
|------|------|-------------|
|
|
76
|
+
| Structure Mapper | Map layout. Prefer GRAPH_REPORT modules/hubs, then verify on disk. Report organization (feature/layer/hybrid), entry points and routes, naming conventions, key config files, monorepo yes/no. | `{ organization, entryPoints[], conventions[], configFiles[], monorepo }` |
|
|
77
|
+
| Dependency & Data Model Analyzer | Prefer `interlock-graph query` / `path`. Report third-party deps by role, internal layer imports, persistence schema/models, entity relationships, outbound integrations. | `{ dependencies[], internalLayers[], dataModels[], entityRelationships[], integrations[] }` |
|
|
78
|
+
| Pattern Extractor | Recurring composition (components/handlers/services), state/lifecycle, errors, auth, data fetch/mutate, testing, code style. | `{ compositionPatterns[], stateManagement, errorHandling, auth, dataFlow, testing, codeStyle }` |
|
|
79
|
+
| Interface Scanner | External surface: endpoints and protocol, mutations, schemas/validators, public exports/SDK, realtime/streaming, CLI. | `{ endpoints[], mutations[], schemas[], publicExports[], realtime[], cli[] }` |
|
|
80
|
+
| Infrastructure & Config Reader | Build/task-runner entry points, env vars referenced in code, CI/CD, deploy target, lint/format, typecheck/static analysis. | `{ buildSystem, tasks[], envVars[], cicd, deployment, linting, staticAnalysis }` |
|
|
81
|
+
|
|
82
|
+
Cap: 8 agents in this phase.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 2. SYNTHESIZE — the architecture document
|
|
87
|
+
|
|
88
|
+
One synthesis pass reads all five outputs and writes `openspec/initial-architecture.md`:
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
# Initial Architecture
|
|
92
|
+
|
|
93
|
+
> Auto-generated by /interlock:bootstrap on {date}.
|
|
94
|
+
> Point-in-time snapshot, not a living document.
|
|
95
|
+
|
|
96
|
+
## Stack & Infrastructure
|
|
97
|
+
## Project Organization
|
|
98
|
+
## Architecture Overview <- ASCII diagram, subsystem boundaries, data flow
|
|
99
|
+
## Data Model
|
|
100
|
+
## Subsystems & Features <- table: subsystem | location | responsibility | patterns
|
|
101
|
+
## Established Patterns <- composition, data flow, state, errors, auth, testing
|
|
102
|
+
## Interface Surface
|
|
103
|
+
## Design Decisions (Inferred)
|
|
104
|
+
- [EXTRACTED] stated outright in comments or docs
|
|
105
|
+
- [INFERRED] deduced from a consistent pattern
|
|
106
|
+
- [AMBIGUOUS] unclear — several patterns coexist
|
|
107
|
+
## Gaps & Risks <- incomplete work, conflicting patterns, hazards
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Tag every design decision with its confidence. An `[INFERRED]` decision that turns out wrong is recoverable; one presented as fact is not.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 3. IDENTIFY FEATURES — boundary detection
|
|
115
|
+
|
|
116
|
+
From the synthesis, pick the units that each deserve a spec:
|
|
117
|
+
|
|
118
|
+
- **Entry-point based** — each major route group, command, or consumer
|
|
119
|
+
- **Domain based** — each data model with a full lifecycle
|
|
120
|
+
- **Capability based** — cross-cutting concerns (auth, observability, error handling)
|
|
121
|
+
- **Module based** — feature directories and barrel exports
|
|
122
|
+
|
|
123
|
+
Present the list for confirmation before generating:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
Discovered N features to spec:
|
|
127
|
+
1. authentication — login, register, session management
|
|
128
|
+
2. task-crud — create, read, update, delete tasks
|
|
129
|
+
3. app-shell — layout, navigation, route protection
|
|
130
|
+
|
|
131
|
+
Generate specs for all, or select specific ones?
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 4. SPEC GENERATION — one agent per feature
|
|
137
|
+
|
|
138
|
+
For each confirmed feature, spawn a subagent (cap: 12).
|
|
139
|
+
|
|
140
|
+
> You are writing an OpenSpec spec for an **existing** feature. Document what IS built, not what SHOULD be.
|
|
141
|
+
> Feature: `{name}`. Architecture context: `{relevant section}`. Source files: `{paths}`.
|
|
142
|
+
> Read the implementation. Write requirements in the repo's OpenSpec spec format, each one traceable to code. Where behavior is genuinely unclear, mark it rather than guessing.
|
|
143
|
+
|
|
144
|
+
Write to `openspec/specs/<feature>/spec.md`. **Never overwrite an existing spec file.** If one exists, skip it and report the skip.
|
|
145
|
+
|
|
146
|
+
Then validate:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
openspec validate
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 5. UPDATE PROJECT CONTEXT
|
|
155
|
+
|
|
156
|
+
Fill in the project context in `openspec/config.yaml` with what was discovered — stack, architecture summary, conventions, domain — so later `openspec instructions` calls carry it. Merge into the existing file; never clobber unrelated keys a user has set.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 6. REPORT
|
|
161
|
+
|
|
162
|
+
- Any `GRAPH UNAVAILABLE: <reason> — explorers fall back to grep and will be slower` banner from pre-flight, repeated verbatim. If the graph built, say so in one line instead — a report that mentions neither reads like a graph-backed run that never happened.
|
|
163
|
+
- Architecture doc path and what it covers
|
|
164
|
+
- Specs created, and specs skipped because they already existed
|
|
165
|
+
- Features deliberately not specced, with the reason
|
|
166
|
+
- `openspec validate` result
|
|
167
|
+
- Corpus-persistence posture (below)
|
|
168
|
+
- Suggested next step: `/interlock:docs-digest` to build the agent prose primer
|
|
169
|
+
|
|
170
|
+
### Corpus-persistence posture
|
|
171
|
+
|
|
172
|
+
This is the one moment the repository is looked at before any run has written to
|
|
173
|
+
it, so raise the question now: will its run corpora be kept?
|
|
174
|
+
|
|
175
|
+
Observe the current state with git's own matcher — do **not** read or parse
|
|
176
|
+
`.gitignore`. Its semantics include negation, directory-only trailing slashes,
|
|
177
|
+
nested files, `.git/info/exclude` and the user's global excludes file, and a
|
|
178
|
+
hand-rolled match gets some of those wrong:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
git check-ignore -q .claude/ship/ ; echo "ship=$?"
|
|
182
|
+
git check-ignore -q .claude/learning/ ; echo "learning=$?"
|
|
183
|
+
git check-ignore -q .claude/metrics/ ; echo "metrics=$?"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Exit 0 means the path is excluded, 1 means it is tracked territory.
|
|
187
|
+
|
|
188
|
+
Report **each of the three separately** — never collapse them into one verdict.
|
|
189
|
+
A split state, where one is excluded and the others are not, is the case most
|
|
190
|
+
likely to be unintentional, and collapsing hides exactly that.
|
|
191
|
+
|
|
192
|
+
State the recommendation as **conditional**, never as a verdict about this
|
|
193
|
+
repository. Nothing you can observe tells you whether the repo will run
|
|
194
|
+
`/interlock:ship` against its own product, so say which posture fits which
|
|
195
|
+
intent and let the reader choose:
|
|
196
|
+
|
|
197
|
+
> `.claude/ship/` and `.claude/metrics/` are excluded, `.claude/learning/` is
|
|
198
|
+
> not. If this repository will run `/interlock:ship` on its own product, those
|
|
199
|
+
> exclusions drop the audit trail — remove them from `.gitignore`. If it is a
|
|
200
|
+
> harness whose ship runs are development exhaust, add `.claude/learning/` so
|
|
201
|
+
> all three match. Rationale and both `.gitignore` blocks: docs/11, "Whether to
|
|
202
|
+
> keep them".
|
|
203
|
+
|
|
204
|
+
**Never write to `.gitignore`.** Not to create it, not to append, not to "fix"
|
|
205
|
+
a split state. Name the entries a person could add and let them add them — this
|
|
206
|
+
skill was invoked to produce specs, and an edit to an unrelated file is a
|
|
207
|
+
surprise in someone's diff, not a service.
|
|
208
|
+
|
|
209
|
+
If any `git check-ignore` exits non-zero for a reason other than "not ignored"
|
|
210
|
+
— an unreadable `.gitignore`, or a directory that is not a git repository at all
|
|
211
|
+
— report the posture as **undetermined and say why**, then carry on. Bootstrap
|
|
212
|
+
completes and writes every artifact it would otherwise have written; a failed
|
|
213
|
+
check never fails the onboarding.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Guardrails
|
|
218
|
+
|
|
219
|
+
- **Never overwrite an existing spec.** Add only.
|
|
220
|
+
- **Never modify source code.** This skill is read-only outside `openspec/` and `.claude/graph/`.
|
|
221
|
+
- Respect `.gitignore`; skip vendored and generated trees.
|
|
222
|
+
- Max 8 explorer agents in phase 1, 12 spec agents in phase 4.
|
|
223
|
+
- **Idempotent.** Re-running adds newly-discovered features and leaves everything else alone.
|
|
224
|
+
- If a feature's behavior can't be determined from the code, say so in the spec rather than inventing a requirement.
|
|
225
|
+
|
|
226
|
+
Follow `${CLAUDE_PLUGIN_ROOT}/shared/TOOL-ECONOMY.md`.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit
|
|
3
|
+
description: Create a single feature-level commit after a change is implemented. Reads the OpenSpec change artifacts to write a verb-phrase conventional-commit message with an outcome summary and optional issue reference. Commit only — never runs tests, typecheck, lint or build, and never pushes.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Requires git. Optional openspec CLI for change context.
|
|
6
|
+
argument-hint: "[ISSUE-REF] [--yes]"
|
|
7
|
+
disable-model-invocation: true
|
|
8
|
+
allowed-tools: Bash(git *) Bash(openspec *) Bash(interlock *) Read Glob
|
|
9
|
+
metadata:
|
|
10
|
+
type: execution
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Write one good commit for a completed change.
|
|
14
|
+
|
|
15
|
+
**Commit only.** This skill never runs tests, typecheck, lint, or a build — not in any mode, `--yes` included. Something else already verified; if nothing did, that is a gap in the caller, not work for this skill to absorb.
|
|
16
|
+
|
|
17
|
+
`--yes` runs non-interactively: no confirmation prompt. It is **not** permission to push or amend.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Resolve the change and the issue reference
|
|
22
|
+
|
|
23
|
+
Resolve the change by trying, in order:
|
|
24
|
+
|
|
25
|
+
1. An explicit change name argument
|
|
26
|
+
2. The current branch name (`feat/<name>`, `fix/<name>`)
|
|
27
|
+
3. The most recently modified `openspec/changes/*/` directory
|
|
28
|
+
|
|
29
|
+
Ask only when the session is interactive **and** all three fail. Under `--yes`, never ask — report which rungs were tried and stop with a one-line message.
|
|
30
|
+
|
|
31
|
+
Extract an issue reference from the branch when one was not passed:
|
|
32
|
+
`feat/RD-65-task-page` → `RD-65` · `fix/PROJ-123-login-bug` → `PROJ-123`
|
|
33
|
+
|
|
34
|
+
If the branch looks like a feature branch but no reference was found:
|
|
35
|
+
> ⚠️ No issue reference found. Branch `<name>` looks like a feature branch — pass one as `/interlock:commit <REF>` to avoid rewriting the message later.
|
|
36
|
+
|
|
37
|
+
Interactive: wait for the user to confirm or supply one. Under `--yes`: emit that single line, **proceed without a ref**, and surface it again in the final report. On `main`, `develop`, or any branch without a `feat/`/`fix/` prefix, proceed silently — the reference is genuinely optional there.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Gather context
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
openspec status --change "<name>" --json
|
|
45
|
+
git status --short
|
|
46
|
+
git diff --stat
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Read `proposal.md` for the one-line intent, `design.md` for scope, and the checked items in `tasks.md` for what was actually done. Inspect the diff to confirm the message matches reality rather than matching the plan.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 3. Compose the message
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
<type>(<scope>): <verb phrase, imperative, lowercase>
|
|
57
|
+
|
|
58
|
+
Summary of changes:
|
|
59
|
+
- <outcome, not task completion>
|
|
60
|
+
- <outcome>
|
|
61
|
+
|
|
62
|
+
Refs: <ISSUE-REF>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- **Scope** is the issue reference when one exists (`feat(RD-65): …`), otherwise the primary module or feature area (`feat(tasks): …`).
|
|
66
|
+
- **Summary bullets describe outcomes**, not "completed task 2.3".
|
|
67
|
+
- **`Refs:` line** appears only when a reference exists. Omit the line entirely otherwise — never write `Refs: none`.
|
|
68
|
+
|
|
69
|
+
| | |
|
|
70
|
+
|---|---|
|
|
71
|
+
| Good | `feat(RD-65): add task list page with filtering and status badges` |
|
|
72
|
+
| Good | `fix(PROJ-123): resolve token refresh race condition` |
|
|
73
|
+
| Good | `feat(tasks): add task list page with filtering` |
|
|
74
|
+
| Bad | `feat(tasks): Task List Page` — not a verb phrase |
|
|
75
|
+
| Bad | `feat(tasks): added the new task list page` — past tense, wordy |
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 4. Preview and commit
|
|
80
|
+
|
|
81
|
+
Show the full message. Interactive: ask "Commit with this message?" and allow edits. Under `--yes`: print it and commit.
|
|
82
|
+
|
|
83
|
+
Stage by naming **every path explicitly**, then commit.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Guardrails
|
|
88
|
+
|
|
89
|
+
- **Never `git add -A` or `git add .`.** Name every path. Leave unrelated dirty files unstaged.
|
|
90
|
+
- **Never push.** `--yes` is not that permission.
|
|
91
|
+
- **Never amend** unless the user explicitly asks and the amend conditions hold. `--yes` is not that permission.
|
|
92
|
+
- **Never run tests, typecheck, lint, or build** — in any mode.
|
|
93
|
+
- **Never re-implement or quick-fix failing code here.** If the tree looks broken: interactive, warn and ask whether to commit anyway; under `--yes`, commit and report the observation. Never start a verify/fix loop either way.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 5. Report
|
|
98
|
+
|
|
99
|
+
Commit hash and subject, files committed, anything left unstaged, and the warning from step 1 if it fired. Suggest the next step: `/interlock:mr` to open or update the merge request.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dispatch
|
|
3
|
+
description: Route a request to the right interlock skill, after one batched pre-flight that loads git state, OpenSpec status, open tasks and graph presence in a single pass. Use when you are not sure which skill applies, or at the start of a session to orient before doing anything else.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Optional openspec CLI and git. Node.js >= 18 for the bundled interlock CLI.
|
|
6
|
+
allowed-tools: Bash(git *) Bash(openspec *) Bash(interlock *) Bash(interlock-graph *) Read Glob
|
|
7
|
+
metadata:
|
|
8
|
+
type: routing
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Figure out where the user actually is in the flow, then route. One cheap pre-flight beats an exploratory warm-up.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Step 0 — Pre-flight, batched
|
|
16
|
+
|
|
17
|
+
Run these **in one turn**, joined with `;` not `&&` — you want every answer regardless of which ones fail:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git branch --show-current; git status --short; git log --oneline -5
|
|
21
|
+
openspec list --json 2>/dev/null
|
|
22
|
+
interlock changes 2>/dev/null
|
|
23
|
+
ls -t .claude/handoff/explore-*.md 2>/dev/null | head -3
|
|
24
|
+
ls .claude/graph/GRAPH_REPORT.md .claude/graph/DOCS_DIGEST.md 2>/dev/null
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
That is Rules 2 and 3 of `${CLAUDE_PLUGIN_ROOT}/shared/TOOL-ECONOMY.md`: read state, do not re-derive it. Do not traverse the tree to reconstruct what these already tell you.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## The flow
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
graph → docs-digest → bootstrap (once per repo)
|
|
35
|
+
/interlock:spec explore → artifacts → review ⟵ STOPS. Human reviews.
|
|
36
|
+
/interlock:ship waves → verify → commit (workflow, zero-touch; --strict adds review)
|
|
37
|
+
/interlock:mr summary → merge request
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The gap between `spec` and `ship` is deliberate. Never bridge it automatically — if a spec is ready, say so and let the user start ship. The user can bridge it themselves with `/interlock:spec --continue`, but that is theirs to ask for; routing never offers it.
|
|
41
|
+
|
|
42
|
+
`ship` is a dynamic workflow. `/interlock:ship` is a skill trampoline that launches it via the Workflow tool (`scriptPath` → `workflows/ship.js`). Invoke the **skill** `interlock:ship` (or call Workflow with that scriptPath yourself). Do not treat a missing Workflow-namespaced command as "ship does not exist" — the skill is the entry point. If the trampoline halts because the Workflow tool is unavailable, that is the runtime gap (v2.1.154+, Dynamic workflows on in `/config`); do not implement the loop inline.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Routing table
|
|
47
|
+
|
|
48
|
+
| Situation | Route to |
|
|
49
|
+
|---|---|
|
|
50
|
+
| No `openspec/` directory, or no specs on an existing codebase | `/interlock:bootstrap` |
|
|
51
|
+
| No `.claude/graph/`, and the session will explore or review heavily | `/interlock:graph` (build) |
|
|
52
|
+
| Docs context too large, or the digest is stale | `/interlock:docs-digest` |
|
|
53
|
+
| "How does X work?", "what breaks if I change Y?", tracing, comparing options | `/interlock:explore` |
|
|
54
|
+
| "I want to build / fix X" — no change exists yet | `/interlock:spec` |
|
|
55
|
+
| A change exists with reviewed artifacts and unchecked tasks | `/interlock:ship` — only if the user asked to ship, and this conversation has not already run ship |
|
|
56
|
+
| Leftover unchecked boxes after a ship workflow just returned | Report them. Do not route to ship. |
|
|
57
|
+
| Implementation done, diff needs review | `/interlock:review-code` |
|
|
58
|
+
| Artifacts written but not yet reviewed | `/interlock:review-artifacts` |
|
|
59
|
+
| Suite is red, or a CI log was pasted | `/interlock:fix-tests` |
|
|
60
|
+
| "Explain this code" / "what changed in that commit?" | `/interlock:explain-code` |
|
|
61
|
+
| Need a QA checklist for a change | `/interlock:manual-test-plan` |
|
|
62
|
+
| Work is done and needs committing | `/interlock:commit` |
|
|
63
|
+
| MR or PR needs creating or updating | `/interlock:mr` |
|
|
64
|
+
| "I want to skip the checkpoint" / "don't stop and make me read it" | `/interlock:spec --continue` — **advanced**. Opt-in, fail-closed, and it stops anyway on anything a machine cannot settle. It cannot catch a wrong idea; only the read can. |
|
|
65
|
+
|
|
66
|
+
**Prerequisite checks before routing:**
|
|
67
|
+
|
|
68
|
+
- Routing to `ship` — run `interlock validate <change>` first. Not ready means route to `spec`, not ship. If a ship workflow already returned in this conversation, leftover boxes are a report, not a retry.
|
|
69
|
+
- Routing to `spec` with no explore brief and a question that spans subsystems — run `explore` first.
|
|
70
|
+
- Routing to anything that reads the graph when `.claude/graph/` is absent — offer to build it once.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Ambiguity
|
|
75
|
+
|
|
76
|
+
When two routes fit, prefer the **earlier phase**. Exploring when you should have specced costs one turn; shipping when you should have specced costs a bad change and a review cycle.
|
|
77
|
+
|
|
78
|
+
When the request genuinely does not fit any skill, say so and handle it directly. Not everything is a workflow, and forcing an ordinary question through a skill is worse than just answering it.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docs-digest
|
|
3
|
+
description: Compress a repo's docs and OpenSpec specs into one token-dense, agent-only primer at .claude/graph/DOCS_DIGEST.md — the prose twin of GRAPH_REPORT.md. Use when docs context is too large to load, after substantial docs or spec edits, or when asked to rebuild or refresh the docs digest. Not for producing human-readable documentation.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Requires Node.js >= 18. The interlock-graph CLI ships with this plugin and is on PATH automatically.
|
|
6
|
+
allowed-tools: Bash(interlock-graph *) Read Write
|
|
7
|
+
metadata:
|
|
8
|
+
type: discovery
|
|
9
|
+
outputs:
|
|
10
|
+
- .claude/graph/docs-index.json
|
|
11
|
+
- .claude/graph/DOCS_DIGEST.md
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
Produce **one agent-only primer** that lets a fresh agent understand this repo's documented domain without reading `docs/` end to end.
|
|
15
|
+
|
|
16
|
+
`GRAPH_REPORT.md` answers *what connects to what*. This answers *what this project means*. They are siblings, both under `.claude/graph/`.
|
|
17
|
+
|
|
18
|
+
**Inputs:** `docs/**` and `openspec/specs/**`, via the deterministic index.
|
|
19
|
+
**Output:** `.claude/graph/DOCS_DIGEST.md`, overwritten in place.
|
|
20
|
+
**Never indexed:** `openspec/changes/**`. Active change artifacts are read directly, not digested.
|
|
21
|
+
|
|
22
|
+
Run this when: the digest is missing or stale, docs or living specs changed substantially, or the user asks to rebuild it. **Do not run it per query** — interactive skills should read an existing fresh digest, not regenerate one.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Execution
|
|
27
|
+
|
|
28
|
+
### 1. Index (deterministic — no model judgement)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
interlock-graph docs-index . --write
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Writes `.claude/graph/docs-index.json` covering `docs/` and `openspec/specs/`, with a `sha256` and heading spans per file.
|
|
35
|
+
|
|
36
|
+
If the index is empty, stop and report that: a repo with no `docs/` and no `openspec/specs/` has nothing to digest, and inventing one is worse than having none.
|
|
37
|
+
|
|
38
|
+
### 2. Staleness check
|
|
39
|
+
|
|
40
|
+
If `.claude/graph/DOCS_DIGEST.md` exists, compare its frontmatter `source_hashes` against each `files[].sha256` in the index. All match, and the user didn't force a refresh? Report fresh and stop.
|
|
41
|
+
|
|
42
|
+
Rebuild when: hashes mismatch, the digest is missing, or the user says rebuild / refresh / force.
|
|
43
|
+
|
|
44
|
+
### 3. Selective read — never concatenate the corpus
|
|
45
|
+
|
|
46
|
+
Read `.claude/graph/docs-index.json` in full. It is an inventory, not the corpus.
|
|
47
|
+
|
|
48
|
+
Then read **section spans only** (`offset`/`limit` from each entry's `startLine`/`endLine`), highest signal first. Rank the index entries yourself using these signals, in order:
|
|
49
|
+
|
|
50
|
+
1. **Entry points.** A file whose path or title matches `readme`, `architecture`, `overview`, `getting-started`, `contributing`, or `adr` — these state intent and structure.
|
|
51
|
+
2. **Inbound references.** Files linked to most often from other indexed files. The index records outbound links; invert them. A doc everything points at is load-bearing.
|
|
52
|
+
3. **Spec coverage.** Every `openspec/specs/*/spec.md` capability gets at least its title and requirement blurbs — the capability map is the single most useful thing in the digest.
|
|
53
|
+
4. **Breadth over depth.** Prefer one section from each of ten documents over ten sections from one. You are building a map, not a summary.
|
|
54
|
+
|
|
55
|
+
Drop first under token pressure: long analysis or research write-ups, changelogs, meeting notes, anything whose blurb already conveys the point, and peripheral spec capabilities. For those, use the index blurb instead of reading a span.
|
|
56
|
+
|
|
57
|
+
Rank what the repo actually contains. Do not assume any particular filename exists.
|
|
58
|
+
|
|
59
|
+
**Forbidden:** `find docs -exec cat`, reading every `docs/**/*.md` or `openspec/specs/**/*.md` end to end, reading anything under `openspec/changes/`, and writing output anywhere under `docs/` or `openspec/`.
|
|
60
|
+
|
|
61
|
+
### 4. Write the digest
|
|
62
|
+
|
|
63
|
+
Overwrite `.claude/graph/DOCS_DIGEST.md` with exactly this contract:
|
|
64
|
+
|
|
65
|
+
```markdown
|
|
66
|
+
---
|
|
67
|
+
audience: agent-only
|
|
68
|
+
target_tokens: 2500
|
|
69
|
+
generated_at: <ISO-8601>
|
|
70
|
+
source_hashes:
|
|
71
|
+
<path>: <sha256>
|
|
72
|
+
# one entry per indexed file
|
|
73
|
+
---
|
|
74
|
+
# docs-digest
|
|
75
|
+
## map
|
|
76
|
+
- <short-key> → <path>
|
|
77
|
+
## facts
|
|
78
|
+
- <dense telegraphic facts; ;-joined clauses fine>
|
|
79
|
+
## workflows
|
|
80
|
+
- <agent-relevant workflows and constraints>
|
|
81
|
+
## specs
|
|
82
|
+
- <capability> → key requirements / constraints (telegraphic, pointer-heavy)
|
|
83
|
+
## pointers
|
|
84
|
+
- <path>#<heading> Lstart-Lend
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Omit `## specs` entirely when the index contains no `openspec/specs/` files.
|
|
88
|
+
|
|
89
|
+
**Style — this is read by agents, not people.** Telegraphic. Abbreviations fine. Lists and `→`. No tutorial tone, no narrative padding, no worked examples. Prefer a pointer over a paraphrase whenever the reader could drill down with `interlock-graph context` or a Read span.
|
|
90
|
+
|
|
91
|
+
**Budgets:** soft cap ~2500 tokens (`ceil(chars/4)`), hard stop ~3200. Drop lowest-priority content first. Never state a fact that isn't in the index or a span you actually read.
|
|
92
|
+
|
|
93
|
+
### 5. Report (≤10 lines)
|
|
94
|
+
|
|
95
|
+
Output path, token estimate, file count split by `docs/` vs `openspec/specs/`, fresh-vs-rebuilt, and a reminder that humans should keep reading `docs/` — this artifact is not for them.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Relation to the graph skill
|
|
100
|
+
|
|
101
|
+
| Need | Use |
|
|
102
|
+
|------|-----|
|
|
103
|
+
| Prose bootstrap / domain primer | This digest (`DOCS_DIGEST.md`) |
|
|
104
|
+
| Structural bootstrap | `GRAPH_REPORT.md`, `interlock-graph query` |
|
|
105
|
+
| Task-specific cited excerpts | `interlock-graph context` / `docs` |
|
|
106
|
+
| Active change artifacts | Read `openspec/changes/<name>/` directly — **never** this digest |
|
|
107
|
+
| TOC and hashes for this skill | `interlock-graph docs-index` |
|
|
108
|
+
|
|
109
|
+
Follow `${CLAUDE_PLUGIN_ROOT}/shared/TOOL-ECONOMY.md`.
|