@jmtrin/opencode-kevin 0.9.0 → 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/README.md +558 -823
- package/dist/migrations/011_v10_proven.sql +69 -0
- package/dist/plugin/Archiver.js +0 -1
- package/dist/plugin/ArtifactWriter.d.ts +25 -10
- package/dist/plugin/ArtifactWriter.js +43 -25
- package/dist/plugin/CausalChain.js +0 -1
- package/dist/plugin/ConflictDetector.js +0 -1
- package/dist/plugin/ContextInjector.js +0 -1
- package/dist/plugin/ConventionMiner.js +0 -1
- package/dist/plugin/Curator.js +0 -1
- package/dist/plugin/Feedback.js +0 -1
- package/dist/plugin/HookLiveness.d.ts +6 -0
- package/dist/plugin/HookLiveness.js +15 -1
- package/dist/plugin/InjectionLedger.js +0 -1
- package/dist/plugin/LessonFixer.js +0 -1
- package/dist/plugin/Materializer.js +0 -1
- package/dist/plugin/MemoryService.js +0 -1
- package/dist/plugin/Migrate.d.ts +1 -1
- package/dist/plugin/Migrate.js +25 -3
- package/dist/plugin/PatternMiner.js +0 -1
- package/dist/plugin/QualityGate.js +0 -1
- package/dist/plugin/Reflector.js +0 -1
- package/dist/plugin/RepoIdentity.js +0 -1
- package/dist/plugin/RepoTruth.js +0 -1
- package/dist/plugin/Retrospective.js +7 -1
- package/dist/plugin/SharedLayer.js +0 -1
- package/dist/plugin/Store.js +0 -1
- package/dist/plugin/ToolCallObserver.js +0 -1
- package/dist/plugin/capabilities.js +0 -1
- package/dist/plugin/confidence.js +0 -1
- package/dist/plugin/contract.d.ts +46 -0
- package/dist/plugin/contract.js +368 -0
- package/dist/plugin/diff.js +0 -1
- package/dist/plugin/escape.d.ts +39 -0
- package/dist/plugin/escape.js +60 -0
- package/dist/plugin/fingerprint.js +0 -1
- package/dist/plugin/host.js +0 -1
- package/dist/plugin/index.d.ts +2 -2
- package/dist/plugin/index.js +425 -227
- package/dist/plugin/inferability.js +0 -1
- package/dist/plugin/kevin_approve.js +0 -1
- package/dist/plugin/kevin_audit.d.ts +31 -0
- package/dist/plugin/kevin_audit.js +60 -1
- package/dist/plugin/kevin_bench.d.ts +10 -0
- package/dist/plugin/kevin_bench.js +82 -0
- package/dist/plugin/kevin_conflicts.js +0 -1
- package/dist/plugin/kevin_contract.d.ts +8 -0
- package/dist/plugin/kevin_contract.js +59 -0
- package/dist/plugin/kevin_doctor.d.ts +5 -0
- package/dist/plugin/kevin_doctor.js +30 -2
- package/dist/plugin/kevin_facts.js +0 -1
- package/dist/plugin/kevin_native.js +0 -1
- package/dist/plugin/kevin_propose.js +0 -1
- package/dist/plugin/kevin_publish.js +0 -1
- package/dist/plugin/kevin_why.js +0 -1
- package/dist/plugin/memory-format.js +0 -1
- package/dist/plugin/metrics.js +0 -1
- package/dist/plugin/native.js +0 -1
- package/dist/plugin/okf-export.js +0 -1
- package/dist/plugin/okf-import.js +0 -1
- package/dist/plugin/okf.js +0 -1
- package/dist/plugin/perf.d.ts +35 -0
- package/dist/plugin/perf.js +174 -0
- package/dist/plugin/query-tokenizer.js +0 -1
- package/dist/plugin/redact.js +0 -1
- package/dist/plugin/replay-types.js +0 -1
- package/dist/plugin/replay.js +0 -1
- package/dist/plugin/sqlite-adapter.js +0 -1
- package/dist/plugin/uuid.js +0 -1
- package/package.json +21 -6
- package/dist/plugin/Archiver.js.map +0 -1
- package/dist/plugin/ArtifactWriter.js.map +0 -1
- package/dist/plugin/CausalChain.js.map +0 -1
- package/dist/plugin/ConflictDetector.js.map +0 -1
- package/dist/plugin/ContextInjector.js.map +0 -1
- package/dist/plugin/ConventionMiner.js.map +0 -1
- package/dist/plugin/Curator.js.map +0 -1
- package/dist/plugin/Feedback.js.map +0 -1
- package/dist/plugin/HookLiveness.js.map +0 -1
- package/dist/plugin/InjectionLedger.js.map +0 -1
- package/dist/plugin/LessonFixer.js.map +0 -1
- package/dist/plugin/Materializer.js.map +0 -1
- package/dist/plugin/MemoryService.js.map +0 -1
- package/dist/plugin/Migrate.js.map +0 -1
- package/dist/plugin/PatternMiner.js.map +0 -1
- package/dist/plugin/QualityGate.js.map +0 -1
- package/dist/plugin/Reflector.js.map +0 -1
- package/dist/plugin/RepoIdentity.js.map +0 -1
- package/dist/plugin/RepoTruth.js.map +0 -1
- package/dist/plugin/Retrospective.js.map +0 -1
- package/dist/plugin/SharedLayer.js.map +0 -1
- package/dist/plugin/Store.js.map +0 -1
- package/dist/plugin/ToolCallObserver.js.map +0 -1
- package/dist/plugin/capabilities.js.map +0 -1
- package/dist/plugin/confidence.js.map +0 -1
- package/dist/plugin/diff.js.map +0 -1
- package/dist/plugin/fingerprint.js.map +0 -1
- package/dist/plugin/host.js.map +0 -1
- package/dist/plugin/index.js.map +0 -1
- package/dist/plugin/inferability.js.map +0 -1
- package/dist/plugin/kevin_approve.js.map +0 -1
- package/dist/plugin/kevin_audit.js.map +0 -1
- package/dist/plugin/kevin_conflicts.js.map +0 -1
- package/dist/plugin/kevin_doctor.js.map +0 -1
- package/dist/plugin/kevin_facts.js.map +0 -1
- package/dist/plugin/kevin_native.js.map +0 -1
- package/dist/plugin/kevin_propose.js.map +0 -1
- package/dist/plugin/kevin_publish.js.map +0 -1
- package/dist/plugin/kevin_why.js.map +0 -1
- package/dist/plugin/memory-format.js.map +0 -1
- package/dist/plugin/metrics.js.map +0 -1
- package/dist/plugin/native.js.map +0 -1
- package/dist/plugin/okf-export.js.map +0 -1
- package/dist/plugin/okf-import.js.map +0 -1
- package/dist/plugin/okf.js.map +0 -1
- package/dist/plugin/query-tokenizer.js.map +0 -1
- package/dist/plugin/redact.js.map +0 -1
- package/dist/plugin/replay-types.js.map +0 -1
- package/dist/plugin/replay.js.map +0 -1
- package/dist/plugin/sqlite-adapter.js.map +0 -1
- package/dist/plugin/uuid.js.map +0 -1
- package/migrations/001_initial.sql +0 -92
- package/migrations/002_indexes.sql +0 -14
- package/migrations/003_v02_signal.sql +0 -58
- package/migrations/004_v03_knowledge.sql +0 -138
- package/migrations/005_v04_signal.sql +0 -57
- package/migrations/006_v05_glassbox.sql +0 -118
- package/migrations/007_v06_pull.sql +0 -145
- package/migrations/008_v07_truth.sql +0 -124
- package/migrations/009_v08_team.sql +0 -100
- package/migrations/010_v09_native.sql +0 -78
package/README.md
CHANGED
|
@@ -1,824 +1,559 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
```
|
|
294
|
-
kevin_trace({ query: "tsc error" })
|
|
295
|
-
// → { "query": "tsc error", "tag": "context", "cap": 400, "would_inject": true,
|
|
296
|
-
// "total_tokens": 82,
|
|
297
|
-
// "admitted": [ { "id": "...", "type": "error", "decision": "admitted", "tokens": 62 } ],
|
|
298
|
-
// "blocked": [ { "id": "...", "type": "error", "decision": "blocked",
|
|
299
|
-
// "reason": "confidence", "tokens": 20 } ] }
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
### `kevin_audit`
|
|
303
|
-
|
|
304
|
-
Read-only report of the whole system state: memories by `status`/`origin`/`type`, injection outcomes with `precision_rate`/`coverage_rate`, the six `blocked` counters, feedback by verdict, tokens injected, the push-vs-pull `channels` comparison and the `curation` scoreboard. `verbose: true` adds the settings block. No writes, no LLM; on pre-007 databases it omits the v0.6 blocks and reports `"partial": true`.
|
|
305
|
-
|
|
306
|
-
```
|
|
307
|
-
kevin_audit({})
|
|
308
|
-
// → { "memories": { "total": 42, "by_status": { "active": 37, "stale": 1, "archived": 4 },
|
|
309
|
-
// "by_origin": { "reflector": 12, "agent": 30 }, "by_type": { "error": 20, ... },
|
|
310
|
-
// "ignored": 1, "with_feedback": 3 },
|
|
311
|
-
// "injections": { "total": 14, "effective": 2, "ineffective": 3, "inconclusive": 9,
|
|
312
|
-
// "unmeasured": 0, "precision_rate": 0.40, "coverage_rate": 0.36 },
|
|
313
|
-
// "blocked": { "seen": 1, "weak": 0, "recurrence": 2, "stale": 0,
|
|
314
|
-
// "ignored": 1, "confidence": 2 },
|
|
315
|
-
// "feedback": { "positive": 2, "negative": 1, "by_verdict": { "useful": 2, "wrong": 1 } },
|
|
316
|
-
// "tokens": { "pre_prompt": 51, "compacting": 0 }, "partial": false,
|
|
317
|
-
// "channels": { "push": { "tokens_pre_prompt": 51, "injections_total": 14,
|
|
318
|
-
// "precision_rate": 0.40, "coverage_rate": 0.36,
|
|
319
|
-
// "budget_tokens": 400 },
|
|
320
|
-
// "pull": { "proposals_created": 6, "proposals_approved": 1,
|
|
321
|
-
// "proposals_rejected": 2, "artifact_writes_total": 2,
|
|
322
|
-
// "artifact_writes_noop": 1, "references_registered": 0,
|
|
323
|
-
// "skills_registered": 0,
|
|
324
|
-
// "skill_emission": "off", "reference_emission": "off" } },
|
|
325
|
-
// "curation": { "eligible": 5, "curated": 1, "inferable": 3, "non_inferable": 2,
|
|
326
|
-
// "unknown": 1, "proposals_by_status": { "pending": 2, "applied": 1, ... } } }
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
### `kevin_propose`
|
|
330
|
-
|
|
331
|
-
Creates curation proposals as `pending` rows with unified diffs — **a strict dry run**. Reads the eligible memories (`inferable != 1`), renders what would go into the artifact, and returns the minimal diff. No disk write, no `curated` marks, no side effects. Only `kevin_approve` may write.
|
|
332
|
-
|
|
333
|
-
```
|
|
334
|
-
kevin_propose({ kind: "agents_md" }) // kind: "agents_md" | "skill" | "reference"
|
|
335
|
-
// → { "proposals": [ { "id": "...", "kind": "agents_md", "targetPath": "AGENTS.md",
|
|
336
|
-
// "memoryIds": ["mem-1"], "status": "pending",
|
|
337
|
-
// "createdAt": "2026-08-14 10:00:00",
|
|
338
|
-
// "diff": "--- a/AGENTS.md\n+++ b/AGENTS.md\n@@ ..." } ] }
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
### `kevin_approve`
|
|
342
|
-
|
|
343
|
-
The **only** code path that writes a file. `approve` applies the proposal's diff atomically (temp file + rename, CRLF/BOM preserved), records an `artifact_writes` audit row, marks the proposal `applied` and its memories `curated`. `reject` records the human decision and touches nothing. Refusals and noops are audited, never silent.
|
|
344
|
-
|
|
345
|
-
```
|
|
346
|
-
kevin_approve({ proposal_id: "...", decision: "approve" }) // or "reject"
|
|
347
|
-
// → { "proposalId": "...", "status": "applied", "outcome": "written", "curated": 1 }
|
|
348
|
-
// ("outcome": "noop" when the artifact already matches, "refused" when the
|
|
349
|
-
// marker block is malformed; a rejected proposal returns
|
|
350
|
-
// { "proposalId": "...", "status": "rejected" })
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
### `kevin_publish`
|
|
354
|
-
|
|
355
|
-
Regenerates the pull-channel bundles under `~/.opencode-kevin/` — `skills/project-knowledge.md` and `refs/<topic>.md` — reporting per-bundle outcome and the emission state (`on` / `off` / `unavailable`). Registration with the host happens at plugin startup; this tool only materializes and reports.
|
|
356
|
-
|
|
357
|
-
### `kevin_project`
|
|
358
|
-
|
|
359
|
-
Repository identity (v0.8.0). `action: "show"` reports the resolved `repoId`, `identity_source`, `projectId`, the memory counts under each scope and `rekey_available`; `action: "init"` writes `.kevin/project.json` pinning the derived id (refused if it already exists); `action: "rekey"` moves the whole corpus to the resolved `repo_id` in one transaction — without `confirm: true` it is a dry run that mutates nothing, and a monorepo collision is rejected unless `force: true`.
|
|
360
|
-
|
|
361
|
-
A **confirmed** rekey updates the running session live — the identity, the memory service and the shared-layer bridge all move to the new `repo_id` immediately, so `kevin_status`, `kevin_audit` and `kevin_share` keep working without a restart, and the OKF file's `#repo` header is repaired so the shared channel keeps working too.
|
|
362
|
-
|
|
363
|
-
```
|
|
364
|
-
kevin_project({ action: "show" })
|
|
365
|
-
// → { "repoId": "2114ad162af50a25", "source": "remote", "evidence": "origin",
|
|
366
|
-
// "projectId": "8f3c2a1b...", "projectScoped": 41, "repoScoped": 0,
|
|
367
|
-
// "rekeyAvailable": true }
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
### `kevin_share`
|
|
371
|
-
|
|
372
|
-
Promotes curated memories into the shared layer: plans an export to the OKF file and (with `confirm: true`) writes it through the single write funnel. **A strict dry run by default** — with no `confirm` it returns the plan and its diff, writing nothing. With no `memory_ids`, it selects every `layer='local'`, curated memory whose confidence clears the shared floor. Refusals: `not_okf`, `version_ahead`, `repo_mismatch`, `too_many_entries`, `line_too_long`, `below_floor`, `not_curated`, `unknown_entry`, `parse_damaged` — a typo'd or foreign memory id refuses the whole export (`unknown_entry`) instead of silently sharing a subset.
|
|
373
|
-
|
|
374
|
-
```
|
|
375
|
-
kevin_share({ memory_ids: ["0195a3b2-..."], dry_run: false, confirm: true })
|
|
376
|
-
// → { "memory_ids": [...], "entries_added": 1, "outcome": "written",
|
|
377
|
-
// "okf_path": ".kevin/knowledge.okf", "diff": "--- a/...\n+++ b/..." }
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
### `kevin_sync`
|
|
381
|
-
|
|
382
|
-
Ingests the OKF file (asserts → shared-layer projections; tombstones → archived) and returns `{ imported, tombstoned, skipped, reason }`. Idempotent: an unchanged file is a no-op. Also runs automatically at `session.idle` while `shared_layer_enabled = "1"`.
|
|
383
|
-
|
|
384
|
-
```
|
|
385
|
-
kevin_sync({})
|
|
386
|
-
// → { "path": ".kevin/knowledge.okf", "fileHash": "3d2f...", "parsed": 1,
|
|
387
|
-
// "folded": 0, "rejected": 0, "imported": 1, "tombstoned": 0,
|
|
388
|
-
// "skipped": false }
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
### `kevin_doctor`
|
|
392
|
-
|
|
393
|
-
Read-only health check — no writes, no probe re-run, no model call. Returns `host`, `hooks`, `dependencies`, `native`, `verdict` and `reason`; `hooks` is sorted dead first so the failure is the first thing on screen. Output contains no filesystem paths or session ids — paste it into an issue report.
|
|
394
|
-
|
|
395
|
-
```
|
|
396
|
-
kevin_doctor({})
|
|
397
|
-
// → { "host": { "plugin_version": "1.18.18", "flavour": "v1+v2", "shell_available": true,
|
|
398
|
-
// "v2": { "skill": true, "reference": true } },
|
|
399
|
-
// "hooks": [{ "hook": "experimental.chat.system.transform", "state": "dead",
|
|
400
|
-
// "fire_count": 0, "expected_count": 3, "since": "2026-08-20T10:00:00Z" },
|
|
401
|
-
// { "hook": "tool.execute.after", "state": "live", "fire_count": 42, "expected_count": 42 }],
|
|
402
|
-
// "dependencies": { "declared": ["@opencode-ai/plugin"], "zod_copies": 1 },
|
|
403
|
-
// "native": { "enabled": true, "registered": { "skill": true, "reference": true },
|
|
404
|
-
// "verified": { "skill": true, "reference": true } },
|
|
405
|
-
// "verdict": "degraded", "reason": "experimental.chat.system.transform dead since 2026-08-20T10:00:00Z; 1 affected hook(s)", "partial": false }
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
One dead hook is enough for `degraded`; every hook `live` is `healthy`; otherwise `unknown` — `unknown` is never rounded to `healthy` (D9-09). With no sessions yet, `verdict` is `unknown`.
|
|
409
|
-
|
|
410
|
-
### `kevin_native`
|
|
411
|
-
|
|
412
|
-
Controls the additive v2 attachment (D9-01): `show` reports the setting, the frozen probe result and the latest `native_registrations` rows; `enable`/`disable` write `kevin_settings` only and never re-probe — a restart is required for the change to take effect. The value is TEXT `"1"`/`"0"`; `enable` on a host without the v2 subpath succeeds and reports `effective: false` (inert) rather than refusing.
|
|
413
|
-
|
|
414
|
-
```
|
|
415
|
-
kevin_native({ action: "show" })
|
|
416
|
-
// → { "action": "show", "value": "0", "effective": true,
|
|
417
|
-
// "registrations": [{ "surface": "skill", "registered": true, "verified": true, "attached_at": "2026-08-20T10:00:00Z" }] }
|
|
418
|
-
|
|
419
|
-
kevin_native({ action: "enable" })
|
|
420
|
-
// → { "action": "enable", "value": "1", "effective": false,
|
|
421
|
-
// "reason": "v2 subpath absent from the resolved host package — registration would be inert",
|
|
422
|
-
// "note": "the probe is frozen for the process lifetime — restart the host for the change to take effect" }
|
|
423
|
-
```
|
|
424
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ⚡ Kevin
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
╔══════════════════════════════════════════════╗
|
|
7
|
+
║ ║
|
|
8
|
+
║ ██╗ ██╗███████╗██╗ ██╗██╗███╗ ██╗ ║
|
|
9
|
+
║ ██║ ██╔╝██╔════╝██║ ██║██║████╗ ██║ ║
|
|
10
|
+
║ █████╔╝ █████╗ ██║ ██║██║██╔██╗ ██║ ║
|
|
11
|
+
║ ██╔═██╗ ██╔══╝ ╚██╗ ██╔╝██║██║╚██╗██║ ║
|
|
12
|
+
║ ██║ ██╗███████╗ ╚████╔╝ ██║██║ ╚████║ ║
|
|
13
|
+
║ ╚═╝ ╚═╝╚══════╝ ╚═══╝ ╚═╝╚═╝ ╚═══╝ ║
|
|
14
|
+
║ ║
|
|
15
|
+
║ Local-First Memory for OpenCode ║
|
|
16
|
+
║ ║
|
|
17
|
+
╚══════════════════════════════════════════════╝
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Local-first memory for OpenCode — it observes, learns, remembers and proves it.
|
|
21
|
+
|
|
22
|
+
**Kevin watches. Kevin learns. Kevin remembers.**
|
|
23
|
+
|
|
24
|
+
It turns every coding session into durable, confidence-scored knowledge,
|
|
25
|
+
injects exactly what matters back into the model's context, curates the best
|
|
26
|
+
of it into files you control, and shares it across a team through one
|
|
27
|
+
git-friendly file — deterministically, locally, with zero network calls.
|
|
28
|
+
|
|
29
|
+

