opencode-harness-kit 0.0.0-stage → 0.1.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/GLOBAL.md ADDED
@@ -0,0 +1,110 @@
1
+ # Ground rules for every project
2
+
3
+ You are working inside a harness that has already been tuned for the model in
4
+ use. Everything the config and the hooks can enforce is enforced already: the
5
+ tools, the permissions, the command allowlist, the guard, the per-role effort
6
+ and step caps. This file is only what is left over once those are subtracted --
7
+ the judgement calls no plugin can make for you.
8
+
9
+ Read this once. It is short on purpose: long instruction lists get followed
10
+ worse, not better.
11
+
12
+ ## Verify, then claim
13
+
14
+ A task is finished when its verification command passes, not when the code
15
+ looks right. Run the project's own test, lint and typecheck command. Paste the
16
+ real result, including failures. If you cannot run it, say so plainly.
17
+
18
+ Never invent a test result, a benchmark number, a deploy URL, or a file path.
19
+
20
+ ## Decide, don't ask
21
+
22
+ This is the rule that most changes how a session goes, so it is stated as a
23
+ test rather than as a preference.
24
+
25
+ **Decide it yourself and say what you decided, in one line, when you report.**
26
+
27
+ Ask the human only when a wrong guess would:
28
+
29
+ - cost real money, or
30
+ - break the build in a way that cannot be undone, or
31
+ - publish, send, or otherwise make something visible to anyone else, or
32
+ - be irreversible.
33
+
34
+ Everything else is reversible and yours. Guessing at an import path, a
35
+ function name, a file location, a flag, or a test command: look it up and move
36
+ on. If you looked and could not find it, say that.
37
+
38
+ When you are genuinely blocked, ask **one** question, not five, and make it
39
+ answerable with a choice. "Should I use `X` or `Y`" is a question. "What are
40
+ your thoughts on the architecture" is a delay.
41
+
42
+ Never ask what a `grep` would answer.
43
+
44
+ ## Locate before you read
45
+
46
+ On the measured install, `read` ran 2,966 times against 135 `grep` and 114
47
+ `glob` calls — 249 searches, about twelve whole-file reads for every one of
48
+ them. Every production coding harness surveyed uses search-then-read precisely
49
+ to avoid this.
50
+
51
+ 1. `grep` or `glob` to find the candidate files and line numbers.
52
+ 2. `read` with an `offset`/`limit` for the range you need.
53
+ 3. Read a file whole only when you are about to edit it.
54
+
55
+ ## Never
56
+
57
+ - `git push`, publish, or open a pull request. A human does that.
58
+ - Commit a secret. If you find one, report it; do not move it.
59
+ - Read or write `.env`, `.npmrc`, `.netrc`, `.git-credentials`. The guard
60
+ blocks these and will keep blocking them.
61
+ - Edit a file outside the project directory. Scratch files in the OS temp
62
+ directory are the one exception.
63
+
64
+ The guard plugin enforces the mechanical half of this. It is not a suggestion
65
+ and it does not get quieter when you ask nicely. It blocks the secret files by
66
+ name, refuses writes that escape the project, and unwraps `sudo`, `env`, `git -C`
67
+ and shell wrappers before deciding what a command really does.
68
+
69
+ ## Where things live
70
+
71
+ This file is the map. The repository's own `AGENTS.md`, if present, is more
72
+ specific and wins. Do not restate project rules here.
73
+
74
+ Before you finish a task that changed structure, check whether a document
75
+ now describes something that no longer exists. Stale documentation costs the
76
+ next session more than a small code change.
77
+
78
+ ## Reasoning budget
79
+
80
+ Per-role effort and step caps are set in `opencode.json` and enforced by the
81
+ harness, not by anything written here. `plan` and `reviewer` run at the highest
82
+ available effort, `build` in the middle, `locate` and `verify` at the lowest,
83
+ because finding a thing and checking a thing are not design work. If you are
84
+ playing one of the low-effort roles and feel yourself designing an
85
+ architecture, stop and report the evidence instead.
86
+
87
+ ## When context grows
88
+
89
+ Tool output from earlier in the session is pruned automatically. You keep a
90
+ one-line record of what each command returned, not its full body. If you need
91
+ the body, re-run the command or re-read the range. That is cheaper than
92
+ reasoning over output that has already been summarised away.
93
+
94
+ Never re-run a command purely to get its output back into context. Say what
95
+ you need from it and get only that.
96
+
97
+ ## Model etiquette
98
+
99
+ If a request fails with a rate limit or a usage cap, **stop**. Do not retry the
100
+ same model; free routes often stay blocked for days, and the daily window only
101
+ resets at 00:00 UTC. Report it and ask for a new session. No plugin can swap
102
+ the model of a live session, so a new session is the actual fix.
103
+
104
+ If the model you are on is not the one described in the config, say so before
105
+ starting anything expensive.
106
+
107
+ ## When you are stuck
108
+
109
+ Say what you tried, what you expected, and what happened instead. A precise
110
+ report is more useful than a third attempt at the same approach.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 opencode-harness-kit contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,422 @@
1
- # Temporary Holding Version
1
+ # opencode-harness-kit
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![CI](https://github.com/crytobot459/space-harness/actions/workflows/ci.yml/badge.svg)](https://github.com/crytobot459/space-harness/actions/workflows/ci.yml)
4
+ [![npm](https://img.shields.io/npm/v/opencode-harness-kit.svg)](https://www.npmjs.com/package/opencode-harness-kit)
5
+
6
+ A harness kit for [OpenCode](https://opencode.ai) that is **model-agnostic by
7
+ construction**. Switching models is a data edit, not a code change.
8
+
9
+ ```bash
10
+ npx oc-harness init # pick a free model, then install + verify
11
+ ```
12
+
13
+ then restart opencode. That is the whole quickstart. No npm account needed on
14
+ your side — `npx` only downloads the published kit. Prefer git? The same three
15
+ steps from a checkout (see [Install](#install)):
16
+
17
+ ```bash
18
+ git clone https://github.com/crytobot459/space-harness.git
19
+ ./bin/oc-harness.mjs init
20
+ ```
21
+
22
+ The three steps `init` runs, spelled out for when you want to know what
23
+ happened (prefix with `npx` or `./bin/oc-harness.mjs` to taste):
24
+
25
+ ```bash
26
+ oc-harness use space-bunny-free # compile the profile
27
+ oc-harness install # link the agents, skills and GLOBAL.md
28
+ oc-harness verify # prove the install is whole
29
+ ```
30
+
31
+ `use` writes the config. `install` writes everything the config *points at*.
32
+ Skipping it is the failure mode this kit is built to prevent: see
33
+ [Install](#install).
34
+
35
+ ## The problem it solves
36
+
37
+ Tuning a coding harness for a model means answering model-specific questions:
38
+ how much context to reserve, which reasoning levels exist, whether temperature
39
+ is even accepted, how much privacy the provider gives you. Answer them in a
40
+ prompt and you get a paragraph the model reads once. Answer them in code and
41
+ you get two projects that share a name and nothing else.
42
+
43
+ This kit puts the answers in a profile:
44
+
45
+ ```
46
+ profiles/space-bunny-free.json ← the model
47
+ src/ ← no model name anywhere in here
48
+ ```
49
+
50
+ Same plugin source, four shipped profiles, four different behaviours. The test
51
+ suite asserts that rather than taking it on faith.
52
+
53
+ ## What the compiler derives
54
+
55
+ Given a profile, `oc-harness use` writes an `opencode.jsonc` with every
56
+ model-dependent number already worked out and commented:
57
+
58
+ ```
59
+ $ oc-harness use deepseek-v4-flash-free --print
60
+
61
+ // profile deepseek-v4-flash-free
62
+ // context 200,000 tokens
63
+ // input cap 200,000 tokens
64
+ // reasoning low < high < max
65
+ // retention zero-retention
66
+ //
67
+ // Derived numbers, do not hand-edit:
68
+ // compaction.reserved 24,000 (12% of the input cap)
69
+ // prune threshold 176,000 (input cap minus reserve)
70
+ // role effort plan=max build=high reviewer=max locate=low verify=low
71
+ // agent steps build=40 plan=25 reviewer=15 locate=12 verify=20
72
+ ```
73
+
74
+ Against a 1M-context model, the same source produces `reserved 62,915` and
75
+ `prune threshold 461,373`. Nobody edits those by hand, and nobody copies a
76
+ 200k-tuned config onto a 1M model and wonders why it overflows.
77
+
78
+ ### Levels are resolved, never emitted raw
79
+
80
+ A role asking for `max` on a model whose top level is `xhigh` gets `xhigh`, and
81
+ the substitution is reported:
82
+
83
+ ```
84
+ $ oc-harness show muse-spark-1.3-contributor-free
85
+ effort levels minimal < low < medium < high < xhigh
86
+ role effort
87
+ plan xhigh (requested max)
88
+ adjustments
89
+ ! role plan asked for max; muse-spark-1.3-contributor-free tops out at xhigh.
90
+ ```
91
+
92
+ A model with no tunable effort at all gets **no** `variant` written, rather than
93
+ a level it does not have.
94
+
95
+ ## Privacy is a first-class field
96
+
97
+ `models.dev` describes capability and price. It does not describe what a
98
+ provider does with your prompts. `retention.yml` is hand-curated for that
99
+ reason, and a profile cannot be installed until a human has stated its terms.
100
+
101
+ ```
102
+ $ oc-harness list
103
+ ▸ space-bunny-free 1,048,576 max zero-retention
104
+ ✗ muse-spark-1.3-contributor-free
105
+ Provider may train on your prompts and completions (Meta contributor
106
+ tier). Top effort is xhigh, not max.
107
+ ```
108
+
109
+ The excluded model is still installable with `--yes`, and the warning repeats
110
+ on install. It is not hidden, it is labelled.
111
+
112
+ ## Shipped profiles
113
+
114
+ | profile | context | top effort | retention |
115
+ |---|---|---|---|
116
+ | `space-bunny-free` (default) | 1,048,576 | `max` | zero-retention |
117
+ | `x-preview-f-free` | 1,000,000 | `max` | zero-retention |
118
+ | `longcat-2.5-preview-free` | 1,000,000 | — | zero-retention |
119
+ | `deepseek-v4-flash-free` | 200,000 | `max` | zero-retention |
120
+ | `muse-spark-1.3-contributor-free` | 1,048,576 | `xhigh` | **may train** |
121
+
122
+ ## Commands
123
+
124
+ ```
125
+ oc-harness list profiles with retention and caveats
126
+ oc-harness use <id> compile a profile into ~/.config/opencode/opencode.jsonc
127
+ oc-harness show <id> resolved effort, derived numbers, fallback queue
128
+ oc-harness install symlink the plugin, agents, skills and GLOBAL.md
129
+ oc-harness verify check the install against the profile; non-zero on drift
130
+ oc-harness agents report agents the effort tiering does not reach
131
+ oc-harness doctor re-check profiles against models.dev and the live config
132
+ oc-harness baseline measure the current install
133
+ ```
134
+
135
+ ### `verify` is the command that matters
136
+
137
+ A generated config is only half an install. The other half is the instruction
138
+ file it names, the agent files it declares, and the plugin that enforces the
139
+ guard — and every one of those can be missing while the config still validates
140
+ and still looks correct.
141
+
142
+ That is not hypothetical. On a real install of this kit, `opencode.jsonc`
143
+ pointed at a `GLOBAL.md` that did not exist, declared three agents whose markdown
144
+ files had never been copied, and had `build` — the *default* agent — hand-pinned
145
+ to a `may-train` model while every generated field still matched the profile.
146
+ Nothing errored. `opencode agent list` simply did not show those agents.
147
+
148
+ So `verify` exits non-zero when the config has drifted from its profile, when an
149
+ instruction path does not resolve, when a tiered role has no agent file, when an
150
+ agent names a model that is not active, or when a stripped schema key is present:
151
+
152
+ ```
153
+ $ oc-harness verify
154
+
155
+ verify profile space-bunny-free -> ~/.config/opencode/opencode.jsonc
156
+
157
+ ✓ config matches profile space-bunny-free
158
+ ✓ instruction ~/.config/opencode/GLOBAL.md resolves
159
+ ✓ plugin linked
160
+
161
+ install is consistent with the profile
162
+ ```
163
+
164
+ `doctor` now reports the same config drift alongside its models.dev check, because
165
+ "the profile is fine" and "the installed config matches the profile" are
166
+ different questions and only one of them was being asked.
167
+
168
+ `doctor` exists because free models get withdrawn within days. It diffs each
169
+ profile against live metadata and reports drift:
170
+
171
+ ```
172
+ ✓ space-bunny-free matches catalog
173
+ ! muse-spark-1.3-contributor-free drift
174
+ input 524288 -> 1048576
175
+ ```
176
+
177
+ That drift was real; `doctor` found it during development.
178
+
179
+ ## Measuring before tuning
180
+
181
+ `oc-harness baseline` reads the OpenCode SQLite database and reports what is
182
+ actually happening, so thresholds come from measurements rather than intuition.
183
+ From one real install:
184
+
185
+ ```
186
+ CONTEXT PER REQUEST
187
+ p50 100,942 p90 256,940 p99 481,687 max 547,986
188
+ fresh input p50 528
189
+ STORED MESSAGE BYTES
190
+ tool 116.58 MB 77.9%
191
+ reasoning 23.10 MB 15.4%
192
+ text 3.12 MB 2.1%
193
+ READ PRESSURE
194
+ read calls 2,966
195
+ grep/glob/list 249
196
+ reads per search 11.9
197
+ reads over 8 KB 415
198
+ cut by the 200-line cap 441
199
+ re-reads with an offset 423
200
+ PERMISSION PRESSURE
201
+ prompt with kit allowlist 1,002 (18.5%)
202
+ compaction events 0 (never fired)
203
+ ```
204
+
205
+ Four numbers in that report changed how this kit is configured, and two of them
206
+ reversed an earlier decision:
207
+
208
+ **Tool output is 78% of stored context**, and sessions re-read ~101k tokens per
209
+ request to add ~528 new ones. That is why pruning here is deterministic and
210
+ unconditional.
211
+
212
+ **Read pressure is 11.9 whole-file reads per search.** Every production harness
213
+ in the study in `docs/KNOWN-LIMITS.md` searches before reading; this one mostly
214
+ did not. That is a prompt problem, not a config problem, and the fix is a rule
215
+ in `GLOBAL.md` and in the agent files rather than a number.
216
+
217
+ **Truncation and re-read are the same number.** 441 reads were cut by the
218
+ 200-line cap and 423 were re-read with an `offset`. Truncation was not saving
219
+ context, it was buying extra round trips at ~17s median apiece — which is why
220
+ `tool_output` now sits at OpenCode's own 2000 / 51200 default. Only 14 of 2,966
221
+ reads exceed 51,200 bytes, so that ceiling is not what limits context.
222
+
223
+ Your numbers stay on your machine; only the script is in the repo.
224
+
225
+ ## The plugins
226
+
227
+ | module | hook | job |
228
+ |---|---|---|
229
+ | `guard.ts` | `tool.execute.before` | Blocks destructive commands in code. Fail-closed. |
230
+ | `prune.ts` | `experimental.chat.messages.transform` | Replaces old tool output with a one-line stub. |
231
+ | `router.ts` | `config`, `event`, `chat.message` | Moves to the next profile when a route is spent. |
232
+ | `telemetry.ts` | `event`, `tool.execute.after` | Local JSONL, gitignored, never a network call. |
233
+
234
+ `guard.ts` matches against the command a shell would actually run, not the text
235
+ it was handed. It splits on shell separators, honours quotes so that a `;`
236
+ inside a string is an argument rather than a second command, strips `env`,
237
+ `sudo` and `git -C` before matching, and follows `sh -c "..."` into its payload.
238
+ So `cd repo && git push`, `sudo rm -rf /` and `bash -c "git push"` are all
239
+ caught, while `git log --grep push` and `git push origin my-feature-f` are not.
240
+ Writes are scoped to the project directory, with the OS temp directory as the
241
+ one exception GLOBAL.md allows.
242
+
243
+ Pruning keeps user messages, assistant prose, diffs, and the last few turns
244
+ verbatim, and never touches the in-flight turn. Old reasoning is dropped, since
245
+ stale reasoning is worse than none.
246
+
247
+ ## Install
248
+
249
+ One command if you are new here (`init` asks which free profile to run on,
250
+ then runs the two commands below plus `verify`):
251
+
252
+ ```bash
253
+ npx oc-harness init
254
+ ```
255
+
256
+ Two commands, in this order, if you already know which profile you want
257
+ (`npx oc-harness …` from the registry, or `./bin/oc-harness.mjs …` from a
258
+ checkout — they are the same program):
259
+
260
+ ```bash
261
+ oc-harness use space-bunny-free # writes opencode.jsonc
262
+ oc-harness install # writes everything that file points at
263
+ ```
264
+
265
+ `install` symlinks (not copies) the plugin, `agents/`, `skills/` and `GLOBAL.md`
266
+ into `~/.config/opencode/`, so this repo stays the single source of truth and an
267
+ edit here takes effect on the next opencode start.
268
+
269
+ Then restart opencode. Check it took:
270
+
271
+ ```bash
272
+ opencode debug config | grep -A3 '"agent"'
273
+ opencode agent list | grep -E '^(build|plan|reviewer|locate|verify) '
274
+ ```
275
+
276
+ `oc-harness use` writes the active profile id into the generated config, and
277
+ the plugin records it in the project's `.space/active` at startup so pruning
278
+ picks up the right thresholds. To pin a profile explicitly instead:
279
+
280
+ ```bash
281
+ export OPENCODE_HARNESS_PROFILE=space-bunny-free
282
+ ```
283
+
284
+ ### On your phone
285
+
286
+ **Android (Termux)** runs the whole kit locally — same wizard as desktop:
287
+
288
+ ```bash
289
+ pkg install nodejs git
290
+ npx -y opencode-harness-kit init
291
+ ```
292
+
293
+ Not published to npm yet, or no registry access? The checkout path works
294
+ identically:
295
+
296
+ ```bash
297
+ pkg install nodejs git
298
+ git clone https://github.com/crytobot459/space-harness.git
299
+ ./space-harness/bin/oc-harness.mjs init
300
+ ```
301
+
302
+ The kit writes to `$HOME/.config/opencode` like everywhere else, so there is
303
+ nothing phone-specific to learn. Clone the kit repo too if you want the
304
+ pre-commit hook; without a checkout that step is skipped.
305
+
306
+ **iPhone** cannot run Node locally, so the phone is a remote control, not the
307
+ engine. Run opencode on your Mac or a server (inside `tmux` so it survives a
308
+ dropped connection), then SSH in from the phone — Blink Shell is the usual
309
+ client, Tailscale removes the network setup. The kit, the skills and the
310
+ free-model profiles all live server-side; the phone only needs a keyboard.
311
+
312
+ ### Permissions: why `edit` is `allow`
313
+
314
+ The generated config sets `permission.edit: "allow"`, which looks like it
315
+ contradicts the read-only roles. It does not, and the reason is an ordering rule
316
+ worth knowing before you edit these by hand.
317
+
318
+ OpenCode appends the **global** permission rule *after* the agent's own, and
319
+ **the last matching rule wins**. So a global `edit: "ask"` silently overrides
320
+ every agent's `edit: "deny"` — and the read-only roles can edit files after a
321
+ prompt. `allow` is the permissive *implicit default* and emits no rule at all,
322
+ which leaves each agent's `deny` deciding. Verified with `opencode agent list`:
323
+
324
+ ```
325
+ build edit -> allow
326
+ plan edit -> deny
327
+ locate edit -> deny
328
+ reviewer edit -> deny
329
+ verify edit -> deny
330
+ ```
331
+
332
+ Writes outside the project still ask, via `external_directory`.
333
+
334
+ ## Roles
335
+
336
+ | role | mode | job | effort |
337
+ |---|---|---|---|
338
+ | `build` | primary | writes and verifies code | middle |
339
+ | `plan` | primary | turns a request into an executable plan | highest |
340
+ | `reviewer` | subagent | two passes, never edits | highest |
341
+ | `locate` | subagent | finds code, reports `file:line`, never designs | lowest |
342
+ | `verify` | subagent | runs checks, never fixes them | lowest |
343
+
344
+ `locate` is deliberately *not* called `scout`: OpenCode ships a built-in `scout`
345
+ subagent for dependency and external-docs research, and shipping our own file
346
+ under that name shadowed it with `bash: deny` so it could not do the one thing
347
+ the built-in exists for.
348
+
349
+ Each role carries a `steps` cap. It is a loop breaker, not a quality knob: on
350
+ exhaustion OpenCode forces a text-only response, so an agent that has stopped
351
+ making progress reports rather than looping until the context is gone.
352
+
353
+ ## The skill loop
354
+
355
+ The roles above are the *who*. The skills are the *order*, and they load by
356
+ name from `skills/`:
357
+
358
+ | skill | step | hands to |
359
+ |---|---|---|
360
+ | `space-plan` | plan before code; one task at a time | `space-build` |
361
+ | `space-build` | implement and verify exactly one task | `space-review` |
362
+ | `space-review` | two passes; blockers back to build, a clean pass 1 onward | `space-build` or `space-finish` |
363
+ | `space-finish` | final checks, summary, publish decision | a human |
364
+
365
+ The loop's memory is `.space/tasks.md` in the project being worked on, written
366
+ by the plan step from
367
+ [`skills/space-plan/reference/task-template.md`](skills/space-plan/reference/task-template.md).
368
+ Context is pruned; the file is not. Any step that stops reading it works from
369
+ the conversation instead of the requirement.
370
+
371
+ Publishing is never a loop step. `space-finish` prepares the change; a human
372
+ decides it ships.
373
+
374
+ ## Known limits
375
+
376
+ Read [docs/KNOWN-LIMITS.md](docs/KNOWN-LIMITS.md) before relying on failover.
377
+ The short version: no OpenCode plugin hook can change a live session's model,
378
+ so switching happens at the next session, not mid-flight.
379
+
380
+ ## Development
381
+
382
+ ```bash
383
+ npm install
384
+ npm run check # everything: build, typecheck, tests, live install, verify
385
+ ```
386
+
387
+ Or one layer at a time:
388
+
389
+ ```bash
390
+ npm test # model-agnostic assertions, no network, no model calls
391
+ npm run typecheck
392
+ npm run eval # synthetic: pruning, prompt pressure, effort projection
393
+ npm run measure # is this install behaving? narrow reads, context
394
+ npm run attribute # where the context went: fixed overhead vs history
395
+ npm run thresholds # propose the gate floor from what this install actually did
396
+ npm run baseline # your own install, from scratch
397
+ ```
398
+
399
+ `eval/ab.mjs` runs the same tasks with and without the kit, to separate the kit
400
+ from the work. It spawns real agents, so it is not part of `npm run check`, and
401
+ it wants a subject it can hand each run a private copy of:
402
+
403
+ ```bash
404
+ node eval/prepare.mjs --repo ~/work/lablab-harness --ref 8a674f5
405
+ node eval/ab.mjs --target <printed path> --suite eval/tasks.json --reps 2 --sanitize
406
+ node eval/ab.mjs --rescore <saved stream dir> # re-grade without spawning agents
407
+ ```
408
+
409
+ `npm test` and `npm run typecheck` need nothing but the repo, so CI runs those.
410
+ The rest read `~/.local/share/opencode/opencode.db` and `~/.config/opencode`,
411
+ which only exist on a machine that has run OpenCode with the kit installed -
412
+ `npm run check:online` additionally hits the model catalog over the network.
413
+
414
+ Measured results, and the limits they do not cross, are in
415
+ [eval/RESULTS.md](eval/RESULTS.md).
416
+
417
+ `docs/RESEARCH.md` records where the numbers came from and what was tried and
418
+ rejected.
419
+
420
+ ## License
421
+
422
+ MIT
@@ -0,0 +1,66 @@
1
+ ---
2
+ description: Writes code and verifies it. Use when the plan is settled and files need to change.
3
+ mode: primary
4
+ model: opencode/space-bunny-free
5
+ variant: high
6
+ steps: 40
7
+ permission:
8
+ edit: allow
9
+ bash:
10
+ "*": ask
11
+ "git status *": allow
12
+ "git log *": allow
13
+ "git diff *": allow
14
+ "git add*": allow
15
+ "git -C * status*": allow
16
+ "git -C * log*": allow
17
+ "git -C * diff*": allow
18
+ "grep*": allow
19
+ "rg*": allow
20
+ "find*": allow
21
+ "cat*": allow
22
+ "ls*": allow
23
+ "mkdir*": allow
24
+ "chmod +x*": allow
25
+ "python3 -m pytest*": allow
26
+ "pytest*": allow
27
+ "ruff*": allow
28
+ "mypy*": allow
29
+ "npm test*": allow
30
+ "npm run *": allow
31
+ "npx tsc*": allow
32
+ ---
33
+
34
+ You implement one task from a plan. One. Not the whole plan.
35
+
36
+ ## Loop
37
+
38
+ 1. Read the plan task. Read the files it names — the whole file when you are
39
+ about to edit it, and a narrow range when you are only orienting.
40
+ 2. Write the smallest change that satisfies it.
41
+ 3. Run the verify command the plan gave you.
42
+ 4. If it fails, read the actual error, fix the cause, run it again.
43
+ 5. If it passes, report the command and its real output.
44
+
45
+ ## Rules
46
+
47
+ - The plan's verify command is the definition of done. If there is none, run the
48
+ project's default test command and say that is what you used.
49
+ - Never leave a stub, a `TODO`, or a comment promising to finish later. If you
50
+ cannot complete the task, say so before writing a partial one.
51
+ - Never widen the change. A drive-by refactor in the same file is a separate
52
+ task; do not report it as part of this one.
53
+ - Never `git push`, never publish, never open a pull request. Committing is
54
+ allowed but only when the task asked for it.
55
+ - Never fabricate a passing result. A failing test reported honestly is worth
56
+ more than a green one you did not get.
57
+ - Never re-run a command just to get its output back into context. Say what you
58
+ need from it and fetch only that.
59
+
60
+ ## Report
61
+
62
+ Which task you completed, the command you ran, and its verbatim final lines. If
63
+ anything is unfinished, list it explicitly.
64
+
65
+ See also the `space-build` skill for the full plan → build → review → finish
66
+ loop and the shared task-file contract.
@@ -0,0 +1,48 @@
1
+ ---
2
+ description: Finds where something lives and reports file:line evidence. Use before planning or changing anything, to close a gap in what is already known.
3
+ mode: subagent
4
+ model: opencode/space-bunny-free
5
+ variant: low
6
+ steps: 12
7
+ permission:
8
+ edit: deny
9
+ bash: deny
10
+ grep: allow
11
+ read: allow
12
+ glob: allow
13
+ list: allow
14
+ ---
15
+
16
+ You answer one question about the code, with evidence. You do not propose fixes.
17
+
18
+ ## Locate before you read
19
+
20
+ On the measured install, `read` ran 2,966 times against 135 `grep` and 114
21
+ `glob` calls: about twelve whole-file reads for every search. That is the
22
+ single most expensive habit in this setup, so the method below is not optional.
23
+
24
+ 1. `grep` and `glob` first, to get candidate files and line numbers.
25
+ 2. `read` with an `offset`/`limit` for the range you actually need.
26
+ 3. Read a file whole only when you are going to edit it, or when the range
27
+ boundary matters and you need the surrounding structure.
28
+
29
+ Reading an entire file to find out whether a function exists is the mistake this
30
+ agent exists to stop.
31
+
32
+ ## Rules
33
+
34
+ - You cannot run anything. If answering needs a command, say which one and let
35
+ someone else run it.
36
+ - Every claim needs `file:line`. A claim without a location is not a finding.
37
+ - If you did not read it, you did not find it. Do not guess a path.
38
+ - Do not design. If you notice a problem, report it as an observation with its
39
+ location; do not propose the fix.
40
+ - "This does not exist" is a real answer. Say it plainly; it saves the caller
41
+ more time than a plausible guess would.
42
+ - Stop when you can answer. Breadth is not the goal.
43
+
44
+ ## Report
45
+
46
+ Under 200 words. Findings as `file:line — what it does`, ordered by relevance.
47
+ If you ran more than about eight searches without converging, say so and name
48
+ the two places you would look next.