Skip to content

Releases: Datata1/mycelium

v5.0.1

Choose a tag to compare

@github-actions github-actions released this 19 May 07:30

Changelog

All notable changes to this project are documented here. Format follows
Keep a Changelog; the project adheres
to Semantic Versioning.

[v4.0.0] — 2026-05-18

v4.0 — Adoption fixed-point + bug triage

Tickets under tickets/v4-*.md. v4 focuses on adoption quality:
making the existing tools work reliably on real codebases. The three
themes are (1) adoption-health observability (B1–B3), (2) bug triage
from the first TS field test (T1–T7), and (3) the get_references
class-symbol fix. No new languages, no new symbol kinds — Rust
and route literals are deferred to v5. No new architectural pillars.
See LIMITATIONS.md for what stays out of scope.

Fixed

  • get_references(ClassName) now includes static and instance method
    calls.
    The TS resolver resolves CsEnv.from() to the method symbol
    (env.CsEnv.from), not the class symbol (env.CsEnv). Previously
    symbolsByTarget only matched the target's own qualified name, so
    get_references("CsEnv") missed all CsEnv.from() / CsEnv.empty()
    call sites. Fix: after collecting direct matches, a second pass
    expands each qualified name to its children via LIKE q+".%", then
    deduplicates. Regression test in get_refs_test.go with fixture
    testdata/fixtures/get-refs/ (reproduces the codesphere monorepo-4
    finding where 3/3 get_references calls returned null on a class
    used only through static-method calls).

  • F1 follow-up batch (T3-T7): five smaller field-test fixes.

    • T3 — search_lexical ergonomics. Three changes: empty results
      return []LexicalHit{} not nil (JSON consumers see [] instead
      of null, distinguishable from "tool errored"); regex compile
      errors gain an actionable hint ("Go regexp syntax: |, ., [], (?i)
      all supported"); the path-eliminate-all error message suggests
      omitting the filter; the daemon logs a one-line stderr hint when
      path_contains narrowed the candidate set but no hits surfaced
      (debuggable signal in myco daemon output).
    • T4 — adaptive corpus for bench-counterfactual. New
      bench.BuildAdaptiveCorpus(client) probes the daemon
      (list_files → pick the heaviest indexed file by symbol_count
      get_file_outline → pick the first non-trivial symbol) to
      construct a corpus targeting REAL symbols + files in any
      indexed repo. New --adaptive flag opts in. When --repo is
      passed without --adaptive and every row fails, the bench
      prints a concrete hint: "the default corpus is mycelium-tuned;
      re-run with --adaptive". Closes the F1/T4 silent-DRIFT case.
    • T5 — counterfactual gates on success. Summary.OutputBytesOK
      new field tracks bytes from successful calls only. Aggregator
      changes counterfactual basis from OutputBytes to
      OutputBytesOK so a find_symbol that returned null (4-14
      bytes for the failed envelope) doesn't earn savings credit.
      F1's session showed -0.1% savings because failed myco calls
      diluted the math; post-fix the model is honest — failed calls
      contribute zero to the without-myco estimate, so savings goes
      appropriately negative when myco failed and the agent paid the
      fallback anyway. Backward-compat shim: when OutputBytesOK == 0
      AND OK == Count, falls back to OutputBytes so v3.4-shape
      fixtures continue to work.
    • T6 — top-level myco find and myco search aliases. Users
      (and agents) typed myco find symbol WorkspacePlan and
      myco search "WorkspacePlan|plans" during F1 — both errored
      because the actual subcommands are buried under myco query.
      Two new top-level cobra commands delegate to the existing
      runQueryFind / runQueryLexical so reflexive command names
      just work. myco find also aliases as find-symbol;
      myco search aliases as grep. The original myco query find
      / myco query grep keep working unchanged.
    • T7 — strip IDE wrapper tags from session "Task" field. A
      session that begins with an IDE-injected <ide_opened_file>...
      or <system-reminder>... block used to surface that tag-soup
      as the session's task description in myco session export.
      Now parseTranscriptReader skips messages whose body is
      exclusively a wrapper tag (<ide_opened_file>, <ide_selection>,
      <system-reminder>, <command-name>, <local-command-stdout>)
      and falls through to the next user message. Mixed-content
      messages (wrapper + prose) keep their content. Nine-case unit
      test pins the heuristic.

    All five land in one bundle because each is small and they
    collectively complete the F1 v4 P0+P1+P2 follow-ups. T3 ergonomics

    • T4 adaptive corpus + T5 counterfactual honesty are the load-
      bearing fixes; T6 + T7 are usability polish.
  • Daemon fd-leak on large repos (F1/T2 EMFILE). Codesphere
    monorepo-4 (3079 files, 49 packages) hit too many open files
    on macOS during a real session because fsnotify consumes one fd
    per watched directory and the macOS default RLIMIT_NOFILE soft
    limit is 256. Three-layer fix:

    1. Layer 3 (the real fix): bump RLIMIT_NOFILE to hard at
      daemon startup.
      New internal/daemon/RaiseFileDescriptorLimit()
      is called in runDaemon before any fd-consuming code runs.
      macOS goes 256 → ~10240 (40× headroom); Linux goes 1024 →
      ~1048576 (1024× headroom). Verified live: daemon now logs
      [daemon] RLIMIT_NOFILE raised to 1048576 (hard cap 1048576)
      on startup. macOS quirk handled: when Setrlimit to hard fails
      (kernel kern.maxfilesperproc cap), we step down through
      {10240, 4096, 2048, 1024} and accept whichever the kernel
      allows. Failure is non-fatal (warning logged, daemon continues
      at original limit). Windows is a no-op (per-process handle
      limit is 16M+, not a real constraint). Build-tagged
      rlimit_unix.go + rlimit_other.go for portability.

    2. Layer 1 (diagnostic): daemon_fd_headroom doctor check.
      New internal/doctor/fd_headroom_linux.go reads the daemon's
      PID file (newly written by runDaemon) and probes
      /proc/<pid>/fd + /proc/<pid>/limits to surface fd-headroom
      pressure before EMFILE hits. WARN at 60% utilisation, FAIL at
      90% (Thresholds.FDHeadroomWarn / FDHeadroomFail). Skips
      gracefully on missing pid file (daemon not running), stale pid
      (daemon died without cleanup), or unreadable /proc
      (sandboxed environments). Linux-only; fd_headroom_other.go
      is a no-op stub on macOS / Windows because counting another
      process's fds requires lsof (sub-process, brittle) or
      platform-specific syscalls — and on macOS the layer 3 setrlimit
      bump preempts the EMFILE case anyway, so the check is less
      load-bearing there. Three unit tests cover the no-pid-file,
      stale-pid, and real-process paths.

    3. Layer 2 (already shipped): Watchman backend. Inventory
      during T2 work showed internal/watch/watchman/ is fully
      implemented (1477 LOC, opt-in via watcher.backend: watchman
      in .mycelium.yml since v1.7). Users with monorepos beyond
      even Layer 3's headroom set the config flag and watchman takes
      over. The existing inotify_headroom doctor check already
      points at this path; no changes needed.

    Daemon also writes .mycelium/daemon.pid on startup (best-effort,
    cleaned up on shutdown via defer) so the doctor check has
    something to probe. Not exposed as a public API — implementation
    detail of T2 layer 1.

    Closes the F1/T2 blocker. Phase 2 field tests can now run on
    monorepo-scale repos without hitting the macOS 256-fd cap; Linux
    users get a doctor warning before crossing 60% utilisation.

  • TypeScript .d.ts indexing — the F1/T1 adoption blocker. The
    default include glob was src/**/*.{ts,tsx} which narrowed TS
    coverage to files inside src/. Codesphere monorepo-4's field
    test surfaced this: find_symbol{name: "WorkspacePlan"} returned
    null because the type is defined in
    packages/payment-service/common/lib/Product.d.ts
    outside src/, never walked. Default include broadened to
    **/*.{ts,tsx,d.ts,mts,cts} so all common TS source locations
    (package roots, lib/, ambient declarations, test config files)
    are picked up; compiled outputs continue to be excluded by
    **/dist/** / **/build/**. Wizard inherits via config.Default()
    — no separate template change needed.

    Also fixed the moduleName qualifier for .d.ts files: previously
    Product.d.ts produced symbols qualified as Product.d.WorkspacePlan
    (the .d suffix wasn't stripped), now strips .d.ts / .d.mts /
    .d.cts as a unit so qualified names match the source file
    (Product.d.tsProduct.WorkspacePlan). Pure rename — symbol
    identity / refs continue to resolve.

    New fixture testdata/fixtures/sample/src/types.d.ts mirrors the
    monorepo-4 shape: interface WorkspacePlan, type WorkspacePlanMap,
    type PlanSelector, enum PlanTier, declare module. New
    integration test find_symbol_in_d_ts_v4_T1_fix asserts each
    shape returns from find_symbol. Existing stats and list_files
    expected file count bumped from 3 → 4 to include the new fixture.
    task check green; myco bench-counterfactual continues to pass
    (unrelated surface). Closes the F1/T1 blocker; Phase 2 Python
    field test (planned) will replicate the fixture for .pyi stub
    files.

Added

  • B3 — multi-repo bench-counterfactual harness. The bench-counterfactual
    corpus + runner moved out of cmd/myco/main.go into a new
    internal/bench/ package: Case, Corpus, Row types,
    MyceliumDefaultCorpus() returning the v3.4-calibrated mycelium-self
    corpus, Run(client, repoRoot, corpus, language, driftThreshold)
    the orchestrator, PrintTable(rows, threshold, corpusName, language)
    the renderer. The CLI command shrinks to a thin flag-parsing
    or...
Read more

v5.0.0

Choose a tag to compare

@github-actions github-actions released this 19 May 07:29

Changelog

All notable changes to this project are documented here. Format follows
Keep a Changelog; the project adheres
to Semantic Versioning.

[v4.0.0] — 2026-05-18

v4.0 — Adoption fixed-point + bug triage

Tickets under tickets/v4-*.md. v4 focuses on adoption quality:
making the existing tools work reliably on real codebases. The three
themes are (1) adoption-health observability (B1–B3), (2) bug triage
from the first TS field test (T1–T7), and (3) the get_references
class-symbol fix. No new languages, no new symbol kinds — Rust
and route literals are deferred to v5. No new architectural pillars.
See LIMITATIONS.md for what stays out of scope.

Fixed

  • get_references(ClassName) now includes static and instance method
    calls.
    The TS resolver resolves CsEnv.from() to the method symbol
    (env.CsEnv.from), not the class symbol (env.CsEnv). Previously
    symbolsByTarget only matched the target's own qualified name, so
    get_references("CsEnv") missed all CsEnv.from() / CsEnv.empty()
    call sites. Fix: after collecting direct matches, a second pass
    expands each qualified name to its children via LIKE q+".%", then
    deduplicates. Regression test in get_refs_test.go with fixture
    testdata/fixtures/get-refs/ (reproduces the codesphere monorepo-4
    finding where 3/3 get_references calls returned null on a class
    used only through static-method calls).

  • F1 follow-up batch (T3-T7): five smaller field-test fixes.

    • T3 — search_lexical ergonomics. Three changes: empty results
      return []LexicalHit{} not nil (JSON consumers see [] instead
      of null, distinguishable from "tool errored"); regex compile
      errors gain an actionable hint ("Go regexp syntax: |, ., [], (?i)
      all supported"); the path-eliminate-all error message suggests
      omitting the filter; the daemon logs a one-line stderr hint when
      path_contains narrowed the candidate set but no hits surfaced
      (debuggable signal in myco daemon output).
    • T4 — adaptive corpus for bench-counterfactual. New
      bench.BuildAdaptiveCorpus(client) probes the daemon
      (list_files → pick the heaviest indexed file by symbol_count
      get_file_outline → pick the first non-trivial symbol) to
      construct a corpus targeting REAL symbols + files in any
      indexed repo. New --adaptive flag opts in. When --repo is
      passed without --adaptive and every row fails, the bench
      prints a concrete hint: "the default corpus is mycelium-tuned;
      re-run with --adaptive". Closes the F1/T4 silent-DRIFT case.
    • T5 — counterfactual gates on success. Summary.OutputBytesOK
      new field tracks bytes from successful calls only. Aggregator
      changes counterfactual basis from OutputBytes to
      OutputBytesOK so a find_symbol that returned null (4-14
      bytes for the failed envelope) doesn't earn savings credit.
      F1's session showed -0.1% savings because failed myco calls
      diluted the math; post-fix the model is honest — failed calls
      contribute zero to the without-myco estimate, so savings goes
      appropriately negative when myco failed and the agent paid the
      fallback anyway. Backward-compat shim: when OutputBytesOK == 0
      AND OK == Count, falls back to OutputBytes so v3.4-shape
      fixtures continue to work.
    • T6 — top-level myco find and myco search aliases. Users
      (and agents) typed myco find symbol WorkspacePlan and
      myco search "WorkspacePlan|plans" during F1 — both errored
      because the actual subcommands are buried under myco query.
      Two new top-level cobra commands delegate to the existing
      runQueryFind / runQueryLexical so reflexive command names
      just work. myco find also aliases as find-symbol;
      myco search aliases as grep. The original myco query find
      / myco query grep keep working unchanged.
    • T7 — strip IDE wrapper tags from session "Task" field. A
      session that begins with an IDE-injected <ide_opened_file>...
      or <system-reminder>... block used to surface that tag-soup
      as the session's task description in myco session export.
      Now parseTranscriptReader skips messages whose body is
      exclusively a wrapper tag (<ide_opened_file>, <ide_selection>,
      <system-reminder>, <command-name>, <local-command-stdout>)
      and falls through to the next user message. Mixed-content
      messages (wrapper + prose) keep their content. Nine-case unit
      test pins the heuristic.

    All five land in one bundle because each is small and they
    collectively complete the F1 v4 P0+P1+P2 follow-ups. T3 ergonomics

    • T4 adaptive corpus + T5 counterfactual honesty are the load-
      bearing fixes; T6 + T7 are usability polish.
  • Daemon fd-leak on large repos (F1/T2 EMFILE). Codesphere
    monorepo-4 (3079 files, 49 packages) hit too many open files
    on macOS during a real session because fsnotify consumes one fd
    per watched directory and the macOS default RLIMIT_NOFILE soft
    limit is 256. Three-layer fix:

    1. Layer 3 (the real fix): bump RLIMIT_NOFILE to hard at
      daemon startup.
      New internal/daemon/RaiseFileDescriptorLimit()
      is called in runDaemon before any fd-consuming code runs.
      macOS goes 256 → ~10240 (40× headroom); Linux goes 1024 →
      ~1048576 (1024× headroom). Verified live: daemon now logs
      [daemon] RLIMIT_NOFILE raised to 1048576 (hard cap 1048576)
      on startup. macOS quirk handled: when Setrlimit to hard fails
      (kernel kern.maxfilesperproc cap), we step down through
      {10240, 4096, 2048, 1024} and accept whichever the kernel
      allows. Failure is non-fatal (warning logged, daemon continues
      at original limit). Windows is a no-op (per-process handle
      limit is 16M+, not a real constraint). Build-tagged
      rlimit_unix.go + rlimit_other.go for portability.

    2. Layer 1 (diagnostic): daemon_fd_headroom doctor check.
      New internal/doctor/fd_headroom_linux.go reads the daemon's
      PID file (newly written by runDaemon) and probes
      /proc/<pid>/fd + /proc/<pid>/limits to surface fd-headroom
      pressure before EMFILE hits. WARN at 60% utilisation, FAIL at
      90% (Thresholds.FDHeadroomWarn / FDHeadroomFail). Skips
      gracefully on missing pid file (daemon not running), stale pid
      (daemon died without cleanup), or unreadable /proc
      (sandboxed environments). Linux-only; fd_headroom_other.go
      is a no-op stub on macOS / Windows because counting another
      process's fds requires lsof (sub-process, brittle) or
      platform-specific syscalls — and on macOS the layer 3 setrlimit
      bump preempts the EMFILE case anyway, so the check is less
      load-bearing there. Three unit tests cover the no-pid-file,
      stale-pid, and real-process paths.

    3. Layer 2 (already shipped): Watchman backend. Inventory
      during T2 work showed internal/watch/watchman/ is fully
      implemented (1477 LOC, opt-in via watcher.backend: watchman
      in .mycelium.yml since v1.7). Users with monorepos beyond
      even Layer 3's headroom set the config flag and watchman takes
      over. The existing inotify_headroom doctor check already
      points at this path; no changes needed.

    Daemon also writes .mycelium/daemon.pid on startup (best-effort,
    cleaned up on shutdown via defer) so the doctor check has
    something to probe. Not exposed as a public API — implementation
    detail of T2 layer 1.

    Closes the F1/T2 blocker. Phase 2 field tests can now run on
    monorepo-scale repos without hitting the macOS 256-fd cap; Linux
    users get a doctor warning before crossing 60% utilisation.

  • TypeScript .d.ts indexing — the F1/T1 adoption blocker. The
    default include glob was src/**/*.{ts,tsx} which narrowed TS
    coverage to files inside src/. Codesphere monorepo-4's field
    test surfaced this: find_symbol{name: "WorkspacePlan"} returned
    null because the type is defined in
    packages/payment-service/common/lib/Product.d.ts
    outside src/, never walked. Default include broadened to
    **/*.{ts,tsx,d.ts,mts,cts} so all common TS source locations
    (package roots, lib/, ambient declarations, test config files)
    are picked up; compiled outputs continue to be excluded by
    **/dist/** / **/build/**. Wizard inherits via config.Default()
    — no separate template change needed.

    Also fixed the moduleName qualifier for .d.ts files: previously
    Product.d.ts produced symbols qualified as Product.d.WorkspacePlan
    (the .d suffix wasn't stripped), now strips .d.ts / .d.mts /
    .d.cts as a unit so qualified names match the source file
    (Product.d.tsProduct.WorkspacePlan). Pure rename — symbol
    identity / refs continue to resolve.

    New fixture testdata/fixtures/sample/src/types.d.ts mirrors the
    monorepo-4 shape: interface WorkspacePlan, type WorkspacePlanMap,
    type PlanSelector, enum PlanTier, declare module. New
    integration test find_symbol_in_d_ts_v4_T1_fix asserts each
    shape returns from find_symbol. Existing stats and list_files
    expected file count bumped from 3 → 4 to include the new fixture.
    task check green; myco bench-counterfactual continues to pass
    (unrelated surface). Closes the F1/T1 blocker; Phase 2 Python
    field test (planned) will replicate the fixture for .pyi stub
    files.

Added

  • B3 — multi-repo bench-counterfactual harness. The bench-counterfactual
    corpus + runner moved out of cmd/myco/main.go into a new
    internal/bench/ package: Case, Corpus, Row types,
    MyceliumDefaultCorpus() returning the v3.4-calibrated mycelium-self
    corpus, Run(client, repoRoot, corpus, language, driftThreshold)
    the orchestrator, PrintTable(rows, threshold, corpusName, language)
    the renderer. The CLI command shrinks to a thin flag-parsing
    or...
Read more

v3.0.0-rc6

Choose a tag to compare

@github-actions github-actions released this 27 Apr 19:02

Changelog

All notable changes to this project are documented here. Format follows
Keep a Changelog; the project adheres
to Semantic Versioning.

[Unreleased]

Added

  • v3.0-rc polish + docs. Canonicalises the docs/ layout (the
    old root RESEARCH.md moves to docs/research.md and gains a
    design-decision crosswalk plus a "read but not acted on" section),
    rewrites the README around the v3 agent-native story (skills tree
    and focused reads as the headline; structural MCP tools demoted
    to "for programmatic use") while leaving the project header /
    badges untouched, ships docs/adoption.md as a guide to verifying
    agent uptake via the v2.2 telemetry log, and adds a navigation
    integration test (navigation_integration_test.go) that
    mechanises docs/navigation-example.md so the
    INDEX.md → SKILL.md → read_focused path is enforced in CI.
    Release tarballs now bundle the matching sqlite-vec shared library
    next to the binary, and index.OpenWithExtension auto-discovers
    it when index.vector.extension_path is left empty in
    .mycelium.yml — semantic search at scale is now zero-config on
    release builds.
  • Incremental skills regeneration (Pillar H, v2.5 in the v3 plan).
    The v2.3 skills tree gets a hash gate: every rendered file (per-
    package SKILL.md, per-aspect INDEX.md, root INDEX.md) is hashed
    before write; if skill_files.skill_hash matches, the WriteFile and
    store update are both skipped. New migration 0006_skills.sql
    introduces the skill_files table; new internal/index helpers
    (SkillFileHash, UpsertSkillFile, DeleteSkillFile,
    PruneSkillFiles, ListSkillFiles) satisfy a small skills.Store
    interface so the renderer stays storage-agnostic. Compile grows
    Options.Store, Options.Stats, Options.DryRun; passing a Store
    enables hash-gated writes, and Stats reports Rendered / Written / Skipped / Pruned. The wall-clock generated: frontmatter line is
    stripped from the hash input so two renders of the same structural
    content produce the same hash regardless of when they ran — without
    this the gate would fire on every daemon batch and defeat the
    whole milestone.
  • Daemon-driven incremental regen. New Daemon.SkillsRegen func(ctx, packages []string) error field plus a debounced batcher in
    the watcher event loop: every path.Dir(relPath) from
    Pipeline.HandleChange is collected into a dedup set, and after
    SkillsDebounce (default 200ms) of channel idle the batch is
    flushed to a worker goroutine that calls SkillsRegen exactly once.
    A second worker serialises regen calls so two bursts can't race on
    the same .mycelium/skills/ tree. cmd/myco daemon wires
    SkillsRegen to skills.RegenerateAffected only when
    .mycelium/skills/ already exists, so users who never opted into
    the skills feature aren't surprised by a regenerated tree.
    RegenerateAffected for v2.5 is a thin wrapper over Compile with
    the Store set: the per-render cost is ~100ms on the self-index and
    the hash gate makes the actual write cost zero on a clean tree, so
    fully exploiting per-package short-circuiting was deferred — the
    packages slice is captured for telemetry and reserved for a future
    optimisation hook.
  • skills_coverage doctor metric. New Stats.SkillsPackagesIndexed
    (distinct directories holding indexed files) plus a filesystem walk
    in internal/doctor that counts present SKILL.md files under
    .mycelium/skills/packages/. Coverage = on-disk / indexed; pass at
    ≥ 0.95, warn below, fail below 0.5. Skipped when the skills dir
    doesn't exist (opt-in feature, not a regression). Walking the
    filesystem rather than reading skill_files catches the case where
    the DB row outlives the file on disk.
  • myco skills compile --status and --incremental flags.
    --status runs the renderer in DryRun mode against the live
    skill_files hashes and reports rendered / unchanged / would change without touching disk or the DB. --incremental is the
    hash-gated equivalent of compile: it writes only the files whose
    rendered bytes differ and prints the same per-call counters the
    daemon logs.

Measured

  • v2.5 hash gate on the self-index (Tiger Lake, 105 files / 30
    packages / 35 rendered files).
    Cold compile: 35 rendered, 35
    written, ~100ms. Warm compile (no source changes): 35 rendered, 0
    written, 35 skipped, ~70ms. Single-symbol change (added one
    top-level func): 35 rendered, 6 written, 29 skipped — the changed
    package + root INDEX.md + four aspect indices. Pure-formatting
    source change (added a blank line to a comment): 35 rendered, 0
    written, 35 skipped — the index hash didn't move, so neither did
    the SKILL.md hash.

  • Focused reads (Pillar I, v2.4 in the v3 plan). New
    internal/focus package implements the deterministic lexical filter
    promised by the v3 roadmap: tokenize a focus string (lowercase,
    stopword-strip), then score candidates against name (3.0 exact / 2.0
    substring), qualified name (2.0 substring), docstring (1.0
    substring), and ref targets (0.5 substring). Pure Go, no neural
    model — we adopt the SWE-Pruner pattern but explicitly not the
    mechanism, so the single-static-binary distribution story holds.
    Wired into three existing reader methods as an optional focus
    param: FindSymbol drops non-matchers and re-ranks survivors by
    score; GetFileOutline keeps top-level items whose subtree
    contains any match; GetNeighborhood prunes nodes outside the
    focus and surfaces a focus filter pruned N node(s) note. Empty
    focus is byte-identical to prior behaviour — verified by the
    pre-existing integration suite.

  • read_focused MCP tool / myco read CLI. New top-level read
    primitive that returns one indexed file with non-focus-matching
    symbols collapsed to one-line markers in the file's native
    comment style (// signature ... // collapsed (lines N-M) for
    Go/TS/JS, # ... for Python). Empty focus returns the file in
    full, so the tool also functions as a daemon-mediated cat when
    the agent isn't sure how big the file is. Multi-line signatures
    (Go interface bodies, struct definitions) are flattened to their
    first line with appended so the marker stays single-line.
    Response carries a Stats { TotalSymbols, ExpandedSymbols, OriginalBytes, ReturnedBytes } block plus an Expanded list of
    surviving symbols with their original [StartLine, EndLine] ranges
    so agents can map back to source. Wire-up: new Focus field on
    FindSymbolParams/GetFileOutlineParams/GetNeighborhoodParams,
    new ReadFocusedParams + MethodReadFocused, daemon dispatch,
    MCP tool schema entry, HTTP route auto-derived from the
    dispatcher, --focus flag on myco query find|outline|neighbors,
    and myco read <path> --focus "<q>" (with --stats for the
    collapse counters on stderr).

Measured

  • read_focused byte reduction (self-index, Tiger Lake). Three
    representative queries on this repo:

    file focus returned/original reduction
    cmd/myco/main.go (44 KB) "telemetry recorder" 8443 / 44337 81%
    cmd/myco/main.go (44 KB) "skills compile" 8909 / 44337 80%
    internal/daemon/daemon.go (9 KB) "dispatch read_focused" 6540 / 9163 29%
    Results vary with focus specificity and file shape — large files
    with many independent symbols collapse aggressively, small dense
    files less so. We're explicitly not claiming SWE-Pruner's 23–54%
    range against a trained reranker; the lexical filter trades
    precision for distribution simplicity.
  • Static skills tree (Pillar L, v2.3 in the v3 plan). New
    internal/skills package + myco skills compile CLI generate a
    deterministic Markdown tree under .mycelium/skills/ that an agent
    can navigate with only the Read tool. Layout: per-package
    SKILL.md (one per directory of source, language unified for
    mixed-language directories), root INDEX.md listing every package,
    and an aspects/ subtree with four cross-cutting filters
    (error-handling, context-propagation — clean signature matches;
    config-loading, logging — heuristic ref-driven, frontmatter-flagged).
    Output is language: complementary to MCP — SKILL.md is lean
    (≤~160 lines on the largest mycelium package), points the reader at
    myco query refs/neighbors for specifics. New reader helpers
    (*query.Reader).PackageRefAggregates,
    SymbolsBySignatureLike, SymbolsByOutboundRef keep the "query is
    the only reader" rule intact. --package and --aspect flags
    scope regen for fast iteration; both correctly skip everything
    outside their scope. Self-dogfood on the mycelium repo: 28 packages
    / 88 files / 589 symbols, full tree compiles in ~52ms; tree
    gitignored as a sibling of index.db. Incremental hash-gated
    regeneration is v2.5.

  • Opt-in telemetry log (Pillar K, v2.2 in the v3 plan). New
    internal/telemetry package with a Recorder interface and a
    JSONL FileRecorder. Off by default; enabled via
    telemetry: { enabled: true } in .mycelium.yml. When on, the
    daemon dispatcher in internal/daemon/daemon.go records one line
    per IPC/MCP call to .mycelium/telemetry.jsonl (timestamp, tool
    name, input bytes, output bytes, wall-clock ms, ok). No network,
    no aggregation off-host — purely a local file the user can
    tail -f. Open failure falls back to Disabled so observability
    never gates daemon startup.

  • myco stats --telemetry aggregator: streams the JSONL log and
    prints per-tool counts, byte totals, and p50/p95 durations, plus
    an all rollup. Friendly hints when telemetry is off in config or
    when no records exist yet, so users who flipped the flag but
    haven't generated traffic understand what they're seeing.

Fixed

  • sqlite-vec extension entrypoint. LoadExtension was being called
    with an empty...
Read more

v2.0.0-rc1

Choose a tag to compare

@github-actions github-actions released this 24 Apr 19:41

Changelog

All notable changes to this project are documented here. Format follows
Keep a Changelog; the project adheres
to Semantic Versioning.

[Unreleased]

[v2.0.0-rc1] — 2026-04-24

First release candidate for v2.0 ("precision and scale"). No new
functional changes since v1.7; this tag consolidates the v1.1 → v1.7
series into a single release and gates the remaining v2.0 work.
Per-milestone details remain in the sections below.

Delivered against the v2.0 acceptance criteria

  • Type-aware references for Go, TypeScript, Python. Self-index
    reports self_loop_count = 0, unresolved_ref_ratio = 0.0%.
    (v1.2, v1.3)
  • Workspace mode: one daemon, one SQLite, N sub-projects with
    per-project config and optional project filter on every query
    tool. (v1.5)
  • Graph-native tools: impact_analysis, critical_path. (v1.6)
  • PR-scoped queries: --since <ref> on five read methods. (v1.6)
  • Doctor + quality signals: myco doctor exits 0/1/2 on
    pass/warn/fail with configurable thresholds. (v1.1, v1.2, v1.7)
  • Watchman opt-in behind watcher.backend. (v1.7)
  • sqlite-vec integration compiled in; brute-force fallback
    measured. (v1.4)

Architectural invariants from v1.0 are preserved: SQLite is still
source of truth and query engine; internal/query is the sole
reader; internal/pipeline is the sole writer; no new top-level
processes; all schema changes are additive.

Known gaps before the final v2.0 tag

  • sqlite-vec p95 unmeasured. The vec0 code path compiles on
    every release target but the "p95 < 50ms at 100k chunks"
    benchmark from the roadmap has not been run on a machine with
    the extension installed. Brute-force numbers on Tiger Lake
    (768 dims): 114ms / 555ms / 1100ms at 10k / 50k / 100k.
  • libsqlite_vec.{so,dylib,dll} not bundled in the release
    tarball. Users install sqlite-vec manually per the README.
  • No 100k+ file monorepo validation. myco doctor,
    workspace mode, and the inotify-headroom check have only been
    exercised against the self-index and the committed fixtures.

[v1.7.0] — 2026-04-24

"Watchman opt-in" — the seventh v2.0 milestone (Pillar G). Pluggable
watcher backend so users on 100k+ file repos can escape the
fs.inotify.max_user_watches ceiling without changing anything
else about how mycelium runs.

Added

  • internal/watch/watchman/ — minimal in-tree watchman client.
    Talks JSON-over-unix-socket: get-sockname, watch-project,
    subscribe, unsubscribe. Read pump demultiplexes command
    responses vs subscription deliveries so one connection handles
    both. $MYCELIUM_WATCHMAN_SOCK overrides sockname discovery for
    container setups.
  • Watcher backend selection. New watcher.backend config field
    ("fsnotify" default, "watchman" opt-in) plus
    myco daemon --watcher-backend <name> CLI override. Unknown
    values are a hard error; watchman unavailability falls back to
    fsnotify with a stderr warning so the daemon still starts.
  • internal/watch restructure. Old monolithic watch.go split
    into watcher.go (public Watcher interface + Options),
    common.go (shared debounce/coalesce/filter wrapper), and
    per-backend sources: fsnotify.go, watchman.go. Both backends
    route through the same wrapper so behavior is identical — the
    two honest-surface bugs the old struct had (unused
    MaxFileSizeKB, unused CoalesceMS) are fixed once, not twice.
  • CoalesceMS is now wired. Bursts of debounced events within
    a coalesce window flush as one batch to the output channel.
  • Doctor: inotify_headroom check. Linux-only. Counts repo
    directories vs /proc/sys/fs/inotify/max_user_watches and warns
    above 50%, fails above 90%. The warn message suggests either
    switching to watcher.backend: watchman or raising the sysctl.

Changed

  • watch.New signature went from positional args to an Options
    struct (source-incompatible; migrates cleanly — all call-sites
    updated).
  • daemon.Daemon.Watcher is now watch.Watcher (interface) rather
    than *watch.Watcher (struct pointer), matching the new backend
    split.

Fixed

  • Shutdown race in the watcher's shared wrapper: coalesce/debounce
    timers could fire w.send after the output channel closed. Pump
    now owns every write to out; timers signal through internal
    channels. go test -race ./internal/watch/... confirms.

[v1.6.0] — 2026-04-24

"Graph-native tools + PR scope" — the sixth v2.0 milestone (Pillars E

  • F). Two new graph traversals that become cheap once v1.2/v1.3's
    type-aware resolvers landed, plus a --since <ref> path filter on the
    existing read surface for PR-scoped queries.

Added

  • impact_analysis(symbol) — new MCP tool and CLI myco query impact. Returns the transitive inbound closure around a symbol as
    a flat list ranked by distance (1 = direct caller). Optional kind
    filter narrows the reported set (typical use: kind=method to find
    test methods covering the target). Default depth 5, hard ceiling
    10. Composes with project and since — they scope the reported
    callers, not the walk, so cross-file / cross-project chains still
    surface.

  • critical_path(from, to) — new MCP tool and CLI myco query path. Returns up to k shortest outbound call paths. Bounded BFS
    at depth ≤ 8 via a single recursive CTE; cycles prevented by the
    SQLite instr() idiom on a comma-delimited accumulated path
    column. Hydrates the distinct vertices in one second-pass query to
    avoid the N+1 fan-out. Default k = 5.

  • --since <ref> filter on find_symbol, get_references,
    list_files, search_lexical, search_semantic. Resolved via
    git -C <root> diff --name-only <ref>...HEAD at the transport
    boundary (daemon RPC handler and CLI offline fallback), then passed
    to the reader as pathsIn []string. Three-dot form uses the merge-
    base so "files on my branch" stays correct after the base advances.

  • internal/gitref/ — thin helper (ResolveSince) that runs the
    git diff with a 5s timeout and surfaces stderr verbatim on
    failure. Returns a non-nil empty slice when the ref has no diff
    against HEAD so the reader's zero-row sentinel distinguishes "no
    changes" from "no filter."

  • internal/query/graph.goImpactAnalysis, CriticalPath,
    ImpactHit, Impact, PathVertex, CriticalPathResult. Reuses
    resolveSeed and loadNode from neighborhood.go.

  • internal/query/paths.go — shared pathsInClause splicer
    renders the AND f.path IN (?, ?, ...) WHERE fragment used across
    the five filtered methods. Caps the path list at 500 entries
    (SQLite's 999-parameter limit) and returns a clear error when a PR
    diff expands beyond that — the correct fix is a tighter base ref.

  • Reader signature change (additive, source-incompatible) — five
    methods gained a final pathsIn []string argument:

    • FindSymbol(ctx, name, kind, project, limit, pathsIn)
    • GetReferences(ctx, target, project, limit, pathsIn)
    • ListFiles(ctx, language, nameContains, project, limit, pathsIn)
    • SearchLexical(ctx, pattern, pathContains, project, k, repoRoot, pathsIn)
    • Searcher.SearchSemantic(ctx, query, k, kind, pathContains, project, pathsIn)

    pathsIn = nil is "unscoped"; pathsIn = []string{} is an
    explicit zero-row sentinel. Existing callers pass nil to preserve
    prior behavior. An options-struct refactor was considered and
    rejected for mid-release API churn.

  • MCP tool schemas — two new tool entries (impact_analysis,
    critical_path), plus a since input on find_symbol,
    get_references, list_files, search_lexical,
    search_semantic. MCP server dispatch in internal/mcp/server.go
    routes the two new tools.

  • CLI subcommandsmyco query impact <symbol> and myco query path <from> <to>. --since <ref> added to find, refs, files,
    grep, search. Offline fallback path runs gitref.ResolveSince
    locally so --since works even without the daemon.

  • Integration tests at graph_integration_test.go:

    • TestIntegration_ImpactAnalysis — seeds on auth.normalizeEmail
      and asserts auth.AuthService.fingerprint at distance 1 and
      auth.AuthService.issueToken at distance 2. Subtests for the
      kind-filter narrowing and the depth-clamp note.
    • TestIntegration_CriticalPath — asserts the path issueToken → fingerprint → normalizeEmail surfaces.
    • TestIntegration_PathsInFilter — exercises the reader-level
      filter (no git process) across three cases: matching file,
      non-matching file, empty-slice sentinel.
  • internal/gitref/resolve_test.go — temp-git-repo tests covering
    the happy path (two-commit diff), empty ref (error), unknown ref
    (error), and the no-changes case (non-nil empty slice).

Notes

  • vec0 KNN fast path is skipped when search_semantic is called
    with a project filter (v1.5) or a since filter (v1.6) —
    vec0 MATCH doesn't compose with arbitrary WHERE clauses.
    Brute-force cosine handles scoped semantic search.
  • impact_analysis is intentionally not a superset of
    get_neighborhood(direction=in). The shapes serve different
    workflows: graph (nodes + edges) vs. flat distance-ranked list; 2
    vs. 5 default depth; 5 vs. 10 max; no kind filter vs. yes.
  • Cross-repo federation (N worktrees, one graph) remains a v3
    non-goal.

Verification

Integration suite green on TestIntegration_IndexAndQuery,
TestIntegration_WorkspaceMode, TestIntegration_ImpactAnalysis,
TestIntegration_CriticalPath, TestIntegration_PathsInFilter, plus
all four internal/gitref cases. go vet -tags sqlite_fts5 ./...
clean. No schema changes, no migration.

[v1.5.0] — 2026-04-23

"Workspace mode" — the fifth v2.0 milestone (Pillar C). One daemon, one
SQLite, N sub-projects under one worktree. Not cross-repo federation
(that's v3): the unit of isola...

Read more