@aistastudio/myc 0.3.6 → 0.3.9

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 CHANGED
@@ -1,8 +1,11 @@
1
1
  # myc
2
2
 
3
3
  A local, fast task-and-memory layer for coding agents: a task queue, an oplog of
4
- facts and decisions, and hybrid (lexical + vector) search over the project's
5
- memory — with no network calls and no mandatory LLM key.
4
+ facts and decisions, hybrid (lexical + vector) search over the project's
5
+ memory, and a built-in code index — with no network calls of its own and no
6
+ mandatory LLM key. The network is reached only when you ask: `myc models
7
+ fetch`, `myc code fetch`, `myc version --check` (or `MYC_UPDATE_CHECK=1`, a
8
+ background version check at most once a day from `init` and `wire`).
6
9
 
7
10
  Agents forget. `myc` is the part that doesn't: decisions survive context
8
11
  compaction, work survives process death, and both survive being moved between
@@ -11,11 +14,15 @@ machines through plain git.
11
14
  Design docs live in `docs/design/` (start with `00-brief.md`); the measurements
12
15
  quoted below are reproducible from `bench/` and `scripts/`.
13
16
 
14
- **Site: <https://aistastudio.github.io/myc/>** — the same measurements as charts,
15
- in English and Russian, with the command that reproduces each number printed
16
- next to it. Source in `site/`; `bun run site/build.ts` re-checks every figure
17
- against the measurement artefacts in this repository and refuses to build on a
18
- mismatch.
17
+ **Site: <https://aistastudio.github.io/myc/>** — every capability with the
18
+ release it arrived in and a command that shows it, the roadmap, and the
19
+ measurements as charts, in English and Russian, with the command that
20
+ reproduces each number printed next to it. It is the one source of numbers:
21
+ `bun run site/build.ts` checks every figure on the site against the measurement
22
+ artefacts in this repository, the figures in this README and in the Russian one
23
+ against the site's `site/measurements.json`, and every `myc` command and flag
24
+ on the site and in both READMEs against this build's `--help`; a mismatch fails
25
+ the build.
19
26
 
20
27
  ## Requires Bun — this is not fine print
21
28
 
@@ -30,20 +37,23 @@ Install Bun: https://bun.sh
30
37
  Installation is one command:
31
38
 
32
39
  ```bash
33
- bun install -g @aistastudio/myc # 3.20 MB, 10 files, no models pulled at install
34
- myc --version # myc 0.3.6 (schema 1)
40
+ bun install -g @aistastudio/myc # 3.41 MB compressed, 12.57 MB unpacked, 13 files; no models pulled
41
+ myc --version # myc 0.3.9 (schema 1)
35
42
  ```
36
43
 
37
- It runs on macOS and Linux; on Windows, use WSL.
44
+ It runs on macOS and Linux. On Windows, use WSL and install Bun and myc inside
45
+ it: the `myc` launcher does not start in cmd or PowerShell, and an npm install
46
+ on Windows says so.
38
47
 
39
48
  The embedding model is **not** downloaded during install. Semantic search is
40
49
  opt-in and explicit: `myc models fetch` (129 MB, ~7 s). Until then search is
41
- lexical and says so.
50
+ lexical and says so on every answer (`WARN degraded.embeddings`). The grammars
51
+ for the code index are fetched the same way, once: `myc code fetch`.
42
52
 
43
53
  To run the newest code instead of the published release, build from source:
44
54
 
45
55
  ```bash
46
- git clone <repo> && cd myc
56
+ git clone https://github.com/aistastudio/myc && cd myc
47
57
  bun install
48
58
  bun run build # produces a single binary: dist/myc
49
59
  ./dist/myc --version
@@ -55,18 +65,40 @@ writing a config that silently won't start.
55
65
 
56
66
  ## Quick start
57
67
 
68
+ Two commands set a project up; the rest is the loop an agent lives in. (From a
69
+ source build, `./dist/myc` instead of `myc`.)
70
+
58
71
  ```bash