|
|
30
|
+

|
|
31
|
+

|
|
32
|
+

|
|
33
|
+

|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
> **AI agents are good at solving problems. Kevin makes sure they don't have to solve the same problem twice.**
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 📖 Contents
|
|
43
|
+
|
|
44
|
+
- [Why Kevin](#-why-kevin)
|
|
45
|
+
- [The Kevin loop](#-the-kevin-loop)
|
|
46
|
+
- [Quick start](#-quick-start)
|
|
47
|
+
- [What's new in 1.0.0](#-whats-new-in-100)
|
|
48
|
+
- [How it works](#-how-it-works)
|
|
49
|
+
- [The 25 tools](#-the-25-tools)
|
|
50
|
+
- [The benchmark: proven, not promised](#-the-benchmark-proven-not-promised)
|
|
51
|
+
- [Curation: from session noise to AGENTS.md](#-curation-from-session-noise-to-agentsmd)
|
|
52
|
+
- [Team sharing: one file, zero servers](#-team-sharing-one-file-zero-servers)
|
|
53
|
+
- [The contract](#-the-contract)
|
|
54
|
+
- [Hooks & latency budgets](#-hooks--latency-budgets)
|
|
55
|
+
- [Configuration](#%EF%B8%8F-configuration)
|
|
56
|
+
- [Supported runtimes](#-supported-runtimes)
|
|
57
|
+
- [Design & trust](#-design--trust)
|
|
58
|
+
- [Development](#-development)
|
|
59
|
+
- [License](#-license)
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 🤔 Why Kevin
|
|
64
|
+
|
|
65
|
+
Every coding session produces experience — errors, fixes, decisions,
|
|
66
|
+
conventions, lessons. Without memory, most of it evaporates when the context
|
|
67
|
+
window closes: the next session starts near zero and walks straight into the
|
|
68
|
+
same wall.
|
|
69
|
+
|
|
70
|
+
Kevin closes that loop:
|
|
71
|
+
|
|
72
|
+
| 🔍 Observe | 🧠 Learn | 🎯 Recall | ✍️ Curate | 👥 Share | 📏 Prove |
|
|
73
|
+
|---|---|---|---|---|---|
|
|
74
|
+
| Tool calls, chat messages, session signals | Failures become lessons, causal chains, patterns | Relevant knowledge ranked and injected inside a token budget | The best knowledge becomes human-approved `AGENTS.md` guidance | Curated knowledge travels through one git-friendly file | Latency and retrieval quality are measured, not assumed |
|
|
75
|
+
|
|
76
|
+
**Local first, by design.** Your coding experience belongs to you:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
no cloud service · no telemetry · no network calls · no hidden write path
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Knowledge lives in a local SQLite database, is projected into files you
|
|
83
|
+
control, and is shared — optionally — through a single file you can read,
|
|
84
|
+
diff and review like code.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 🔁 The Kevin loop
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
CODING SESSION
|
|
92
|
+
│
|
|
93
|
+
▼
|
|
94
|
+
🔍 OBSERVE ────── tool calls, chat signals, failures
|
|
95
|
+
│
|
|
96
|
+
▼
|
|
97
|
+
🧠 LEARN ─────── lessons, causal chains, patterns
|
|
98
|
+
│
|
|
99
|
+
▼
|
|
100
|
+
💾 REMEMBER ───── confidence · provenance · recurrence
|
|
101
|
+
│
|
|
102
|
+
▼
|
|
103
|
+
🎯 RECALL ────── rank → gates → token budget
|
|
104
|
+
│
|
|
105
|
+
▼
|
|
106
|
+
MODEL CONTEXT ──── only what matters now
|
|
107
|
+
│
|
|
108
|
+
▼
|
|
109
|
+
✍️ CURATE ─────── propose → HUMAN review → approve
|
|
110
|
+
│
|
|
111
|
+
▼
|
|
112
|
+
AGENTS.md
|
|
113
|
+
│
|
|
114
|
+
▼
|
|
115
|
+
NEXT SESSION ─────────────────▶ 🔁
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Experience compounds instead of evaporating.**
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 🚀 Quick start
|
|
123
|
+
|
|
124
|
+
### 1. Declare the plugin
|
|
125
|
+
|
|
126
|
+
```jsonc
|
|
127
|
+
// opencode.json
|
|
128
|
+
{
|
|
129
|
+
"plugin": ["@jmtrin/opencode-kevin"]
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npm install @jmtrin/opencode-kevin
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 2. Restart OpenCode
|
|
138
|
+
|
|
139
|
+
On first boot Kevin migrates its database to schema version `011` and starts
|
|
140
|
+
observing. Nothing else is required.
|
|
141
|
+
|
|
142
|
+
### 3. Talk to it
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
kevin_status → is everything healthy?
|
|
146
|
+
kevin_why → why did this keep failing, and how was it fixed?
|
|
147
|
+
kevin_query → what does Kevin remember about X?
|
|
148
|
+
kevin_doctor → health report: hooks, deps, perf, verdict
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 4. Where data lives
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
~/.opencode-kevin/
|
|
155
|
+
├── kevin.db ← everything Kevin learns (SQLite, WAL)
|
|
156
|
+
├── skills/ ← generated pull channels
|
|
157
|
+
└── refs/ ← topic reference bundles
|
|
158
|
+
|
|
159
|
+
<repo>/.kevin/
|
|
160
|
+
├── AGENTS.md ← curated knowledge (marker block, human-approved)
|
|
161
|
+
└── knowledge.okf ← optional team-sharing file (opt-in)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 🆕 What's new in 1.0.0
|
|
167
|
+
|
|
168
|
+
> 1.0.0 is the **proven release**: the surface is frozen as data, the cost is
|
|
169
|
+
> measured, the value is benchmarked — reproducibly.
|
|
170
|
+
|
|
171
|
+
- ❄️ **A frozen public contract** — nine clauses (`C-01` … `C-09`) derived from
|
|
172
|
+
live source, digest-stamped, enforced by an append-only golden file.
|
|
173
|
+
Inspect it live with `kevin_contract`.
|
|
174
|
+
- ⏱️ **Latency budgets** — eight instrumented scopes; `npm run bench:check`
|
|
175
|
+
fails if any scope exceeds its p95 budget. `dispose` joins as the seventh
|
|
176
|
+
hook with crash-safe deferred settlement.
|
|
177
|
+
- 📊 **A reproducible benchmark** — committed synthetic corpus, four arms,
|
|
178
|
+
committed result. See [below](#-the-benchmark-proven-not-promised).
|
|
179
|
+
- 🛡️ **An untrusted-input boundary** — everything reaching an artifact or
|
|
180
|
+
prompt is escaped at the single write path; stored text is never trusted.
|
|
181
|
+
- 📦 **A corrected published package** — types-first exports, `dist/` only,
|
|
182
|
+
verified against the packed tarball by `npm run verify:pack`.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## ⚙️ How it works
|
|
187
|
+
|
|
188
|
+
Kevin is an intentionally deterministic pipeline — no LLM in the core loop:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
your coding session
|
|
192
|
+
│
|
|
193
|
+
▼
|
|
194
|
+
┌────────────────────────────────────────────┐
|
|
195
|
+
│ 🔍 OBSERVE │
|
|
196
|
+
│ tool.execute.before/after · chat.message │
|
|
197
|
+
│ Failures auto-detected from exit codes, │
|
|
198
|
+
│ stderr and stdout markers. │
|
|
199
|
+
└──────────────────┬─────────────────────────┘
|
|
200
|
+
▼
|
|
201
|
+
┌────────────────────────────────────────────┐
|
|
202
|
+
│ 🧠 LEARN │
|
|
203
|
+
│ Reflector → lessons │
|
|
204
|
+
│ CausalChain → failure/fix links │
|
|
205
|
+
│ PatternMiner → repeated sequences │
|
|
206
|
+
│ Evidence raises confidence; recurrence │
|
|
207
|
+
│ lowers it and flags staleness. │
|
|
208
|
+
└──────────────────┬─────────────────────────┘
|
|
209
|
+
▼
|
|
210
|
+
┌────────────────────────────────────────────┐
|
|
211
|
+
│ 🎯 INJECT │
|
|
212
|
+
│ QualityGate → BM25 × origin × recency × │
|
|
213
|
+
│ truth penalty → token-budget fit │
|
|
214
|
+
│ Deduped per session, inside <kevin-context>│
|
|
215
|
+
└──────────────────┬─────────────────────────┘
|
|
216
|
+
▼
|
|
217
|
+
┌────────────────────────────────────────────┐
|
|
218
|
+
│ ✍️ CURATE │
|
|
219
|
+
│ propose → HUMAN REVIEW → approve │
|
|
220
|
+
│ Nothing writes without approval. │
|
|
221
|
+
└──────────────────┬─────────────────────────┘
|
|
222
|
+
▼
|
|
223
|
+
┌────────────────────────────────────────────┐
|
|
224
|
+
│ 📏 PROVE │
|
|
225
|
+
│ perf budgets · retrieval benchmark · │
|
|
226
|
+
│ contract digest │
|
|
227
|
+
│ The system measures itself instead of │
|
|
228
|
+
│ merely claiming to work. │
|
|
229
|
+
└────────────────────────────────────────────┘
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 🧰 The 25 tools
|
|
235
|
+
|
|
236
|
+
<details open>
|
|
237
|
+
<summary><b>🧠 Core memory</b></summary>
|
|
238
|
+
|
|
239
|
+
| Tool | What it does |
|
|
240
|
+
|---|---|
|
|
241
|
+
| `kevin_save` | Store a memory: decision, rule, pattern, context or solution |
|
|
242
|
+
| `kevin_query` | Search memories — slim payload; `evidence: true` exposes confidence |
|
|
243
|
+
| `kevin_get` | Fetch one memory in full |
|
|
244
|
+
| `kevin_recall` | Ranked recall with origin-aware scoring |
|
|
245
|
+
| `kevin_status` | Session scoreboard: counts, precision, metrics |
|
|
246
|
+
| `kevin_config` | List/set any of the 31 settings — no SQL required |
|
|
247
|
+
| `kevin_project` | Show, initialize or rekey the repository identity |
|
|
248
|
+
|
|
249
|
+
</details>
|
|
250
|
+
|
|
251
|
+
<details>
|
|
252
|
+
<summary><b>🔎 Understanding & debugging</b></summary>
|
|
253
|
+
|
|
254
|
+
| Tool | What it does |
|
|
255
|
+
|---|---|
|
|
256
|
+
| `kevin_why` | Failure→fix trace for a recurring error, with confidence and evidence |
|
|
257
|
+
| `kevin_trace` | Dry-run: exactly what would be injected for a query, zero side effects |
|
|
258
|
+
| `kevin_feedback` | Rate an injected memory `useful` / `wrong` / `outdated` / `ignore` |
|
|
259
|
+
| `kevin_conflicts` | Surface contradictions between memories and repository truth |
|
|
260
|
+
| `kevin_facts` | Scan the repository for ground-truth facts |
|
|
261
|
+
| `kevin_retrospective` | Per-session markdown retrospective |
|
|
262
|
+
|
|
263
|
+
</details>
|
|
264
|
+
|
|
265
|
+
<details>
|
|
266
|
+
<summary><b>✍️ Curation & publishing</b></summary>
|
|
267
|
+
|
|
268
|
+
| Tool | What it does |
|
|
269
|
+
|---|---|
|
|
270
|
+
| `kevin_propose` | Dry-run curation proposals with unified diffs — writes nothing |
|
|
271
|
+
| `kevin_approve` | The **only** path that writes `AGENTS.md` (or rejects) |
|
|
272
|
+
| `kevin_publish` | Regenerate skill/ref pull bundles under `~/.opencode-kevin/` |
|
|
273
|
+
|
|
274
|
+
</details>
|
|
275
|
+
|
|
276
|
+
<details>
|
|
277
|
+
<summary><b>👥 Team & operations</b></summary>
|
|
278
|
+
|
|
279
|
+
| Tool | What it does |
|
|
280
|
+
|---|---|
|
|
281
|
+
| `kevin_share` | Promote curated memories into `.kevin/knowledge.okf` (approval-gated) |
|
|
282
|
+
| `kevin_sync` | Import the shared file into the local layer |
|
|
283
|
+
| `kevin_export` / `kevin_import` | Markdown/OKF bundles out and in |
|
|
284
|
+
| `kevin_audit` | Whole-system report: memories, injections, channels, team, perf, contract |
|
|
285
|
+
| `kevin_doctor` | Health verdict: `healthy` / `degraded` / `unknown`, with reasons |
|
|
286
|
+
| `kevin_native` | Show/enable/disable native host registration (default off) |
|
|
287
|
+
| `kevin_contract` | **v1.0.0** — inspect the frozen public surface at runtime |
|
|
288
|
+
| `kevin_bench` | **v1.0.0** — report benchmark results; never runs them in-session |
|
|
289
|
+
|
|
290
|
+
</details>
|
|
291
|
+
|
|
425
292
|
---
|
|
426
|
-
|
|
427
|
-
##
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
`
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
```
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
| `pre_prompt_budget_tokens` | `"400"` | Pre-prompt injection cap, clamped to `[0, 4000]`; `0` turns push off |
|
|
694
|
-
| `archive_after_days` | `"30"` | Age at which stale non-pattern memories are retired to `archived` on `session.idle` |
|
|
695
|
-
| `curation_enabled` | `"1"` | Generates curation proposals at `session.idle` |
|
|
696
|
-
| `agents_md_path` | `"AGENTS.md"` | Where the AGENTS.md channel writes (project-relative) |
|
|
697
|
-
| `skill_emission_enabled` | `"0"` | Registers the curated skill with the host at startup (v2 hosts only) |
|
|
698
|
-
| `reference_emission_enabled` | `"0"` | Registers `@kevin/<topic>` references at startup (v2 hosts only) |
|
|
699
|
-
| `injection_confidence_floor` | `"0.6"` | Push gate: memories below this confidence are counted and rejected |
|
|
700
|
-
| `repo_truth_enabled` | `"0"` | Opt-in Project Truth: fact scanning + contradiction detection at `session.idle` |
|
|
701
|
-
| `convention_mining_enabled` | `"0"` | Opt-in deterministic convention mining into `AGENTS.md` |
|
|
702
|
-
| `conflict_detection_enabled` | `"0"` | Opt-in contradiction detection between memories and observed facts |
|
|
703
|
-
| `error_lesson_mode` | `"all"` | Which failures produce lessons: `all` / `rules_only` / `patterns_only` |
|
|
704
|
-
| `shared_layer_enabled` | `"0"` | Master switch for the shared layer. When `"0"`, Kevin never reads or writes the OKF file and `session.idle` performs no filesystem access. Compare with `=== "1"` — a truthiness check would turn the feature on for every installation |
|
|
705
|
-
| `okf_path` | `".kevin/knowledge.okf"` | Project-relative path of the committed OKF file (**string** — always truthy, which is exactly why the layer flag above must not be read as a boolean) |
|
|
706
|
-
| `share_requires_approval` | `"1"` | When `"1"`, `kevin_share` writes only with `confirm: true`; un-curated memories are refused with `not_curated` |
|
|
707
|
-
| `author_identity_mode` | `"hashed"` | Author attribution in exports: `"hashed"` or `"none"` (**string** enum) |
|
|
708
|
-
| `shared_confidence_floor` | `"0.7"` | Gate for `kevin_share` selection and export — a **string**, read with `Number.parseFloat` and clamped to `[0, 1]`. Deliberately stricter than `injection_confidence_floor` (`0.6`): sharing is a commitment, injecting is a suggestion. `parseInt` on this setting would yield `0` and share everything |
|
|
709
|
-
| `hook_liveness_enabled` | `"1"` | Master switch for the liveness instrument. When `"0"`, `HookLiveness.wrap()` returns hooks untouched and no counters are recorded — compare with `=== "1"` |
|
|
710
|
-
| `native_registration_enabled` | `"0"` | Opt-in for the additive v2 attachment (`skill.transform`/`reference.transform` via `define()`). Default `"0"` keeps the release byte-identical to v0.8.0; `kevin_native enable` sets `"1"` (TEXT) but the probe is frozen — restart required (D9-01) |
|
|
711
|
-
| `host_probe_history_enabled` | `"0"` | When `"1"`, one `host_probes` row per construction is appended (version, flavour, v2 flags, notes). Off by default because it is unbounded append-only |
|
|
712
|
-
| `dead_hook_report_threshold` | `"3"` | How many checkpointed sessions without a hook firing before it is `dead`. TEXT holding a number, read with `Number.parseInt(v, 10)`, clamped to `[1, 1000]`, `NaN` → `3` |
|
|
713
|
-
|
|
714
|
-
All 27 settings are TEXT values; booleans and flags compare against `"1"`; the three v0.8 **string-valued** settings are `okf_path`, `author_identity_mode` and `shared_confidence_floor`, and `dead_hook_report_threshold` is a numeric string.
|
|
715
|
-
|
|
716
|
-
---
|
|
717
|
-
|
|
718
|
-
## Development
|
|
719
|
-
|
|
720
|
-
```bash
|
|
721
|
-
git clone https://github.com/jmtrin/opencode-kevin.git
|
|
722
|
-
cd opencode-kevin
|
|
723
|
-
npm install
|
|
724
|
-
npm run typecheck # tsc --noEmit (strict)
|
|
725
|
-
npm run lint # biome check .
|
|
726
|
-
npm test # vitest run (unit + integration + e2e + replay)
|
|
727
|
-
npm run verify # post-install verification (also checks DB migrations)
|
|
728
|
-
npm run replay # replay report over tests/replay/fixtures
|
|
729
|
-
```
|
|
730
|
-
|
|
731
|
-
### Quick diagnostic
|
|
732
|
-
|
|
733
|
-
```bash
|
|
734
|
-
# One read-only command that tells you whether Kevin is healthy:
|
|
735
|
-
# host surface, every hook's state, dependency check, and native registration.
|
|
736
|
-
kevin_doctor({})
|
|
737
|
-
# → { host: { flavour: "v1+v2", v2: { skill: true, reference: true } },
|
|
738
|
-
# hooks: [{ hook: "experimental.chat.system.transform", state: "dead", ... }],
|
|
739
|
-
# verdict: "degraded", reason: "experimental.chat.system.transform dead since ..." }
|
|
740
|
-
|
|
741
|
-
# Native registration is opt-in (default off). Enable, restart, check again:
|
|
742
|
-
kevin_native({ action: "enable" }) # writes native_registration_enabled="1" (TEXT), no re-probe
|
|
743
|
-
kevin_native({ action: "show" }) # → { effective: false, reason: "v2 subpath absent …" } on 1.17.x
|
|
744
|
-
```
|
|
745
|
-
|
|
746
|
-
### Publishing (maintainer)
|
|
747
|
-
|
|
748
|
-
```bash
|
|
749
|
-
npm login # as the jmtrin account that owns the @jmtrin scope
|
|
750
|
-
npm publish --access public
|
|
751
|
-
```
|
|
752
|
-
|
|
753
|
-
`prepublishOnly` runs `npm run build` (tsc + copy migrations) automatically. The `files` field ships only `dist/plugin`, `dist/migrations`, and `migrations`. `dist/` is gitignored and rebuilt on publish.
|
|
754
|
-
|
|
755
|
-
### Structure
|
|
756
|
-
|
|
757
|
-
```
|
|
758
|
-
plugin/
|
|
759
|
-
index.ts # Entry point: KevinPlugin (wires hooks, tools, emissions)
|
|
760
|
-
Store.ts # SQLite wrapper (node:sqlite / bun:sqlite / better-sqlite3 fallback)
|
|
761
|
-
sqlite-adapter.ts # Runtime-agnostic SQLite adapter behind Store
|
|
762
|
-
Migrate.ts # Idempotent migrations + post-apply hooks
|
|
763
|
-
MemoryService.ts # save/query/getRelevant (FTS5 + bm25 + origin-aware rank + supersede)
|
|
764
|
-
ToolCallObserver.ts # onBefore/onAfter + redact + inferErrorType + dedup (opt-in)
|
|
765
|
-
Reflector.ts # Heuristic lessons + per-fingerprint throttle + LLM enrich (opt-in)
|
|
766
|
-
ContextInjector.ts # deriveQuery + pre-prompt/compacting injection + <kevin-suggestion>
|
|
767
|
-
Retrospective.ts # Generates retrospective.md + FP recap + metrics snapshot
|
|
768
|
-
Feedback.ts # kevin_feedback: verdicts, confidence terms, ignored stamp
|
|
769
|
-
Archiver.ts # Retires stale non-pattern memories past archive_after_days
|
|
770
|
-
CausalChain.ts # Links fixes to failures + promotes causal patterns
|
|
771
|
-
QualityGate.ts # Weak-lesson gate (stored, not injected by default)
|
|
772
|
-
InjectionLedger.ts # Injection ledger + settle → precision_rate
|
|
773
|
-
LessonFixer.ts # Deterministic fix_args capture + promotion enrichment
|
|
774
|
-
PatternMiner.ts # Opt-in deterministic 2-gram/3-gram miner
|
|
775
|
-
Curator.ts # Curation candidates + propose/approve lifecycle
|
|
776
|
-
ArtifactWriter.ts # The SINGLE write path (markers, atomic, noop, audit rows)
|
|
777
|
-
Materializer.ts # Pull-channel topic bundles (skills, refs)
|
|
778
|
-
inferability.ts # Deterministic inferable/non-inferable/unknown classifier
|
|
779
|
-
capabilities.ts # v2 domain probe (skills / references)
|
|
780
|
-
diff.ts # Minimal unified diff for proposal review
|
|
781
|
-
replay.ts # Hermetic replay driver over recorded transcripts
|
|
782
|
-
replay-types.ts # Transcript/result types for the replay harness
|
|
783
|
-
kevin_propose.ts # kevin_propose tool (strict dry run)
|
|
784
|
-
kevin_approve.ts # kevin_approve tool (only writer call site)
|
|
785
|
-
kevin_publish.ts # kevin_publish tool (bundle regeneration)
|
|
786
|
-
kevin_audit.ts # Read-only audit + channels/curation blocks
|
|
787
|
-
kevin_why.ts # kevin_why tool: failure→fix traces + related rules
|
|
788
|
-
SharedLayer.ts # v0.8: OKF plan/apply/tombstone + import → shared projections
|
|
789
|
-
RepoIdentity.ts # v0.8: repo_id resolution (declared → remote → path) + rekey
|
|
790
|
-
okf.ts # v0.8: OKF v2 parse/serialize (headers, entry_id, limits)
|
|
791
|
-
okf-export.ts # kevin_export: OKF/markdown export
|
|
792
|
-
okf-import.ts # kevin_import: bundle parser + import
|
|
793
|
-
confidence.ts # Two-sided computeConfidence (evidence + recurrence + feedback)
|
|
794
|
-
query-tokenizer.ts # FTS5 tokenizer for query sanitization
|
|
795
|
-
memory-format.ts # escapeInjectedText, formatMemories, <protect> + id: line wrappers
|
|
796
|
-
redact.ts # redactPaths + stripPrivate
|
|
797
|
-
fingerprint.ts # FNV-1a 64-bit (in-house, no node:crypto)
|
|
798
|
-
metrics.ts # In-memory counters + debounced flush to kevin_metrics
|
|
799
|
-
uuid.ts # UUIDv7
|
|
800
|
-
migrations/
|
|
801
|
-
001_initial.sql # schema: memories, tool_calls, retrospectives
|
|
802
|
-
002_indexes.sql # FTS5 + indexes
|
|
803
|
-
003_v02_signal.sql # fingerprint, origin, metrics, dedup indexes
|
|
804
|
-
004_v03_knowledge.sql # evidence/status/supersede, error_fingerprint
|
|
805
|
-
005_v04_signal.sql # recurrence_count, fix_args, last_injected_at
|
|
806
|
-
006_v05_glassbox.sql # ignored/archived/superseded_by, feedback, metrics
|
|
807
|
-
007_v06_pull.sql # curation_proposals, artifact_writes, curated/inferable
|
|
808
|
-
008_v07_truth.sql # facts + contradictions, conflict_detection settings
|
|
809
|
-
009_v08_team.sql # shared_entries, okf_imports, the five v0.8 settings
|
|
810
|
-
tests/
|
|
811
|
-
unit/ # component tests
|
|
812
|
-
integration/ # tool-level tests through real components
|
|
813
|
-
e2e/ # closed-loop tests through the host hooks
|
|
814
|
-
replay/ # transcript fixtures + replay harness tests
|
|
815
|
-
scripts/
|
|
816
|
-
copy-migrations.mjs # build step: copies *.sql to dist/migrations
|
|
817
|
-
verify-install.ts # npm run verify
|
|
818
|
-
```
|
|
819
|
-
|
|
820
|
-
---
|
|
821
|
-
|
|
822
|
-
## License
|
|
823
|
-
|
|
824
|
-
MIT
|
|
293
|
+
|
|
294
|
+
## 📊 The benchmark: proven, not promised
|
|
295
|
+
|
|
296
|
+
Kevin ships a committed synthetic corpus and a four-arm harness measuring
|
|
297
|
+
whether real retrieval beats trivial baselines at surfacing labelled-relevant
|
|
298
|
+
memories:
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
bench/corpus/
|
|
302
|
+
seed: 1262835273 (xorshift32, byte-for-byte regenerable)
|
|
303
|
+
digest: adecbdf4c7af82e2
|
|
304
|
+
result: bench/results/2026-08-21-adecbdf4c7af82e2.json (k = 5)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
npm run bench # run the harness (also persists one row per arm)
|
|
309
|
+
npm run bench:check # gate: every perf scope within its p95 budget
|
|
310
|
+
npm run verify:pack # gate: seven properties against the packed tarball
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
| Arm | Precision@5 | Recall@5 | MRR |
|
|
314
|
+
|---|---:|---:|---:|
|
|
315
|
+
| `none` (control) | 0.000 | 0.000 | 0.000 |
|
|
316
|
+
| `recent-k` (baseline) | 0.050 | 0.026 | 0.109 |
|
|
317
|
+
| `random-k` (floor) | 0.048 | 0.028 | 0.093 |
|
|
318
|
+
| **`kevin`** | **0.950** | **0.546** | **1.000** |
|
|
319
|
+
|
|
320
|
+
```
|
|
321
|
+
Precision@5 Recall@5 MRR
|
|
322
|
+
0.950 ██████████████████░░ 0.546 ██████████░░░░ 1.000 ████████████████████
|
|
323
|
+
0.050 █░░░░░░░░░░░░░░░░░░░ 0.026 █░░░░░░░░░░░░░ 0.109 ██░░░░░░░░░░░░░░░░░░
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The labelling rule is mechanical and the retrieval numbers are exactly
|
|
327
|
+
reproducible — asserted by running the harness twice in-process.
|
|
328
|
+
|
|
329
|
+
**Honest limits, stated up front.** This benchmark measures retrieval on a
|
|
330
|
+
synthetic corpus built to have a ranked answer; it does **not** prove that real sessions look like this synthetic corpus. It does not prove that a surfaced memory changed what the model did. Retrieval quality is one layer of the agent loop, not the whole of it.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## ✍️ Curation: from session noise to AGENTS.md
|
|
335
|
+
|
|
336
|
+
Knowledge worth keeping becomes a proposal; a human decides; only then is it
|
|
337
|
+
written — once, atomically, inside a marker pair you can edit around:
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
memories ──▶ kevin_propose ──▶ pending proposals (unified diffs, no writes)
|
|
341
|
+
│
|
|
342
|
+
HUMAN REVIEW
|
|
343
|
+
│
|
|
344
|
+
┌── approve ────┴──── reject ──▶ decision recorded
|
|
345
|
+
▼ nothing written
|
|
346
|
+
AGENTS.md updated atomically ◀── the single write path (D6-01)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```markdown
|
|
350
|
+
<!-- kevin:begin — curated by opencode-kevin, safe to edit -->
|
|
351
|
+
- Always run `npm run typecheck` before committing (fixed 3 CI failures)
|
|
352
|
+
<!-- kevin:end -->
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Deliberately conservative: only non-inferable memories are eligible — an
|
|
356
|
+
LLM-recoverable diagnostic is not something a human should have to review into
|
|
357
|
+
a permanent rule. Re-applying an unchanged plan is a counted noop, never a
|
|
358
|
+
write. **Kevin can propose. Humans decide.**
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## 👥 Team sharing: one file, zero servers
|
|
363
|
+
|
|
364
|
+
Opt-in via `shared_layer_enabled='1'`. Curated knowledge exports to one
|
|
365
|
+
`.kevin/knowledge.okf` — header lines plus one JSON entry per line, sorted by a
|
|
366
|
+
deterministic `entry_id`, LF-only, ≤4096 bytes per line — designed so git
|
|
367
|
+
merges are meaningful and conflicts are parseable:
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
DEV A DEV B
|
|
371
|
+
│ share (approval-gated) │ git pull
|
|
372
|
+
▼ ▼
|
|
373
|
+
knowledge.okf ◀═══════ git ══════▶ knowledge.okf
|
|
374
|
+
│ kevin_sync
|
|
375
|
+
▼
|
|
376
|
+
projected into local memories
|
|
377
|
+
(layer='shared', immutable)
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Repository identity resolves **once**, in order:
|
|
381
|
+
`.kevin/project.json` (declared) → git remote hash (never a raw URL) → path.
|
|
382
|
+
Two clones of the same repository are one team; different repositories never
|
|
383
|
+
leak into each other. Sharing requires explicit approval
|
|
384
|
+
(`share_requires_approval='1'`), author identity is hashed by default, and
|
|
385
|
+
tombstones archive rather than delete.
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## 📜 The contract
|
|
390
|
+
|
|
391
|
+
Kevin 1.x makes promises about its published surface **in writing**.
|
|
392
|
+
[`docs/CONTRACT.md`](docs/CONTRACT.md) freezes nine clauses — `C-01` … `C-09` —
|
|
393
|
+
from the `AGENTS.md` marker bytes to the database schema, each tagged `frozen`
|
|
394
|
+
or `forward-only` and stamped with the release that incurred the obligation. A
|
|
395
|
+
test diffs the live contract against an append-only golden file on every run:
|
|
396
|
+
removals and silent changes fail loudly; additions must carry `since`.
|
|
397
|
+
|
|
398
|
+
```jsonc
|
|
399
|
+
// kevin_contract (excerpt)
|
|
400
|
+
{
|
|
401
|
+
"contract_version": 1,
|
|
402
|
+
"digest": "1de9740bba2e9f95",
|
|
403
|
+
"clauses": [
|
|
404
|
+
{ "id": "C-03", "title": "Tool names and argument shapes", "stability": "frozen", "since": "0.2.0" },
|
|
405
|
+
{ "id": "C-07", "title": "Database schema", "stability": "forward-only", "since": "0.1.0" }
|
|
406
|
+
]
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
> 1.0.0 is not just a version number — it is where Kevin starts making explicit, testable promises about its surface.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## ⏱️ Hooks & latency budgets
|
|
415
|
+
|
|
416
|
+
Six host hooks plus Kevin's own `dispose` checkpoint — eight measured scopes,
|
|
417
|
+
each with a declared p95/max budget enforced by `npm run bench:check`:
|
|
418
|
+
|
|
419
|
+
| Scope | p95 budget | max |
|
|
420
|
+
|---|---:|---:|
|
|
421
|
+
| `tool.execute.before` | 2 ms | 10 ms |
|
|
422
|
+
| `tool.execute.after` | 5 ms | 25 ms |
|
|
423
|
+
| `chat.message` | 2 ms | 10 ms |
|
|
424
|
+
| `chat.system.transform` | 15 ms | 50 ms |
|
|
425
|
+
| `session.compacting` | 15 ms | 50 ms |
|
|
426
|
+
| `event` | 5 ms | 25 ms |
|
|
427
|
+
| `session.idle` | 150 ms | 600 ms |
|
|
428
|
+
| `dispose` | 50 ms | 250 ms |
|
|
429
|
+
|
|
430
|
+
Measured on the reference laptop: retrieval p50 ≈ 0.2 ms, p95 < 1 ms — orders
|
|
431
|
+
of magnitude under budget. Samples persist to `perf_samples` at idle; a breach
|
|
432
|
+
degrades `kevin_doctor`'s verdict, because a plugin that is technically alive
|
|
433
|
+
but consistently slow is not healthy.
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## ⚙️ Configuration
|
|
438
|
+
|
|
439
|
+
Everything is a TEXT setting managed through `kevin_config` (or any SQLite
|
|
440
|
+
client). All values are TEXT — flags compare with `=== "1"`, never truthiness.
|
|
441
|
+
|
|
442
|
+
| Key | Default | Purpose |
|
|
443
|
+
|---|---|---|
|
|
444
|
+
| `quality_gate_enabled` | `'1'` | Weak lessons stored but never injected |
|
|
445
|
+
| `lesson_snippet_injection` | `'1'` | Compact 2-line snippets instead of full bodies |
|
|
446
|
+
| `patternminer_enabled` | `'0'` | Deterministic tool-sequence mining (≥5 sessions) |
|
|
447
|
+
| `cross_project_enabled` | `'0'` | Include imported cross-project rows |
|
|
448
|
+
| `llm_reflection_enabled` | `'0'` | Opt-in LLM enrichment at pattern promotion |
|
|
449
|
+
| `tool_calls_dedup_enabled` | `'0'` | Suppress duplicate call recordings per minute bucket |
|
|
450
|
+
| `deterministic_retrieval` | `'0'` | Freeze the clock for hermetic tests/replay |
|
|
451
|
+
| `pre_prompt_budget_tokens` | `'400'` | Pre-prompt injection cap (clamped `[0, 4000]`) |
|
|
452
|
+
| `archive_after_days` | `'30'` | Age threshold for idle archival |
|
|
453
|
+
| `curation_enabled` | `'1'` | Idle dry-run proposal generation |
|
|
454
|
+
| `agents_md_path` | `'AGENTS.md'` | Where curated knowledge lands |
|
|
455
|
+
| `skill_emission_enabled` | `'0'` | Register project-knowledge skill on v2 hosts |
|
|
456
|
+
| `reference_emission_enabled` | `'0'` | Register `@kevin/<topic>` mentions |
|
|
457
|
+
| `injection_confidence_floor` | `'0.6'` | Memories below this never inject |
|
|
458
|
+
| `repo_truth_enabled` | `'0'` | Repository fact scanning |
|
|
459
|
+
| `convention_mining_enabled` | `'0'` | Deterministic convention mining |
|
|
460
|
+
| `conflict_detection_enabled` | `'0'` | Contradiction surfacing |
|
|
461
|
+
| `error_lesson_mode` | `'all'` | Error lesson injection mode |
|
|
462
|
+
| `shared_layer_enabled` | `'0'` | Team sharing via `.kevin/knowledge.okf` |
|
|
463
|
+
| `okf_path` | `'.kevin/knowledge.okf'` | Shared file location |
|
|
464
|
+
| `share_requires_approval` | `'1'` | No export without human confirmation |
|
|
465
|
+
| `author_identity_mode` | `'hashed'` | Author identity hashed, never raw email |
|
|
466
|
+
| `shared_confidence_floor` | `'0.7'` | Confidence floor for shared projections |
|
|
467
|
+
| `hook_liveness_enabled` | `'1'` | Per-hook liveness tracking |
|
|
468
|
+
| `native_registration_enabled` | `'0'` | v2 native skill/reference registration |
|
|
469
|
+
| `host_probe_history_enabled` | `'0'` | Append-only probe history |
|
|
470
|
+
| `dead_hook_report_threshold` | `'3'` | Consecutive misses before a hook reads dead |
|
|
471
|
+
| `perf_enabled` | `'1'` | Latency instrumentation |
|
|
472
|
+
| `perf_ring_capacity` | `'512'` | Samples per scope (clamped `[64, 8192]`) |
|
|
473
|
+
| `perf_flush_on_idle` | `'1'` | Persist samples at idle |
|
|
474
|
+
| `contract_report_enabled` | `'1'` | Contract block in `kevin_audit` |
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
## 🖥️ Supported runtimes
|
|
479
|
+
|
|
480
|
+
| Runtime | SQLite backend | Status |
|
|
481
|
+
|---|---|---|
|
|
482
|
+
| Node 24.x | `node:sqlite` (stable) | ✅ **Supported** — the reference row |
|
|
483
|
+
| Node 22.5+ | `better-sqlite3` (optional dep) | ⚠️ **Supported with a caveat** — needs a build toolchain; without one there is no backend (and npm install still succeeds silently) |
|
|
484
|
+
| Node 22.5+ | `node:sqlite` behind `--experimental-sqlite` | 🔶 Works, unsupported — exercised in CI, not promised |
|
|
485
|
+
| Bun ≥ 1.1 | `bun:sqlite` | ✅ **Supported** — smoke-tested in `npm run verify` |
|
|
486
|
+
|
|
487
|
+
Zero process spawns, zero network calls — asserted by source scan on every
|
|
488
|
+
test run.
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## 🎨 Design & trust
|
|
493
|
+
|
|
494
|
+
**Principles.** Local first · deterministic by default (no LLM in the core
|
|
495
|
+
loop) · evidence over vibes (every memory carries evidence, provenance,
|
|
496
|
+
recurrence and confidence) · signal over noise (inject *less, better* context,
|
|
497
|
+
not more) · humans hold the write boundary · git-friendly collaboration ·
|
|
498
|
+
important claims become executable checks.
|
|
499
|
+
|
|
500
|
+
**Security model.** Stored knowledge is treated as untrusted input: anything
|
|
501
|
+
reaching an artifact or prompt passes through idempotent escaping at the
|
|
502
|
+
single write path; permanent project-file changes require explicit human
|
|
503
|
+
approval; author identity in the shared layer is hashed
|
|
504
|
+
(`author_identity_mode='hashed'`). No network service is required to store,
|
|
505
|
+
retrieve or share knowledge.
|
|
506
|
+
|
|
507
|
+
**Without memory vs with Kevin:**
|
|
508
|
+
|
|
509
|
+
```
|
|
510
|
+
without: session 1 solve ─▶ context closes ─▶ session 2 same problem ─▶ solve again
|
|
511
|
+
|
|
512
|
+
with: session 1 solve ─▶ lesson ─▶ memory ─┐
|
|
513
|
+
session 2 problem ◀── recall ◀───────┘ ─▶ fix ─▶ evidence ↑
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
**Why not just `AGENTS.md`?** It is excellent for durable, human-authored
|
|
517
|
+
guidance — Kevin treats it as a curated destination, not as a memory system.
|
|
518
|
+
It cannot do failure/fix traces, confidence scoring, evidence tracking, ranked
|
|
519
|
+
retrieval, recurrence signals, dry-run injection inspection, automatic
|
|
520
|
+
proposal generation, team projections, or performance and contract
|
|
521
|
+
instrumentation. That is what Kevin adds around it.
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
## 🛠️ Development
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
npm install
|
|
529
|
+
npm run typecheck # tsc --noEmit (strict)
|
|
530
|
+
npm run lint # biome
|
|
531
|
+
npm test # vitest — 1374 tests across 190 files
|
|
532
|
+
npm run verify # install checks + Bun smoke + verify:pack
|
|
533
|
+
npm run gen:corpus # regenerate the seeded corpus (byte-identical)
|
|
534
|
+
npm run replay # replay recorded sessions deterministically
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
Project layout:
|
|
538
|
+
|
|
539
|
+
```
|
|
540
|
+
plugin/ 51 modules — Store, MemoryService, Reflector, Perf, Contract, …
|
|
541
|
+
migrations/ 001 → 011 — additive, idempotent, forward-only forever
|
|
542
|
+
scripts/ bench · gen-corpus · verify-pack · verify-install · …
|
|
543
|
+
tests/ unit · integration · e2e · replay fixtures
|
|
544
|
+
bench/ committed corpus + committed results
|
|
545
|
+
docs/ CONTRACT.md · per-release plans/tasks · roadmap
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## 📄 License
|
|
551
|
+
|
|
552
|
+
MIT — see the package manifest. Kevin is built by [jmtrin](https://github.com/jmtrin);
|
|
553
|
+
bug reports and PRs welcome at the [issue tracker](https://github.com/jmtrin/opencode-kevin/issues).
|
|
554
|
+
|
|
555
|
+
<div align="center">
|
|
556
|
+
|
|
557
|
+
### ⚡ Kevin — *Observe. Learn. Remember. Improve.*
|
|
558
|
+
|
|
559
|
+
</div>
|