@bodhi-ventures/aiocs 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/LICENSE +21 -0
- package/README.md +488 -0
- package/dist/chunk-ID3PUSMY.js +4535 -0
- package/dist/cli.js +624 -0
- package/dist/mcp-server.js +720 -0
- package/docs/2026-03-26-agent-json-and-daemon-design.md +157 -0
- package/docs/2026-03-28-hybrid-search-design.md +423 -0
- package/docs/README.md +12 -0
- package/docs/codex-integration.md +125 -0
- package/docs/examples/codex-agents/aiocs-docs-specialist.example.toml +21 -0
- package/docs/json-contract.md +524 -0
- package/docs/superpowers/specs/2026-03-29-tag-driven-release-pipeline-design.md +135 -0
- package/package.json +74 -0
- package/skills/aiocs/SKILL.md +174 -0
- package/sources/ethereal.yaml +20 -0
- package/sources/hyperliquid.yaml +20 -0
- package/sources/lighter.yaml +24 -0
- package/sources/nado.yaml +22 -0
- package/sources/synthetix.yaml +24 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name = "aiocs_docs_specialist"
|
|
2
|
+
description = "Development example specialist for local aiocs documentation search, drift checks, diffs, and health verification through a checkout-local MCP server."
|
|
3
|
+
model = "gpt-5.4-mini"
|
|
4
|
+
model_reasoning_effort = "high"
|
|
5
|
+
sandbox_mode = "read-only"
|
|
6
|
+
nickname_candidates = ["Index", "Ledger", "Compass"]
|
|
7
|
+
developer_instructions = """
|
|
8
|
+
Use aiocs as the first stop for local documentation work.
|
|
9
|
+
Prefer aiocs before live browsing when the requested docs may already exist in the local catalog.
|
|
10
|
+
Check source presence and freshness with source_list before assuming docs are missing or stale.
|
|
11
|
+
Default to search mode auto, switch to lexical for exact identifiers, prefer refresh_due for targeted freshness checks, and use batch when multiple aiocs tool calls are needed in one task.
|
|
12
|
+
If the parent agent explicitly asks for aiocs write operations and a source is missing but likely to be reused, add a spec under ~/.aiocs/sources, upsert it, then refresh only that source.
|
|
13
|
+
Avoid fetch all unless the parent agent explicitly asks for broad maintenance.
|
|
14
|
+
When returning results, include sourceId, snapshotId, and pageUrl when they materially improve traceability.
|
|
15
|
+
Do not edit aiocs source specs, catalog contents, or daemon configuration unless the parent agent explicitly asks for it.
|
|
16
|
+
If aiocs health is in doubt, run doctor before assuming the catalog is broken.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
[mcp_servers.aiocs]
|
|
20
|
+
command = "pnpm"
|
|
21
|
+
args = ["--dir", "/absolute/path/to/aiocs", "dev:mcp"]
|
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
# CLI JSON Contract
|
|
2
|
+
|
|
3
|
+
`aiocs` exposes a single-document JSON envelope for every one-shot CLI command when the root `--json` flag is present.
|
|
4
|
+
|
|
5
|
+
## One-shot command envelope
|
|
6
|
+
|
|
7
|
+
Successful commands write exactly one JSON object to stdout:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"ok": true,
|
|
12
|
+
"command": "search",
|
|
13
|
+
"data": {
|
|
14
|
+
"results": []
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Failed commands still write exactly one JSON object to stdout and exit with status `1`:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"ok": false,
|
|
24
|
+
"command": "show",
|
|
25
|
+
"error": {
|
|
26
|
+
"code": "CHUNK_NOT_FOUND",
|
|
27
|
+
"message": "Chunk 42 not found"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Envelope fields:
|
|
33
|
+
|
|
34
|
+
- `ok`: `true` when the command executed and returned data, `false` when command execution failed
|
|
35
|
+
- `command`: stable command identifier such as `source.list`, `refresh.due`, `doctor`, or `init`
|
|
36
|
+
- `data`: command-specific payload on success
|
|
37
|
+
- `error.code`: stable machine-readable failure code
|
|
38
|
+
- `error.message`: stable human-readable error summary on failure
|
|
39
|
+
- `error.details`: optional extra machine-readable error context
|
|
40
|
+
|
|
41
|
+
## Supported one-shot commands
|
|
42
|
+
|
|
43
|
+
All of these support the root-level `--json` flag:
|
|
44
|
+
|
|
45
|
+
- `version`
|
|
46
|
+
- `init`
|
|
47
|
+
- `doctor`
|
|
48
|
+
- `source upsert`
|
|
49
|
+
- `source list`
|
|
50
|
+
- `fetch`
|
|
51
|
+
- `canary`
|
|
52
|
+
- `refresh due`
|
|
53
|
+
- `snapshot list`
|
|
54
|
+
- `diff`
|
|
55
|
+
- `project link`
|
|
56
|
+
- `project unlink`
|
|
57
|
+
- `backup export`
|
|
58
|
+
- `backup import`
|
|
59
|
+
- `embeddings status`
|
|
60
|
+
- `embeddings backfill`
|
|
61
|
+
- `embeddings clear`
|
|
62
|
+
- `embeddings run`
|
|
63
|
+
- `search`
|
|
64
|
+
- `verify coverage`
|
|
65
|
+
- `show`
|
|
66
|
+
|
|
67
|
+
## Command payloads
|
|
68
|
+
|
|
69
|
+
This section documents the stable top-level `data` payload per command.
|
|
70
|
+
|
|
71
|
+
### `version`
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"name": "@bodhi-ventures/aiocs",
|
|
76
|
+
"version": "0.1.0"
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### `init`
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"sourceSpecDir": "/absolute/path/to/aiocs/sources",
|
|
85
|
+
"fetched": false,
|
|
86
|
+
"initializedSources": [
|
|
87
|
+
{
|
|
88
|
+
"sourceId": "hyperliquid",
|
|
89
|
+
"specPath": "/absolute/path/to/aiocs/sources/hyperliquid.yaml",
|
|
90
|
+
"configHash": "sha256...",
|
|
91
|
+
"configChanged": false
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
"removedSourceIds": [],
|
|
95
|
+
"fetchResults": []
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### `doctor`
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"summary": {
|
|
104
|
+
"status": "healthy",
|
|
105
|
+
"checkCount": 10,
|
|
106
|
+
"passCount": 10,
|
|
107
|
+
"warnCount": 0,
|
|
108
|
+
"failCount": 0
|
|
109
|
+
},
|
|
110
|
+
"checks": [
|
|
111
|
+
{
|
|
112
|
+
"id": "catalog",
|
|
113
|
+
"status": "pass",
|
|
114
|
+
"summary": "Catalog opened successfully at ~/.aiocs/data",
|
|
115
|
+
"details": {}
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Check ids are currently:
|
|
122
|
+
|
|
123
|
+
- `catalog`
|
|
124
|
+
- `playwright`
|
|
125
|
+
- `daemon-config`
|
|
126
|
+
- `source-spec-dirs`
|
|
127
|
+
- `freshness`
|
|
128
|
+
- `daemon-heartbeat`
|
|
129
|
+
- `embedding-provider`
|
|
130
|
+
- `vector-store`
|
|
131
|
+
- `embeddings`
|
|
132
|
+
- `docker`
|
|
133
|
+
|
|
134
|
+
Summary status values:
|
|
135
|
+
|
|
136
|
+
- `healthy`: no warnings or failures
|
|
137
|
+
- `degraded`: warnings but no failures
|
|
138
|
+
- `unhealthy`: at least one failed check
|
|
139
|
+
|
|
140
|
+
### `source.upsert`
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"sourceId": "hyperliquid",
|
|
145
|
+
"configHash": "sha256...",
|
|
146
|
+
"specPath": "/absolute/path/to/spec.yaml"
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### `source.list`
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"sources": [
|
|
155
|
+
{
|
|
156
|
+
"id": "hyperliquid",
|
|
157
|
+
"label": "Hyperliquid",
|
|
158
|
+
"nextDueAt": "2026-03-26T12:00:00.000Z",
|
|
159
|
+
"nextCanaryDueAt": "2026-03-26T06:00:00.000Z",
|
|
160
|
+
"lastCheckedAt": "2026-03-26T10:00:00.000Z",
|
|
161
|
+
"lastSuccessfulSnapshotAt": "2026-03-26T10:00:00.000Z",
|
|
162
|
+
"lastSuccessfulSnapshotId": "snp_...",
|
|
163
|
+
"lastCanaryCheckedAt": "2026-03-26T08:00:00.000Z",
|
|
164
|
+
"lastSuccessfulCanaryAt": "2026-03-26T08:00:00.000Z",
|
|
165
|
+
"lastCanaryStatus": "pass"
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### `fetch` and `refresh.due`
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"results": [
|
|
176
|
+
{
|
|
177
|
+
"sourceId": "hyperliquid",
|
|
178
|
+
"snapshotId": "snp_...",
|
|
179
|
+
"pageCount": 139,
|
|
180
|
+
"reused": false
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### `canary`
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"results": [
|
|
191
|
+
{
|
|
192
|
+
"sourceId": "hyperliquid",
|
|
193
|
+
"status": "pass",
|
|
194
|
+
"checkedAt": "2026-03-26T10:00:00.000Z",
|
|
195
|
+
"summary": {
|
|
196
|
+
"checkCount": 1,
|
|
197
|
+
"passCount": 1,
|
|
198
|
+
"failCount": 0
|
|
199
|
+
},
|
|
200
|
+
"checks": [
|
|
201
|
+
{
|
|
202
|
+
"url": "https://example.dev/docs/start",
|
|
203
|
+
"status": "pass",
|
|
204
|
+
"title": "Docs Start",
|
|
205
|
+
"markdownLength": 120
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### `snapshot.list`
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"sourceId": "hyperliquid",
|
|
218
|
+
"snapshots": [
|
|
219
|
+
{
|
|
220
|
+
"snapshotId": "snp_...",
|
|
221
|
+
"sourceId": "hyperliquid",
|
|
222
|
+
"detectedVersion": null,
|
|
223
|
+
"createdAt": "2026-03-26T10:00:00.000Z",
|
|
224
|
+
"pageCount": 139
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### `project.link` and `project.unlink`
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"projectPath": "/absolute/path/to/project",
|
|
235
|
+
"sourceIds": ["hyperliquid", "lighter"]
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### `diff`
|
|
240
|
+
|
|
241
|
+
```json
|
|
242
|
+
{
|
|
243
|
+
"sourceId": "hyperliquid",
|
|
244
|
+
"fromSnapshotId": "snp_old",
|
|
245
|
+
"toSnapshotId": "snp_new",
|
|
246
|
+
"summary": {
|
|
247
|
+
"addedPageCount": 1,
|
|
248
|
+
"removedPageCount": 1,
|
|
249
|
+
"changedPageCount": 2,
|
|
250
|
+
"unchangedPageCount": 98
|
|
251
|
+
},
|
|
252
|
+
"addedPages": [
|
|
253
|
+
{
|
|
254
|
+
"url": "https://example.dev/docs/new-page",
|
|
255
|
+
"title": "New page"
|
|
256
|
+
}
|
|
257
|
+
],
|
|
258
|
+
"removedPages": [],
|
|
259
|
+
"changedPages": [
|
|
260
|
+
{
|
|
261
|
+
"url": "https://example.dev/docs/start",
|
|
262
|
+
"beforeTitle": "Start",
|
|
263
|
+
"afterTitle": "Start",
|
|
264
|
+
"lineSummary": {
|
|
265
|
+
"addedLineCount": 3,
|
|
266
|
+
"removedLineCount": 2
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
]
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### `search`
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"query": "maker flow",
|
|
278
|
+
"total": 42,
|
|
279
|
+
"limit": 20,
|
|
280
|
+
"offset": 0,
|
|
281
|
+
"hasMore": true,
|
|
282
|
+
"modeRequested": "auto",
|
|
283
|
+
"modeUsed": "hybrid",
|
|
284
|
+
"results": [
|
|
285
|
+
{
|
|
286
|
+
"chunkId": 42,
|
|
287
|
+
"sourceId": "hyperliquid",
|
|
288
|
+
"snapshotId": "snp_...",
|
|
289
|
+
"pageUrl": "https://example.dev/docs/maker-flow",
|
|
290
|
+
"pageTitle": "Maker flow",
|
|
291
|
+
"sectionTitle": "Order lifecycle",
|
|
292
|
+
"markdown": "# Order lifecycle\n...",
|
|
293
|
+
"score": 0.036,
|
|
294
|
+
"signals": ["lexical", "vector"]
|
|
295
|
+
}
|
|
296
|
+
]
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
`limit` defaults to `20`. `offset` defaults to `0`.
|
|
301
|
+
|
|
302
|
+
`modeRequested` is the requested search mode (`auto`, `lexical`, `hybrid`, `semantic`).
|
|
303
|
+
`modeUsed` is the actual executed mode after fallbacks. In `auto`, `aiocs` can degrade back to lexical if the vector layer is unavailable or incomplete for the requested scope.
|
|
304
|
+
|
|
305
|
+
### `embeddings.status`
|
|
306
|
+
|
|
307
|
+
```json
|
|
308
|
+
{
|
|
309
|
+
"queue": {
|
|
310
|
+
"pendingJobs": 0,
|
|
311
|
+
"runningJobs": 0,
|
|
312
|
+
"failedJobs": 0
|
|
313
|
+
},
|
|
314
|
+
"sources": [
|
|
315
|
+
{
|
|
316
|
+
"sourceId": "hyperliquid",
|
|
317
|
+
"snapshotId": "snp_...",
|
|
318
|
+
"totalChunks": 420,
|
|
319
|
+
"indexedChunks": 420,
|
|
320
|
+
"pendingChunks": 0,
|
|
321
|
+
"failedChunks": 0,
|
|
322
|
+
"staleChunks": 0,
|
|
323
|
+
"coverageRatio": 1
|
|
324
|
+
}
|
|
325
|
+
]
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### `embeddings.backfill`
|
|
330
|
+
|
|
331
|
+
```json
|
|
332
|
+
{
|
|
333
|
+
"queuedJobs": 5
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### `embeddings.clear`
|
|
338
|
+
|
|
339
|
+
```json
|
|
340
|
+
{
|
|
341
|
+
"clearedSources": ["hyperliquid", "lighter"]
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### `embeddings.run`
|
|
346
|
+
|
|
347
|
+
```json
|
|
348
|
+
{
|
|
349
|
+
"processedJobs": 2,
|
|
350
|
+
"succeededJobs": [
|
|
351
|
+
{
|
|
352
|
+
"sourceId": "hyperliquid",
|
|
353
|
+
"snapshotId": "snp_...",
|
|
354
|
+
"chunkCount": 420
|
|
355
|
+
}
|
|
356
|
+
],
|
|
357
|
+
"failedJobs": []
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### `verify.coverage`
|
|
362
|
+
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"sourceId": "hyperliquid",
|
|
366
|
+
"snapshotId": "snp_...",
|
|
367
|
+
"complete": false,
|
|
368
|
+
"summary": {
|
|
369
|
+
"fileCount": 1,
|
|
370
|
+
"headingCount": 100,
|
|
371
|
+
"matchedHeadingCount": 99,
|
|
372
|
+
"missingHeadingCount": 1,
|
|
373
|
+
"matchCounts": {
|
|
374
|
+
"pageTitle": 80,
|
|
375
|
+
"sectionTitle": 15,
|
|
376
|
+
"body": 4
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
"files": [
|
|
380
|
+
{
|
|
381
|
+
"referenceFile": "/absolute/path/to/reference.md",
|
|
382
|
+
"headingCount": 100,
|
|
383
|
+
"matchedHeadingCount": 99,
|
|
384
|
+
"missingHeadingCount": 1,
|
|
385
|
+
"missingHeadings": ["Missing Heading"],
|
|
386
|
+
"matchCounts": {
|
|
387
|
+
"pageTitle": 80,
|
|
388
|
+
"sectionTitle": 15,
|
|
389
|
+
"body": 4
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
]
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### `backup.export`
|
|
397
|
+
|
|
398
|
+
```json
|
|
399
|
+
{
|
|
400
|
+
"outputDir": "/absolute/path/to/backup",
|
|
401
|
+
"manifestPath": "/absolute/path/to/backup/manifest.json",
|
|
402
|
+
"manifest": {
|
|
403
|
+
"formatVersion": 1,
|
|
404
|
+
"createdAt": "2026-03-26T10:00:00.000Z",
|
|
405
|
+
"packageVersion": "0.1.0",
|
|
406
|
+
"entries": [
|
|
407
|
+
{
|
|
408
|
+
"relativePath": "data/catalog.sqlite",
|
|
409
|
+
"type": "file",
|
|
410
|
+
"size": 32768
|
|
411
|
+
}
|
|
412
|
+
]
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### `backup.import`
|
|
418
|
+
|
|
419
|
+
```json
|
|
420
|
+
{
|
|
421
|
+
"inputDir": "/absolute/path/to/backup",
|
|
422
|
+
"dataDir": "/Users/example/.aiocs/data",
|
|
423
|
+
"configDir": "/Users/example/.aiocs/config",
|
|
424
|
+
"manifest": {
|
|
425
|
+
"formatVersion": 1,
|
|
426
|
+
"createdAt": "2026-03-26T10:00:00.000Z",
|
|
427
|
+
"packageVersion": "0.1.0",
|
|
428
|
+
"entries": []
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### `show`
|
|
434
|
+
|
|
435
|
+
```json
|
|
436
|
+
{
|
|
437
|
+
"chunk": {
|
|
438
|
+
"chunkId": 42,
|
|
439
|
+
"sourceId": "hyperliquid",
|
|
440
|
+
"snapshotId": "snp_...",
|
|
441
|
+
"pageUrl": "https://example.dev/docs/maker-flow",
|
|
442
|
+
"pageTitle": "Maker flow",
|
|
443
|
+
"sectionTitle": "Order lifecycle",
|
|
444
|
+
"markdown": "# Order lifecycle\n..."
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
## Daemon event stream
|
|
450
|
+
|
|
451
|
+
`docs daemon --json` is intentionally different because the process is long-running. It emits newline-delimited JSON events to stdout rather than a single envelope.
|
|
452
|
+
|
|
453
|
+
Current event types:
|
|
454
|
+
|
|
455
|
+
- `daemon.started`
|
|
456
|
+
- `daemon.cycle.started`
|
|
457
|
+
- `daemon.cycle.completed`
|
|
458
|
+
- `daemon.stopped`
|
|
459
|
+
|
|
460
|
+
Example:
|
|
461
|
+
|
|
462
|
+
```json
|
|
463
|
+
{"type":"daemon.started","intervalMinutes":60,"fetchOnStart":true,"sourceSpecDirs":["/app/sources"]}
|
|
464
|
+
{"type":"daemon.cycle.started","reason":"startup","startedAt":"2026-03-26T00:00:00.000Z"}
|
|
465
|
+
{"type":"daemon.cycle.completed","reason":"startup","result":{"startedAt":"2026-03-26T00:00:00.000Z","finishedAt":"2026-03-26T00:00:10.000Z","dueSourceIds":[],"bootstrapped":{"processedSpecCount":5,"removedSourceIds":[],"sources":[]},"refreshed":[],"failed":[],"embedded":[],"embeddingFailed":[]}}
|
|
466
|
+
{"type":"daemon.stopped"}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
## Error codes
|
|
470
|
+
|
|
471
|
+
Current stable CLI error codes include:
|
|
472
|
+
|
|
473
|
+
- `INVALID_ARGUMENT`
|
|
474
|
+
- `SOURCE_NOT_FOUND`
|
|
475
|
+
- `SNAPSHOT_NOT_FOUND`
|
|
476
|
+
- `NO_PAGES_FETCHED`
|
|
477
|
+
- `NO_PROJECT_SCOPE`
|
|
478
|
+
- `CHUNK_NOT_FOUND`
|
|
479
|
+
- `REFERENCE_FILE_NOT_FOUND`
|
|
480
|
+
- `INVALID_REFERENCE_FILE`
|
|
481
|
+
- `EMBEDDING_CONFIG_INVALID`
|
|
482
|
+
- `EMBEDDING_PROVIDER_UNAVAILABLE`
|
|
483
|
+
- `VECTOR_STORE_UNAVAILABLE`
|
|
484
|
+
- `EMBEDDING_JOB_NOT_FOUND`
|
|
485
|
+
- `INTERNAL_ERROR`
|
|
486
|
+
|
|
487
|
+
## MCP relationship
|
|
488
|
+
|
|
489
|
+
The `aiocs-mcp` server uses the same underlying payloads, but wraps them in a structured MCP envelope:
|
|
490
|
+
|
|
491
|
+
Successful MCP tool results:
|
|
492
|
+
|
|
493
|
+
```json
|
|
494
|
+
{
|
|
495
|
+
"ok": true,
|
|
496
|
+
"data": {
|
|
497
|
+
"name": "@bodhi-ventures/aiocs",
|
|
498
|
+
"version": "0.1.0"
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Failed MCP tool results:
|
|
504
|
+
|
|
505
|
+
```json
|
|
506
|
+
{
|
|
507
|
+
"ok": false,
|
|
508
|
+
"error": {
|
|
509
|
+
"code": "CHUNK_NOT_FOUND",
|
|
510
|
+
"message": "Chunk 42 not found"
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
The MCP `search` tool supports the same `limit` and `offset` fields as the CLI. The MCP server also exposes:
|
|
516
|
+
|
|
517
|
+
- `embeddings_status`
|
|
518
|
+
- `embeddings_backfill`
|
|
519
|
+
- `embeddings_clear`
|
|
520
|
+
- `embeddings_run`
|
|
521
|
+
- `verify_coverage`
|
|
522
|
+
- `batch`
|
|
523
|
+
|
|
524
|
+
`batch` returns one result object per requested operation, each with its own `ok`, `data`, or `error` fields.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Tag-Driven Release Pipeline Design
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
`aiocs` should release as the public scoped npm package `@bodhi-ventures/aiocs` through a stable, tag-driven GitHub Actions workflow. The repository remains the source of truth for versioning. Releases are created only from pushed stable tags of the form `vX.Y.Z`.
|
|
6
|
+
|
|
7
|
+
The workflow must never mutate git state. It should validate the tag against `package.json`, run the full release verification stack, publish publicly to npm with provenance, and create a GitHub release from the same tag.
|
|
8
|
+
|
|
9
|
+
## Goals
|
|
10
|
+
|
|
11
|
+
- publish `aiocs` publicly under `@bodhi-ventures/aiocs`
|
|
12
|
+
- eliminate workflow-managed version bumps, commits, and tag creation
|
|
13
|
+
- remove improvised git author configuration from the release workflow
|
|
14
|
+
- make the release contract deterministic and easy to reason about
|
|
15
|
+
- keep CI and release validation aligned with the actual shipped package surface
|
|
16
|
+
|
|
17
|
+
## Non-Goals
|
|
18
|
+
|
|
19
|
+
- prerelease publishing
|
|
20
|
+
- automatic releases from `main`
|
|
21
|
+
- workspace/multi-package publishing
|
|
22
|
+
- alternative binary distribution outside npm
|
|
23
|
+
|
|
24
|
+
## Current State
|
|
25
|
+
|
|
26
|
+
- `package.json` still uses the unscoped package name `aiocs`
|
|
27
|
+
- the current release workflow is `workflow_dispatch`-driven
|
|
28
|
+
- the workflow edits `package.json`, creates commits and tags, and configures a bot git identity
|
|
29
|
+
- release automation is more complex than necessary and mixes version mutation with publishing
|
|
30
|
+
|
|
31
|
+
## Chosen Design
|
|
32
|
+
|
|
33
|
+
### Package Identity
|
|
34
|
+
|
|
35
|
+
- rename the npm package to `@bodhi-ventures/aiocs`
|
|
36
|
+
- keep the package public
|
|
37
|
+
- keep CLI command names unchanged:
|
|
38
|
+
- `docs`
|
|
39
|
+
- `aiocs-mcp`
|
|
40
|
+
- add explicit `publishConfig`:
|
|
41
|
+
- `access: public`
|
|
42
|
+
- `provenance: true`
|
|
43
|
+
|
|
44
|
+
### Release Trigger
|
|
45
|
+
|
|
46
|
+
- release workflow triggers only on pushed stable semver tags matching `v*.*.*`
|
|
47
|
+
- the tag version must match `package.json.version` exactly
|
|
48
|
+
- only stable releases are supported; prerelease tags are rejected
|
|
49
|
+
|
|
50
|
+
### Release Workflow Behavior
|
|
51
|
+
|
|
52
|
+
- check out the tagged revision
|
|
53
|
+
- install dependencies and release prerequisites
|
|
54
|
+
- fail fast unless all of these are true:
|
|
55
|
+
- tag matches `vX.Y.Z`
|
|
56
|
+
- `package.json.version === X.Y.Z`
|
|
57
|
+
- `package.json.name === @bodhi-ventures/aiocs`
|
|
58
|
+
- run full release validation:
|
|
59
|
+
- `pnpm lint`
|
|
60
|
+
- `pnpm test`
|
|
61
|
+
- `pnpm build`
|
|
62
|
+
- `npm pack --dry-run`
|
|
63
|
+
- built CLI smoke, at minimum `node dist/cli.js --version`
|
|
64
|
+
- publish to npm with the existing `NPM_TOKEN` org secret
|
|
65
|
+
- create a GitHub release for the pushed tag
|
|
66
|
+
- if a GitHub release already exists for that tag, do not recreate it
|
|
67
|
+
|
|
68
|
+
### Rerun and Partial-Failure Policy
|
|
69
|
+
|
|
70
|
+
Tag releases must be safely rerunnable.
|
|
71
|
+
|
|
72
|
+
- `workflow_dispatch` is removed entirely; tag pushes are the only release trigger
|
|
73
|
+
- if a rerun sees that `@bodhi-ventures/aiocs@X.Y.Z` is already published on npm, it must skip `npm publish` instead of failing
|
|
74
|
+
- if a rerun sees that the GitHub release for `vX.Y.Z` already exists, it must skip release creation instead of failing
|
|
75
|
+
- validation steps always run on every attempt, even when publish/release steps are skipped
|
|
76
|
+
- if npm already contains `@bodhi-ventures/aiocs@X.Y.Z` but the checked-out tag does not match `package.json.version === X.Y.Z` or `package.json.name === @bodhi-ventures/aiocs`, the workflow must fail fast
|
|
77
|
+
- the workflow should treat npm and GitHub release publication as independently idempotent so a partial success can be completed by rerunning the same tag job
|
|
78
|
+
|
|
79
|
+
### Git Behavior
|
|
80
|
+
|
|
81
|
+
- the workflow never edits files
|
|
82
|
+
- the workflow never commits
|
|
83
|
+
- the workflow never creates tags
|
|
84
|
+
- the workflow never configures a synthetic git author
|
|
85
|
+
|
|
86
|
+
Version bumps happen in normal development flow:
|
|
87
|
+
|
|
88
|
+
1. update `package.json.version`
|
|
89
|
+
2. commit the version bump
|
|
90
|
+
3. create tag `vX.Y.Z`
|
|
91
|
+
4. push commit and tag
|
|
92
|
+
|
|
93
|
+
## CI Alignment
|
|
94
|
+
|
|
95
|
+
CI remains the pre-release gate and should stay close to the release workflow:
|
|
96
|
+
|
|
97
|
+
- install dependencies
|
|
98
|
+
- install Playwright Chromium
|
|
99
|
+
- run lint, tests, build, and `npm pack --dry-run`
|
|
100
|
+
- validate Docker image and compose config
|
|
101
|
+
- smoke test the packaged CLI surface
|
|
102
|
+
|
|
103
|
+
CI should also assert package metadata consistency where useful, especially the scoped package name.
|
|
104
|
+
|
|
105
|
+
## Documentation Changes
|
|
106
|
+
|
|
107
|
+
Update repository docs to reflect the scoped public package and release process:
|
|
108
|
+
|
|
109
|
+
- install command becomes `npm install -g @bodhi-ventures/aiocs`
|
|
110
|
+
- add a short release section to the README describing the tag-based flow
|
|
111
|
+
- keep the CLI-facing command examples unchanged
|
|
112
|
+
|
|
113
|
+
## Risks
|
|
114
|
+
|
|
115
|
+
- npm org publishing can still fail if org/package permissions are not configured correctly on npmjs
|
|
116
|
+
- the first release is the highest-risk run because the scoped package has not been proven yet
|
|
117
|
+
- GitHub Actions can only validate the workflow structure locally; final proof requires one live tag release
|
|
118
|
+
|
|
119
|
+
## Acceptance Criteria
|
|
120
|
+
|
|
121
|
+
- `package.json` is updated to `@bodhi-ventures/aiocs`
|
|
122
|
+
- release workflow triggers on stable tags only
|
|
123
|
+
- release workflow does not mutate git state
|
|
124
|
+
- release workflow validates tag/version/name consistency before publishing
|
|
125
|
+
- README/install docs reference the scoped package name
|
|
126
|
+
- local verification passes on the updated tree:
|
|
127
|
+
- lint
|
|
128
|
+
- tests
|
|
129
|
+
- build
|
|
130
|
+
- `npm pack --dry-run`
|
|
131
|
+
- the first real release can be executed by bumping version, pushing a `vX.Y.Z` tag, and observing npm + GitHub release creation
|
|
132
|
+
|
|
133
|
+
## Follow-Up
|
|
134
|
+
|
|
135
|
+
After implementation, do one real tagged stable release to prove the pipeline end to end.
|