59
- ./dist/myc init # .myc/ + SQLite + migrations in this repo
60
- ./dist/myc wire # hooks for Claude Code / Codex / opencode / Kimi
61
- ./dist/myc wire --scope user # the same for agents in git worktrees (Claude Code's user layer)
62
- ./dist/myc ready # what can be picked up right now
63
- ./dist/myc remember "why X, not Y" # record a fact or decision
64
- ./dist/myc recall "how retrieval works"
65
- ./dist/myc prime # session context packet (agents call it)
66
- ./dist/myc doctor # schema, counters, hooks says "don't know" where it doesn't
72
+ myc init # .myc/ + SQLite + migrations in this repo
73
+ myc wire # hooks + MCP for Claude Code, Codex, opencode and Kimi
74
+ myc ready --claim # take the next task
75
+ myc show <id> # all that is known about it
76
+ myc close <id>
77
+ myc remember "why X, not Y" # record a fact or decision
78
+ myc recall "how retrieval works"
79
+ myc prime # session context packet (agents call it)
80
+ myc code fetch # grammars for this repo's languages, once
81
+ myc code index # symbols, callers, code search
82
+ myc doctor # schema, counters, hooks — says "don't know" where it doesn't
67
83
  ```
68
84
 
69
- Full command list: `./dist/myc --help`.
85
+ Full command list: `myc --help`; details of each: `myc <command> --help`.
86
+
87
+ ## Wiring agents
88
+
89
+ `myc wire` writes only its own files in full and merges JSON configs node by
90
+ node with a `.myc.bak` alongside; `CLAUDE.md` is never touched. Running it twice
91
+ changes nothing. Everything past the plain `wire` is opt-in:
92
+
93
+ ```bash
94
+ myc wire --dry-run # show every change, write nothing
95
+ myc wire --agents claude,codex # only some of the agents
96
+ myc wire --status-line # + myc's status line under Claude Code's prompt
97
+ myc wire --queue-hook # + heavy commands take turns (below)
98
+ myc wire --agents-md # + the myc block in AGENTS.md
99
+ myc wire --scope user # the same for agents in git worktrees (Claude Code's user layer)
100
+ myc unwire # remove what wire put in
101
+ ```
70
102
 
71
103
  **Agents in git worktrees.** `myc wire` writes into the project:
72
104
  `.claude/settings.json`, `.mcp.json`. An agent that orca starts in a git
@@ -94,15 +126,15 @@ journal, not in our command, and gets the same stdin on every redraw, never
94
126
  waited on: orca takes a line whose command mentions its
95
127
  `agent-hooks/claude-statusline.sh` for its own and removes it when it
96
128
  uninstalls (a foreign line it leaves alone), so ours never carries the word
97
- `claude-statusline`. A
98
- project with its own myc line keeps it, and that line hands the input to the
99
- same recorded line. If another tool replaces the user line after wire, `myc
100
- doctor --hooks` says so; `myc wire --scope user --status-line` puts ours back
101
- and makes the new line the previous one, and `myc unwire --scope user` puts the
102
- previous line back byte for byte. `myc doctor --hooks` checks the whole user
103
- layer against the journal: myc's hook entries and rules still in
104
- `~/.claude/settings.json`, the helpers exactly what this build writes (a stale
105
- one is named with the build that wrote it), the status line, the MCP server.
129
+ `claude-statusline`. A project with its own myc line keeps it, and that line
130
+ hands the input to the same recorded line. If another tool replaces the user
131
+ line after wire, `myc doctor --hooks` says so; `myc wire --scope user
132
+ --status-line` puts ours back and makes the new line the previous one, and `myc
133
+ unwire --scope user` puts the previous line back byte for byte. `myc doctor
134
+ --hooks` checks the whole user layer against the journal: myc's hook entries and
135
+ rules still in `~/.claude/settings.json`, the helpers exactly what this build
136
+ writes (a stale one is named with the build that wrote it), the status line, the
137
+ MCP server.
106
138
 
107
139
  ## Heavy commands take turns
108
140
 
@@ -144,14 +176,14 @@ Code `PreToolUse` hook that rewrites a heavy Bash command into
144
176
  `myc run -- <the same command>` before it runs. Heavy means a full test run or a
145
177
  build: `bun test` with no paths, `bun run build` / `typecheck`, `npm` / `pnpm` /
146
178
  `yarn` `test` and `build`, `cargo test` / `build`, `go test ./...`, `pytest`
147
- with no paths, `make`. A targeted `bun test path/file.test.ts`, a command already
179
+ with no paths, `make`. A targeted `bun test <path>`, a command already
148
180
  under `myc run`, a background one and a nested one pass untouched.
149
181
  `MYC_QUEUE_HEAVY` replaces the list (`+…` adds to it, `off` turns the hook off).
150
182
  It is opt-in: `wire` without the flag writes no such hook, and `unwire` removes
151
183
  it. It is cheap, because it runs on every Bash call: a command that is not heavy
152
184
  is let through by the host's own shell without starting bun or node — 3.4 ms at
153
- the median and 4.3 ms at p99 in the run of 2026-09-11, against 30 ms for the
154
- prime hook (`bun test packages/cli/src/hooks/queue-hook.multiprocess.test.ts`).
185
+ the median and 4.3 ms at p99 in the run of 2026-09-11, against the prime hook's
186
+ 30 ms p99 budget (`bun test packages/cli/src/hooks/queue-hook.multiprocess.test.ts`).
155
187
 
156
188
  **`myc run` is not a way around permissions.** It runs whatever it is given, so
157
189
  a queued command goes through without a question only when your own rules would
@@ -159,26 +191,139 @@ let the original command through — `Bash(bun test:*)` keeps `bun test` silent
159
191
  under the queue as well. Otherwise Claude Code asks, and the question shows the
160
192
  whole command; a deny or ask rule on the original command still holds. The same
161
193
  goes for a `myc run -- <cmd>` an agent types itself. For the same reason `wire`
162
- no longer writes the broad `Bash(myc:*)`: it allows myc's subcommands one by
163
- one, and `run`, `statusline --then`, `wire` and `unwire` ask.
194
+ does not write the broad `Bash(myc:*)`: it allows myc's subcommands one by one,
195
+ and `run`, `statusline --then`, `wire` and `unwire` ask.
196
+
197
+ ## Code intelligence
198
+
199
+ Code intelligence is built in, and it is the same engine the alternatives use:
200
+ tree-sitter, with grammars fetched on demand rather than shipped. Symbols,
201
+ callers and code search work for TypeScript, TSX, JavaScript (js, jsx, mjs,
202
+ cjs) and Python — the languages myc has definition rules for. The grammar
203
+ package holds 36; a language is added as a pair, a rule and a catalog entry,
204
+ so a grammar that would yield no symbols is never offered. Every other file
205
+ still gets `code grep`, anchors and staleness.
206
+
207
+ `myc code fetch` downloads exactly the grammars this repository's files need,
208
+ checked by sha256 — the only step that goes to the network; indexing never does,
209
+ and a language whose grammar is missing is skipped and named. `myc code index`
210
+ builds the index, incrementally: a repeat run over an unchanged tree reads
211
+ nothing, and after that the index is refreshed in the background. These read it,
212
+ from the CLI and over MCP alike:
213
+
214
+ ```
215
+ myc code symbol <name> where it is defined, and what knowledge is anchored there
216
+ myc callers <name> who calls it; --direction out, --depth all
217
+ myc code search "…" by meaning, when you do not know the name
218
+ myc code grep "<lit>" exhaustive, every occurrence; --in <path> narrows it
219
+ myc code map orientation: directory clusters, their hubs, who depends on them
220
+ myc skeleton <file> the file's API, and how many times cheaper that was than reading it
221
+ ```
222
+
223
+ The file list is git's own (`git ls-files`, so `.gitignore` applies; a tree
224
+ without git is walked, and the command says so). On top of any list,
225
+ secret-named files are never indexed, whatever `.gitignore` says: `.env` and
226
+ `.env.*` (templates like `.env.example` are indexed), `*.pem`, `*.key`,
227
+ keystores, private SSH keys, `.npmrc`, `.netrc` and other credential files —
228
+ `code index` counts them without naming them, and `code grep` refuses to read one.
229
+
230
+ **Nested repositories and git worktrees.** A workspace can be an ecosystem: a
231
+ root that is a git repository with independent repositories inside it (not
232
+ submodules). It has one code index, built from the root — one row per file,
233
+ paths like `messaging-server/server/src/x.ts`. From inside a nested
234
+ repository every code command answers from that repository's part of the
235
+ root index, with paths relative to the repository you are in; from the root
236
+ the answers do not change. `myc code index` run inside a nested repository
237
+ refreshes its part of the root index instead of building a second copy of the
238
+ same files. The index also keeps itself fresh: after any myc command, when its
239
+ last run is older than 15 minutes (`MYC_CODE_INDEX_PERIOD_MS`), one background
240
+ `code index` per workspace is queued and runs detached at low priority, never
241
+ delaying the command; the status line and the code commands say when it is
242
+ refreshing, queued or stale. A git worktree — even one
243
+ outside the workspace tree — is answered from the index of the main checkout:
244
+ there is no index per branch. When the worktree is on another commit, or has
245
+ uncommitted changes to tracked files, every answer carries
246
+ `WARN code_index.worktree_divergent` naming both branches, because lines and
247
+ spans may not match your files. `code grep` reads the worktree's files (the
248
+ line numbers are yours, the owning symbols come from the index); `skeleton`
249
+ shows the main copy's declarations when your copy differs from what the index
250
+ saw, and says so. When nothing covers the repository, the hint is the command
251
+ for the workspace root (`myc -C <root> code index`), not one that would build a
252
+ duplicate. Anchors set from the root and from inside a repository are stored
253
+ under different keys; `code symbol` reads both.
254
+
255
+ Anchors tie knowledge to a span and follow the code as it moves; that half is
256
+ language-agnostic and was verified on Python as well as TypeScript.
257
+
258
+ ## Migration from beads
259
+
260
+ ```bash
261
+ cd <beads-project>
262
+ myc init
263
+ myc import-beads --dry-run # count what would come over, change nothing
264
+ myc import-beads # collects the snapshot itself: bd export --include-memories
265
+ ```
266
+
267
+ Run it again later and it is a sync, not a second copy: fields changed in beads
268
+ (status, priority, labels, close reason, parent, blockers) are applied as normal
269
+ graph changes, and local myc edits are never silently overwritten — one-sided
270
+ local changes are kept and named, two-sided ones are named as conflicts and left
271
+ alone. A snapshot file moves the same between machines:
272
+ `bd export --include-memories > snapshot.json`, then
273
+ `myc import-beads snapshot.json`.
274
+
275
+ **It is real, not a demo.** A working project imported into an empty workspace
276
+ in 889 ms: 796 tasks, 972 dependencies, 265 notes, 41 memories — with unknown
277
+ issue types carried over verbatim and named, and out-of-range priorities
278
+ clamped and named, instead of one odd row aborting the import. Those numbers are
279
+ from the first release (0.1.1, 2026-09-07), and that run silently dropped the
280
+ export's comments while reporting every note as imported; it was found the next
281
+ day on a real project and fixed in 0.2.0 (`git show aac5d1f`). What the import
282
+ carries now:
283
+
284
+ - comments, into the node's thread with their authors; unknown top-level
285
+ fields are named instead of dropped (0.2.0);
286
+ - acceptance criteria and design, into the task body between managed markers,
287
+ and the source's own dates, author and owner (0.3.3);
288
+ - statuses myc has no name for, such as `deferred`, as `blocked` with the
289
+ original word kept — never as `open` (0.3.3);
290
+ - sub-repositories of a shared workspace, each with its own repository reach;
291
+ an empty source is a refusal with a hint, not a silent zero (0.3.3).
292
+
293
+ On that same graph both ready queues now return the same 152 tasks. They did
294
+ not always: myc used to offer 195 against beads' 144, because beads inherits
295
+ blockers down the parent chain and myc looked only at a task's own. Those 51
296
+ were inside a still-blocked epic and beads was right to hide them;
297
+ `memory-atcm254ry6c7` is closed, `anc_blockers` is materialised by trigger, and
298
+ the queue now says `281 blocked (51 through an ancestor)` rather than quietly
299
+ offering them.
164
300
 
165
301
  ## What makes it different
166
302
 
167
- **Speed is a constraint, not an optimisation.** Every hot path has a budget
168
- enforced in CI; a p95 regression over 15% fails the build. Measured on 100 000
169
- nodes, 2026-09-07, darwin-arm64-14 (`bun run scripts/bench-latency.ts`):
303
+ **Speed is a constraint, not an optimisation.** Every hot path has a budget,
304
+ and a budget test makes three kinds of claims: structural (the query plan, the
305
+ prefilter), relative (the healthy path against a deliberately degraded rival,
306
+ measured alternately, so the hardware cancels out) and absolute. On every push
307
+ CI checks the first two. The absolute budgets and the 15% p95 regression line
308
+ are calibrated on darwin-arm64-14 and bind there; CI and the nightly run use
309
+ GitHub's 4-core runners, which are not that machine and are declared
310
+ uncalibrated (`MYC_BENCH_ABSOLUTE=0`), so there the absolute numbers are printed
311
+ and logged, not enforced. Measured on 100 000 nodes on 2026-09-11,
312
+ darwin-arm64-14, myc 0.3.6, not re-measured since
313
+ (`bun run scripts/bench-latency.ts`):
170
314
 
171
315
  | operation | p99 | budget |
172
316
  |---|---|---|
173
- | `prime` (session context) | 0.755 ms | 30 ms |
174
- | read | 0.012 ms | 3 ms |
175
- | search | 10.354 ms | 25 ms |
176
- | write | 0.460 ms | 5 ms |
177
- | cold start | 23.820 ms | 60 ms |
317
+ | `prime` (session context) | 0.608 ms | 30 ms |
318
+ | read | 0.010 ms | 3 ms |
319
+ | search | 8.215 ms | 25 ms |
320
+ | write | 0.327 ms | 5 ms |
321
+ | cold start | 21.337 ms | 60 ms |
178
322
 
179
323
  **Ranking is measured, not asserted.** Two labelled corpora with graded
180
324
  relevance, each containing a *control group that gets worse* when the feature
181
- works — so a gain cannot be manufactured by shaping the corpus:
325
+ works — so a gain cannot be manufactured by shaping the corpus (both re-measured
326
+ 2026-09-10):
182
327
 
183
328
  - boosts (priority, freshness, layer): MRR@10 **0.520 → 0.867** (`bench/boost-eval.ts`)
184
329
  - graph expansion to 2 hops: MRR@10 **0.193 → 0.422** (`bench/graph-eval.ts`),
@@ -205,6 +350,29 @@ episode sess-5jh8je4g050m saved (265 B)
205
350
  NEXT myc show sess-5jh8je4g050m · myc ready --claim
206
351
  ```
