@qvac/harness 0.2.6 → 0.2.7
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/skills/gh-stack/SKILL.md +24 -24
- package/.claude/skills/gh-stack/references/commands.md +2 -2
- package/.claude/skills/js-house-style/SKILL.md +89 -68
- package/.claude/skills/kvcache/SKILL.md +7 -7
- package/.claude/skills/pr-create/SKILL.md +58 -15
- package/.claude/skills/pr-review/SKILL.md +83 -14
- package/CLAUDE.md +3 -0
- package/README.md +26 -4
- package/dist/harness.bundle +5 -4
- package/dist-lib/lib/docx/index.d.ts +5 -0
- package/dist-lib/lib/docx/index.js +49 -0
- package/dist-lib/lib/tools/exec/adapters/python/pyodide.js +2 -0
- package/dist-lib/lib/tools/exec/adapters/python/wheels.js +2 -1
- package/dist-lib/lib/tools/exec/adapters/python/worker/client.js +1 -1
- package/docs/decisions/2026-05-29-kvcache-tool-turns.md +75 -0
- package/docs/decisions/2026-06-02-kvcache-tool-turns-reenabled.md +127 -0
- package/docs/decisions/2026-06-23-android-cpu-llm-defaults.md +126 -0
- package/docs/decisions/2026-07-29-assistant-owned-storage-layout.md +88 -0
- package/docs/decisions/2026-08-04-sidecar-orphan-reaping.md +79 -0
- package/docs/decisions/2026-08-11-pyodide-worker-thread.md +68 -0
- package/docs/decisions/2026-08-17-harness-hook-pipeline.md +84 -0
- package/docs/decisions/2026-08-17-harness-outbound-egress-guard.md +176 -0
- package/docs/decisions/2026-08-20-chat-prompt-prefix-is-stable.md +95 -0
- package/docs/decisions/2026-08-20-kvcache-static-placement.md +109 -0
- package/docs/decisions/2026-08-21-vendored-python-wheels.md +85 -0
- package/docs/decisions/2026-08-26-exec-is-not-gated-by-skills.md +64 -0
- package/docs/decisions/2026-08-27-writable-skills-overlay.md +56 -0
- package/docs/decisions/2026-09-01-skill-operation-manifests.md +53 -0
- package/docs/decisions/2026-09-01-usage-breakdown-is-measured.md +78 -0
- package/docs/decisions/2026-09-03-usage-breakdown-reported-by-the-harness.md +136 -0
- package/docs/decisions/INDEX.md +38 -0
- package/docs/decisions/TEMPLATE.md +32 -0
- package/package.json +6 -2
|
@@ -37,17 +37,17 @@ build chore ci docs style refactor perf test fix feat
|
|
|
37
37
|
It is the line someone reads to decide whether to upgrade, so it claims real
|
|
38
38
|
breakage in something already published.
|
|
39
39
|
|
|
40
|
-
| The change
|
|
41
|
-
|
|
|
42
|
-
| Breaks a consumer on a published version
|
|
43
|
-
| Repairs code that has never shipped (same release cycle)
|
|
40
|
+
| The change | Type |
|
|
41
|
+
| ----------------------------------------------------------- | -------------------------------------------------- |
|
|
42
|
+
| Breaks a consumer on a published version | `fix` |
|
|
43
|
+
| Repairs code that has never shipped (same release cycle) | `chore` |
|
|
44
44
|
| Repairs the build, the bundle, or what lands in the tarball | `build` or `fix` if a published artifact was wrong |
|
|
45
|
-
| Repairs CI, a workflow, an action pin
|
|
46
|
-
| Repairs or adds a test
|
|
47
|
-
| Repairs a lint/type error
|
|
48
|
-
| Pure move or rename, no behaviour change
|
|
49
|
-
| New capability, new export, new flag
|
|
50
|
-
| README, comments, docs
|
|
45
|
+
| Repairs CI, a workflow, an action pin | `ci` |
|
|
46
|
+
| Repairs or adds a test | `test` |
|
|
47
|
+
| Repairs a lint/type error | `chore` |
|
|
48
|
+
| Pure move or rename, no behaviour change | `refactor` |
|
|
49
|
+
| New capability, new export, new flag | `feat` |
|
|
50
|
+
| README, comments, docs | `docs` |
|
|
51
51
|
|
|
52
52
|
When a repair is on unreleased code, check the last release tag: if the bug was
|
|
53
53
|
never in a published version, it is `chore`, not `fix`.
|
|
@@ -61,6 +61,45 @@ Optional, and taken from what the diff actually touches — `lib`, `worker`, `sc
|
|
|
61
61
|
A scope that restates the type (`fix(fix)`) or names the whole repo adds
|
|
62
62
|
nothing; leave it off.
|
|
63
63
|
|
|
64
|
+
## Decision records
|
|
65
|
+
|
|
66
|
+
`docs/decisions/` holds the durable, non-obvious choices — why a boundary is
|
|
67
|
+
where it is, why an approach was rejected. They are reference for a future
|
|
68
|
+
reader, **not rules, and not to be loaded by default**.
|
|
69
|
+
|
|
70
|
+
Add one when this PR settles something a later reader would otherwise have to
|
|
71
|
+
reverse-engineer from the diff: a runtime or storage boundary, a wire-format or
|
|
72
|
+
schema choice, a build or publish constraint, a rejected alternative that will
|
|
73
|
+
look obvious later. Do not add one for a bug fix, a rename, or anything the code
|
|
74
|
+
already says plainly.
|
|
75
|
+
|
|
76
|
+
Copy `docs/decisions/TEMPLATE.md`, give it a `status`, list it once in
|
|
77
|
+
`INDEX.md`, and name it in the PR's Decisions section. `node
|
|
78
|
+
scripts/docs-audit.cjs` checks all of that, and CI runs it.
|
|
79
|
+
|
|
80
|
+
An **active** record may cite only paths that exist here; a path in another
|
|
81
|
+
repository is written `@qvac/harness → lib/x.ts` so the audit treats it as
|
|
82
|
+
context rather than a local file. A superseded record is exempt — it describes
|
|
83
|
+
how things used to be.
|
|
84
|
+
|
|
85
|
+
### One PR, one type
|
|
86
|
+
|
|
87
|
+
The commits carry conventional-commit types, so the mix of types _is_ the scope
|
|
88
|
+
statement. `feat:`, `fix:` and `chore:` on one branch is not a well-rounded
|
|
89
|
+
change, it is three changes sharing a branch, and a reviewer has to hold all
|
|
90
|
+
three while judging any one of them.
|
|
91
|
+
|
|
92
|
+
List them before writing the body:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git log --format='%s' main..HEAD | grep -oE '^[a-z]+' | sort -u
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- **One type** is the PR's type.
|
|
99
|
+
- **A dominant type plus its own tests or docs** (`feat` + `test`, `fix` +
|
|
100
|
+
`docs`) is fine; the dominant one wins.
|
|
101
|
+
- **Unrelated types** means split the PR, or stack it.
|
|
102
|
+
|
|
64
103
|
## Small PRs, stacked
|
|
65
104
|
|
|
66
105
|
A PR is read by a human, so it has to fit in one head. Default to one concern.
|
|
@@ -71,7 +110,7 @@ stack them, so each step is reviewable alone and lands in order.
|
|
|
71
110
|
- **Refactor commits never live inside a non-refactor branch.** A `feat/` branch
|
|
72
111
|
that also reshuffles unrelated code is two PRs. Behaviour changes and pure
|
|
73
112
|
moves are reviewed differently, and mixing them hides both.
|
|
74
|
-
- A pure rename or move lands
|
|
113
|
+
- A pure rename or move lands _before_ the change that depends on it, as its own
|
|
75
114
|
commit or its own PR in the stack.
|
|
76
115
|
|
|
77
116
|
Branch names must never contain `codex`, `cursor`, or `claude` (case
|
|
@@ -79,8 +118,10 @@ insensitive). Use a neutral name before committing or pushing.
|
|
|
79
118
|
|
|
80
119
|
## Body
|
|
81
120
|
|
|
82
|
-
|
|
83
|
-
|
|
121
|
+
`.github/pull_request_template.md` pre-fills the headings. Keep its shape, fill
|
|
122
|
+
what applies, and delete the sections that would be empty — an absent section
|
|
123
|
+
says more than one saying "n/a". The template's own order is Why, What, Testing,
|
|
124
|
+
Decisions; the expanded form below is what each should contain.
|
|
84
125
|
|
|
85
126
|
```markdown
|
|
86
127
|
## What
|
|
@@ -111,8 +152,10 @@ this is the only warning they get.
|
|
|
111
152
|
|
|
112
153
|
1. Check the branch is not `main` and the name is neutral.
|
|
113
154
|
2. `git log --oneline main..HEAD` — every commit is a conventional commit, and
|
|
114
|
-
each one is a change you would defend on its own.
|
|
115
|
-
|
|
155
|
+
each one is a change you would defend on its own. A trail of `wip`,
|
|
156
|
+
`fixup` or `address review` commits is not history; reshape it before
|
|
157
|
+
opening.
|
|
158
|
+
3. `bun run lint` and ``bun run test` (node, bare and addon lanes)` pass locally. CI runs the same lanes; a
|
|
116
159
|
red PR wastes a reviewer's round trip.
|
|
117
160
|
4. Rebase on `main` rather than merging it in. A merge commit in the branch
|
|
118
161
|
makes the diff unreadable.
|
|
@@ -15,6 +15,26 @@ Reviews changes in `@qvac/harness`. Two modes.
|
|
|
15
15
|
- **Local mode** (`local`, or "review my changes") — the overview in chat only.
|
|
16
16
|
Posts nothing, anywhere.
|
|
17
17
|
|
|
18
|
+
## Reviewing is read-only
|
|
19
|
+
|
|
20
|
+
This skill never writes to the working tree. Against the user's repo these are
|
|
21
|
+
forbidden, whatever the reason:
|
|
22
|
+
|
|
23
|
+
- `git switch`, `git checkout`, `git reset`, `git restore`, `git clean`
|
|
24
|
+
- `git stash`, in any form
|
|
25
|
+
- `git pull`, `git merge`, `git rebase`, `git cherry-pick`
|
|
26
|
+
- `gh pr checkout`
|
|
27
|
+
- any edit to a file
|
|
28
|
+
|
|
29
|
+
Local mode reads the diff with `git diff`, `git status` and `git ls-files`, and
|
|
30
|
+
nothing else. If the tree is dirty in a way that makes the diff hard to read, say
|
|
31
|
+
so and let the user decide; never tidy it yourself. A review that loses
|
|
32
|
+
uncommitted work is worse than no review.
|
|
33
|
+
|
|
34
|
+
PR mode needs no checkout at all: `gh pr diff` gives the patch, and
|
|
35
|
+
`gh api repos/{owner}/{repo}/contents/{path}?ref={sha}` gives any file at the PR
|
|
36
|
+
head.
|
|
37
|
+
|
|
18
38
|
## Gather
|
|
19
39
|
|
|
20
40
|
PR mode:
|
|
@@ -48,13 +68,13 @@ single `Lint & Tests` job. `publish.yml` runs on release, not on PRs.
|
|
|
48
68
|
Its steps are each a separate way to fail, and the last three catch what a
|
|
49
69
|
local `bun run test` does not:
|
|
50
70
|
|
|
51
|
-
| Step
|
|
52
|
-
|
|
|
53
|
-
| Lint
|
|
54
|
-
| Schema is regenerated
|
|
55
|
-
| Tests
|
|
56
|
-
| Library surface compiles | `bun run build:lib`
|
|
57
|
-
| Sidecar bundle builds
|
|
71
|
+
| Step | Command | Fails when |
|
|
72
|
+
| ------------------------ | ---------------------- | --------------------------------------------------------------------------------------------- |
|
|
73
|
+
| Lint | `bun run lint` | prettier, lunte or `tsc --noEmit` |
|
|
74
|
+
| Schema is regenerated | `bun run build:schema` | `spec/` is dirty after codegen — someone hand-edited it, or forgot to commit the regeneration |
|
|
75
|
+
| Tests | `bun run test` | the node, bare and addon lanes |
|
|
76
|
+
| Library surface compiles | `bun run build:lib` | the compiled export surface breaks |
|
|
77
|
+
| Sidecar bundle builds | `bun run build:bundle` | the stowed bundle no longer assembles — a new bare import, or a missing addon external |
|
|
58
78
|
|
|
59
79
|
A PR that touches `schema/` and leaves `spec/` stale is the most common red
|
|
60
80
|
here, and it looks nothing like a test failure.
|
|
@@ -105,6 +125,32 @@ avoid `codex` / `cursor` / `claude`?
|
|
|
105
125
|
**6. Scope.** Does the PR do one thing? A behaviour change mixed with an
|
|
106
126
|
unrelated rename is two PRs — say so, and say which commit to split out.
|
|
107
127
|
|
|
128
|
+
**7. Decision records.** Does the change contradict something in
|
|
129
|
+
`docs/decisions/`? If it does, the record is updated or superseded in the same
|
|
130
|
+
PR, not left to rot. Does it settle something non-obvious with no record at all?
|
|
131
|
+
Say which, and what the record would have to state.
|
|
132
|
+
|
|
133
|
+
### Do not over-engineer the review
|
|
134
|
+
|
|
135
|
+
The most damaging thing a review can do is talk a good PR into a worse one. AI
|
|
136
|
+
review skews defensive: a guard here, an abstraction there, a layer to absorb a
|
|
137
|
+
hypothetical, each one permanent debt bolted to a problem that never happened.
|
|
138
|
+
That runs directly against the house style, which does not program defensively.
|
|
139
|
+
|
|
140
|
+
It compounds. Successive reviews each add a layer against a different
|
|
141
|
+
speculative case, one review's fix undoes another's, and the code ends up in a
|
|
142
|
+
corner nobody chose.
|
|
143
|
+
|
|
144
|
+
- **Only raise what is wrong now**, or has a concrete path to being wrong.
|
|
145
|
+
"Someone could later..." is not a finding.
|
|
146
|
+
- **Never propose a guard, wrapper, fallback or abstraction** whose only job is
|
|
147
|
+
to make a hypothetical safe. Let caller bugs crash; that is the contract.
|
|
148
|
+
- **Prefer the fix that deletes code.** If your suggestion makes the diff
|
|
149
|
+
bigger, be sure it earns it.
|
|
150
|
+
- **Simplification is a valid finding; speculative hardening is not.**
|
|
151
|
+
- When you cannot tell whether something is real, ask instead of requesting a
|
|
152
|
+
change, and be willing to land zero findings.
|
|
153
|
+
|
|
108
154
|
## Write the findings
|
|
109
155
|
|
|
110
156
|
Each finding: the file and line, what breaks, and the concrete scenario that
|
|
@@ -112,18 +158,41 @@ breaks it. No finding without a failure mode you can state.
|
|
|
112
158
|
|
|
113
159
|
Drop anything you cannot defend as changing the code, the reviewer's decision,
|
|
114
160
|
or a consumer's experience. Style opinions the house style does not back are
|
|
115
|
-
noise. Say so plainly when the diff is clean
|
|
116
|
-
complete review.
|
|
161
|
+
noise. Say so plainly when the diff is clean: "no `[P1]` or `[P2]`
|
|
162
|
+
findings" is a complete review.
|
|
163
|
+
|
|
164
|
+
Lead with the findings, ordered by severity.
|
|
165
|
+
|
|
166
|
+
### Severity tags
|
|
167
|
+
|
|
168
|
+
Tag every finding `[P1]`, `[P2]` or `[P3]`. Use the tag, not a word, so two
|
|
169
|
+
reviews of the same repo rank things the same way.
|
|
170
|
+
|
|
171
|
+
- `[P1]` — almost-certain bug, data corruption, security issue, CI breaker, or a
|
|
172
|
+
break of behaviour a consumer relies on. In the overview, and **proposed inline
|
|
173
|
+
by default**.
|
|
174
|
+
- `[P2]` — likely bug, non-obvious caveat, contract or API mismatch, subtle
|
|
175
|
+
behaviour change, missing test on a risky path. In the overview, and **proposed
|
|
176
|
+
inline by default**.
|
|
177
|
+
- `[P3]` — minor: a stale comment or doc, an ergonomic improvement, an optional
|
|
178
|
+
cleanup. In the overview when material, and **not proposed inline** unless the
|
|
179
|
+
user asks for them.
|
|
180
|
+
|
|
181
|
+
**Never silently put a `[P3]` in the inline payload.** A review that posts ten
|
|
182
|
+
nits inline teaches the author to skim the next one.
|
|
117
183
|
|
|
118
|
-
|
|
184
|
+
**Severity is what the code does today, not what it might do.** A finding whose
|
|
185
|
+
only support is a scenario nobody has hit is not a `[P2]`: either find the path
|
|
186
|
+
that reaches it, or drop it. Zero findings is a legitimate result.
|
|
119
187
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
- **Question** — you could not tell from the diff, and the author can.
|
|
188
|
+
If the user says this is a re-review, say explicitly which earlier concerns are
|
|
189
|
+
resolved and which still stand.
|
|
123
190
|
|
|
124
191
|
## Posting (PR mode only)
|
|
125
192
|
|
|
126
|
-
1. Print every proposed comment in chat first: file, line, body.
|
|
193
|
+
1. Print every proposed comment in chat first: file, line, severity, body.
|
|
194
|
+
The default set is the `[P1]` and `[P2]` findings; name any `[P3]` you are
|
|
195
|
+
holding back so the user can pull it in.
|
|
127
196
|
2. Ask the user to confirm the exact set. Wait for a clear yes.
|
|
128
197
|
3. Create the review as **PENDING**, with no event:
|
|
129
198
|
|
package/CLAUDE.md
CHANGED
|
@@ -31,6 +31,9 @@ Runs on both Bare and Node. Anything that only works on one is a bug.
|
|
|
31
31
|
never more. Most code needs none — do not narrate it.
|
|
32
32
|
- **Commits read as if a human wrote them.** No `Co-Authored-By` trailer and no
|
|
33
33
|
AI or agent attribution, in a commit message or a PR.
|
|
34
|
+
- **Durable decisions are in `docs/decisions/`.** Read `INDEX.md` when touching an
|
|
35
|
+
area it lists, and open a record only on a path or keyword match — they are
|
|
36
|
+
reference, not rules. Add one when a change makes a non-obvious lasting choice.
|
|
34
37
|
- **Branch from `main`, and open the PR against `main`.** The one exception is a
|
|
35
38
|
stacked PR, which branches from the PR below it and targets that branch.
|
|
36
39
|
- **Branch names never contain `codex`, `cursor` or `claude`**, in any case.
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ spawns and talks to over hrpc — crash isolation for free, death is the exit
|
|
|
10
10
|
itself. See [bare-supervisor](https://github.com/tetherto/bare-supervisor) for
|
|
11
11
|
the supervision contract.
|
|
12
12
|
|
|
13
|
-
## The
|
|
13
|
+
## The published package
|
|
14
14
|
|
|
15
15
|
The published package ships the prebuilt engine and its runtime content, not
|
|
16
16
|
the library source:
|
|
@@ -28,9 +28,9 @@ The `@qvac` inference addons and `pyodide` resolve from the host's real
|
|
|
28
28
|
installs those alongside.
|
|
29
29
|
|
|
30
30
|
The host-side library surface — `spawnHarness`/`harnessChild`, the transport,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
model catalogs, skill helpers and DOCX extractor — ships as compiled JavaScript
|
|
32
|
+
and declarations in `dist-lib/`. The package exports resolve to that surface;
|
|
33
|
+
the TypeScript source stays in the repository.
|
|
34
34
|
|
|
35
35
|
## Spawning
|
|
36
36
|
|
|
@@ -48,6 +48,28 @@ dir, ...) are the ones `worker/harness-sidecar.mjs` documents in this repo. The
|
|
|
48
48
|
in-house hosts don't call this directly — they use the repo's library surface
|
|
49
49
|
(`harnessChild` under bare-supervisor), which owns that argv contract.
|
|
50
50
|
|
|
51
|
+
## DOCX extraction
|
|
52
|
+
|
|
53
|
+
Hosts can supply the bundled Python extractor to their document pipeline:
|
|
54
|
+
|
|
55
|
+
Set `QVAC_PYODIDE_CACHE_DIR` to a writable directory before calling the API,
|
|
56
|
+
including from source and compiled-package consumers. The worker seeds this
|
|
57
|
+
cache from shipped wheels; without it, Pyodide can try downloading packages.
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
import { extractDocxText, closeDocxWorker } from '@qvac/harness/docx'
|
|
61
|
+
|
|
62
|
+
const text = await extractDocxText(bytes, 'notes.docx', { signal })
|
|
63
|
+
// At host shutdown, after outstanding extractions have settled:
|
|
64
|
+
await closeDocxWorker()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The extractor preserves paragraph and table order, accepts up to 20 MiB, and
|
|
68
|
+
requires the shipped Python wheels. With the cache configured, extraction uses
|
|
69
|
+
those wheels offline. Bundled hosts also set `QVAC_PYODIDE_WORKER_ENTRY` and
|
|
70
|
+
`QVAC_PYTHON_WHEELS_DIR` to their staged worker and wheels paths.
|
|
71
|
+
Source checkouts prepare wheels with `bun run vendor:wheels`.
|
|
72
|
+
|
|
51
73
|
## Development
|
|
52
74
|
|
|
53
75
|
```
|