207
352
 
353
+ **Decisions pulled from a compaction are candidates, not facts.** The same hook
354
+ lifts "we decided / because" lines out of the transcript and stores them as
355
+ candidates (`state pending_review`); recall, search, prime and MCP do not
356
+ return them until someone confirms. `prime` names them in its footer —
357
+ `N pending review hidden — myc review` — and `myc review` lists them, this
358
+ session's first, for a person or an agent to settle. Confirming makes the
359
+ candidate knowledge the way a new note is born (embedding and absorb
360
+ classification queued); rejecting retracts it with the reason kept in the node.
361
+ An agent does the same through MCP: `myc_ready` with `review` lists,
362
+ `myc_update` with `confirm` or `reject` settles; the web knowledge base puts
363
+ the two buttons on the candidate's row.
364
+
365
+ ```
366
+ $ myc review
367
+ PENDING REVIEW 2 · 1 in this session's prime · 1 from other sessions · session 3f9c21aa
368
+ $ myc review confirm memory-6k2x…
369
+ $ myc review reject memory-9x1q… --reason "restates the task, not a decision"
370
+ ```
371
+
372
+ A retracted note — a rejected candidate among them — is out of every retrieval
373
+ path, not only replaced versions: superseded, retracted and cancelled are one
374
+ list shared by recall, prime and the status line.
375
+
208
376
  **A status line with what the agent cannot see.** `myc wire --status-line`
209
377
  puts one line under Claude Code's prompt — how full the context is, the task
210
378
  queue, the code index, the project's memory, and how many of this session's
@@ -233,17 +401,20 @@ project-wide.
233
401
  $ MYC_SESSION_ID=s1 myc recall "retries" $ MYC_SESSION_ID=s2 myc recall "retries"
234
402
  … prj project note: retries use jitter … prj project note: retries use jitter
235
403
  … ses session note: retries back off… … ses* session note: retries back off…
236
- 3 of 3 · bm25 only 3 of 3 · bm25 only · 2 from other sessions
404
+ 3 of 3 · bm25 only · … 3 of 3 · bm25 only · … · 2 from other sessions
237
405
  ```
238
406
 
239
407
  **Memory has three independent axes**, and the surface says what it hid:
240
408
  tier (project vs personal), session reach, repository reach. `prime` prints
241
- `N notes from other repositories hidden` rather than quietly narrowing results.
409
+ `N from other sessions hidden` and `N notes from other repos hidden` rather
410
+ than quietly narrowing results.
242
411
 
243
412
  **Degradation is loud.** No silent fallbacks: when the vector branch is
244
413
  unavailable the output says so and marks the answer as lexical-only; when a
245
414
  budget is exceeded it is named with the number. The invariant is that a
246
- degraded answer must never be indistinguishable from a healthy one.
415
+ degraded answer must never be indistinguishable from a healthy one. With
416
+ `--strict` a degraded answer also exits with code 6 instead of 0, and the
417
+ `WARN` line still prints.
247
418
 
248
419
  **Multi-machine sync through plain git, merged per field.** Only the oplog is
249
420
  committed. Two machines editing the same node converge: one changes title and
@@ -251,91 +422,48 @@ priority, the other title and tags — after exchange both show the later title,
251
422
  the first machine's priority and the second's tags. Nothing is lost to
252
423
  last-writer-wins over whole records.
253
424
 
254
- **Migration from beads is real, not a demo.** A working project imported in
255
- 889 ms: 796 tasks, 972 dependencies, 265 notes, 41 memories — with unknown
256
- issue types carried over verbatim and named, and out-of-range priorities
257
- clamped and named, instead of one odd row aborting the import. On that same
258
- graph both queues now return the same 152 tasks. They did not always: myc used
259
- to offer 195 against beads' 144, because beads inherits blockers down the
260
- parent chain and myc looked only at a task's own. Those 51 were inside a
261
- still-blocked epic and beads was right to hide them; `memory-atcm254ry6c7` is
262
- closed, `anc_blockers` is materialised by trigger, and the queue now says
263
- `281 blocked (51 through an ancestor)` rather than quietly offering them.
264
-
265
425
  **Guards are proved by mutation.** Every refusal and every invariant is
266
426
  accompanied by a mutation that removes it; a guard whose removal breaks no test
267
- is treated as absent.
268
-
269
- ## Roadmap
427
+ is treated as absent. The full suite: 3625 pass / 0 fail / 16 skip
428
+ (`bun test`, 2026-09-11).
270
429
 
271
- Numbers are closed/total subtasks per milestone (`myc show <epic-id>`), as of
272
- 2026-09-10. Done and not-done are shown the same way on purpose. Totals grow
273
- when work uncovers work: M0 went 33 → 39 because measuring it found four real
274
- defects, not because the plan changed.
275
-
276
- | milestone | status |
277
- |---|---|
278
- | **M0** core and tasks | 40 / 43 |
279
- | **M0.5** self-hosting (myc developed through myc) | **4 / 4 — closed** |
280
- | **M1** memory | 22 / 24 |
281
- | **M2** semantics | 20 / 22 |
282
- | **M7** human interface (board, cards, threads, routing panel, status line) | **15 / 15** |
283
- | **M3** code intelligence | 6 / 10 |
284
- | **M4** team: `myc serve`, ACL, network sync, Postgres, containers | 3 / 14 |
285
- | **M5** swarm self-learning: routing by cost and outcome | 0 / 13 |
286
- | **M6** distillation | 0 / 7 |
287
-
288
- What that means in practice: **today myc is a single-user local tool over files
289
- in git.** There is no server, no ACL and no team mode. Those are designed
290
- (`docs/design/03…`, `04…`, `05…`) and tracked, not implemented.
430
+ ## What myc does
291
431
 
292
- Code intelligence is built in, and it is the same engine the alternatives use:
293
- tree-sitter, with grammars fetched on demand rather than shipped. Symbols,
294
- callers and code search work for TypeScript, TSX, JavaScript (js, jsx, mjs,
295
- cjs) and Python the languages myc has definition rules for. The grammar
296
- package holds 36; a language is added as a pair, a rule and a catalog entry,
297
- so a grammar that would yield no symbols is never offered. Every other file
298
- still gets `code grep`, anchors and staleness. `myc code index` builds it on this repository,
299
- 826 files and 3 949 symbols in 904 ms — and four commands read it:
432
+ Tasks with leases, dependencies and blockers inherited down the parent chain;
433
+ memory that survives compaction and is scoped by session and repository;
434
+ ranked hybrid search; the code index above; hooks and MCP for four agents;
435
+ the machine-wide queue for heavy commands; the status line; import from beads;
436
+ a local web interface (`myc viz`: graph, queue, board, cards, search, health
437
+ edits go through the same write path as the CLI); git worktrees and nested
438
+ repositories; sync through git and a `doctor` that compares claims with a
439
+ recount.
300
440
 
301
- ```
302
- myc code symbol <name> where it is defined, and what knowledge is anchored there
303
- myc callers <name> who calls it; --direction out, --depth all
304
- myc code search "…" by meaning, when you do not know the name
305
- myc code grep "<lit>" exhaustive, every occurrence; --in <path> narrows it
306
- myc skeleton <file> the file's API — 26× cheaper than reading it
307
- ```
441
+ The full list — each capability with the release it arrived in and a command
442
+ that shows it on your machine, every command checked against this build's
443
+ `--help` when the site is built is on the site:
444
+ <https://aistastudio.github.io/myc/#features>.
308
445
 
309
- The file list is git's own (`git ls-files`, so `.gitignore` applies; a tree
310
- without git is walked, and the command says so). On top of any list,
311
- secret-named files are never indexed, whatever `.gitignore` says: `.env` and
312
- `.env.*` (templates like `.env.example` are indexed), `*.pem`, `*.key`,
313
- keystores, private SSH keys, `.npmrc`, `.netrc` and other credential files —
314
- `code index` counts them without naming them, and `code grep` refuses to read one.
446
+ ## Roadmap
315
447
 
316
- **Nested repositories and git worktrees.** A workspace can be an ecosystem: a
317
- root that is a git repository with independent repositories inside it (not
318
- submodules). It has one code index, built from the root one row per file,
319
- paths like `messaging-server/server/src/x.ts`. From inside a nested
320
- repository every code command answers from that repository's part of the
321
- root index, with paths relative to the repository you are in; from the root
322
- the answers do not change. `myc code index` run inside a nested repository
323
- refreshes its part of the root index instead of building a second copy of the
324
- same files, and so does the background refresh. A git worktree even one
325
- outside the workspace tree is answered from the index of the main checkout:
326
- there is no index per branch. When the worktree is on another commit, or has
327
- uncommitted changes to tracked files, every answer carries
328
- `WARN code_index.worktree_divergent` naming both branches, because lines and
329
- spans may not match your files. `code grep` reads the worktree's files (the
330
- line numbers are yours, the owning symbols come from the index); `skeleton`
331
- shows the main copy's declarations when your copy differs from what the index
332
- saw, and says so. When nothing covers the repository, the hint is the command
333
- for the workspace root (`myc -C <root> code index`), not one that would build a
334
- duplicate. Anchors set from the root and from inside a repository are stored
335
- under different keys; `code symbol` reads both.
448
+ Where each milestone stands closed/total subtasks of every epic in the
449
+ project's own tracker, and every task still open inside it, with no dates — is
450
+ on the site: <https://aistastudio.github.io/myc/#planned>. The counts are not
451
+ typed in: `bun run site/roadmap.ts` reads them from myc before a release, and
452
+ the site build refuses a plan that describes a task the tracker no longer has
453
+ open.
454
+
455
+ In short: the core, memory, semantics and the human interface (M0–M2, M7) are
456
+ done or nearly done, and so is English output for every CLI and MCP line; code
457
+ intelligence (M3, including the built-in replacement for graft) and the
458
+ heavy-command queue have shipped, with tasks still open; the team milestone
459
+ (M4: `myc serve`, ACL, network sync, Postgres) is mostly design; swarm
460
+ self-learning (M5: routing by cost and outcome, with a shared pool of agent
461
+ statistics) and distillation (M6) have not started.
336
462
 
337
- Anchors tie knowledge to a span and follow the code as it moves; that half is
338
- language-agnostic and was verified on Python as well as TypeScript.
463
+ What that means in practice: **today myc is a single-user local tool over files
464
+ in git.** There is no server, no ACL and no team mode. Those are designed
465
+ (`docs/design/03-interfaces-and-integration.md`,
466
+ `docs/design/04-swarm-learning-and-routing.md`) and tracked, not implemented.
339
467
 
340
468
  ## Syncing between machines
341
469
 
package/bin/myc.js CHANGED
@@ -28,7 +28,8 @@
28
28
  * после интерпретатора ОДНИМ аргументом. -S есть в GNU coreutils ≥ 8.30 и в
29
29
  * env macOS/BSD. На Windows такой shebang не исполним: шим `bun add -g` берёт
30
30
  * `-S` за программу, а cmd-shim npm -S понимает, но Bun на Windows не
31
- * открывает /dev/null — myc там только через WSL (говорит preflight.js).
31
+ * открывает /dev/null — myc там только через WSL (говорят preflight.js и
32
+ * refusal() ниже, если этот файл всё же запустили под Node).
32
33
  * Запуск МИМО shebang (`bun …/myc.js`) флагов не получает; второй рубеж для
33
34
  * `myc run` — callerEnv в src/commands/run.ts.
34
35
  */
@@ -82,31 +83,44 @@ function resolveVec0() {
82
83
  }
83
84
  }
84
85
 
86
+ /**
87
+ * Текст отказа — по-английски, как весь вывод CLI (эпик memory-rc2s0m1e9kpz).
88
+ * На Windows совет «поставьте Bun» был бы ложным: shebang там не исполним и с
89
+ * Bun (см. шапку и preflight.js), поэтому совет там один — WSL, тем же текстом,
90
+ * что в рамке preflight.js.
91
+ */
85
92
  function refusal() {
86
93
  const node = process.versions.node;
87
94
  const lines = [
88
95
  "",
89
96
  " myc requires Bun — it cannot run on Node.",
90
97
  "",
91
- ` myc запущен под Node ${node}, а он работает только на Bun: хранилище`,
92
- " построено на встроенном в Bun `bun:sqlite`, которого в Node нет.",
98
+ ` This is Node ${node}, and myc runs only on Bun: its storage is built`,
99
+ " on Bun's built-in `bun:sqlite`, which Node does not have.",
93
100
  "",
94
101
  ];
95
- if (bunOnPath()) {
102
+ if (process.platform === "win32") {
103
+ lines.push(
104
+ " myc runs on macOS and Linux; on Windows use WSL.",
105
+ " The `myc` launcher will not start in cmd or PowerShell, with or without Bun.",
106
+ " wsl --install",
107
+ " Then, inside WSL: install Bun and @aistastudio/myc there.",
108
+ "",
109
+ );
110
+ } else if (bunOnPath()) {
96
111
  lines.push(
97
- " Bun у вас установлен запускайте через него:",
98
- " bun x myc <команда>",
99
- " либо переустановите пакет средствами bun:",
112
+ " Bun is installedrun myc through it:",
113
+ " bun x myc <command>",
114
+ " or reinstall the package with bun:",
100
115
  " bun add -g @aistastudio/myc",
101
116
  "",
102
117
  );
103
118
  } else {
104
119
  lines.push(
105
- " Установите Bun (>= 1.3.0) и повторите:",
120
+ " Install Bun (>= 1.3.0) and try again:",
106
121
  " curl -fsSL https://bun.sh/install | bash # macOS, Linux, WSL",
107
- ' powershell -c "irm bun.sh/install.ps1 | iex" # Windows',
108
122
  "",
109
- " После установки: myc --version",
123
+ " Then: myc --version",
110
124
  "",
111
125
  );
112
126
  }
package/bin/preflight.js CHANGED
@@ -38,14 +38,15 @@ if (process.platform === "win32") {
38
38
  ]),
39
39
  );
40
40
  } else if (typeof process.versions.bun !== "string" && !bunOnPath()) {
41
+ // По-английски, как весь вывод CLI (эпик memory-rc2s0m1e9kpz).
41
42
  process.stderr.write(
42
- frame("@aistastudio/myc установлен, но запускаться пока не будет", [
43
- "myc работает только на Bun (хранилище на bun:sqlite).",
44
- "Bun в системе не найден.",
43
+ frame("@aistastudio/myc is installed, but it will not start yet", [
44
+ "myc runs only on Bun (its storage is bun:sqlite).",
45
+ "Bun was not found on this system.",
45
46
  "",
46
47
  " curl -fsSL https://bun.sh/install | bash",
47
48
  "",
48
- "После этого: myc --version",
49
+ "Then: myc --version",
49
50
  ]),
50
51
  );
51
52
  }