Skip to content
This repository was archived by the owner on May 28, 2026. It is now read-only.

chore(deps): bump @os-eco/mulch-cli from 0.6.5 to 0.10.1#151

Open
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/main/os-eco/mulch-cli-0.10.1
Open

chore(deps): bump @os-eco/mulch-cli from 0.6.5 to 0.10.1#151
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/main/os-eco/mulch-cli-0.10.1

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github May 16, 2026

Copy link
Copy Markdown
Contributor

Bumps @os-eco/mulch-cli from 0.6.5 to 0.10.1.

Release notes

Sourced from @​os-eco/mulch-cli's releases.

v0.10.1

A polish release that ships the @os-eco/pi-mulch extension (pl-5563), makes the close-session footer configurable, and generalizes ml audit from seeds-only to tracker-agnostic. The pi extension is the first first-class runtime integration — ml prime auto-fires on session_start, scope-load fires on tool_call, and record_expertise / query_expertise tools register inside the agent process so the model stops escaping into bash for record I/O. 1465 tests across 72 files / 3856 expect() calls (up from 1225 / 61 / 3047 in 0.10.0).

Added

pi-mulch extension (pl-5563)

  • @os-eco/pi-mulch extension shipped in-tree under extensions/pi/ (mulch-be45 / mulch-7359 / mulch-71cf / mulch-4d87 / mulch-903f / mulch-d060 / mulch-7229): a first-class integration for the pi-coding-agent runtime. The package exports a single ExtensionAPI factory wired into pi's lifecycle hooks (session_start, before_agent_start, tool_call, agent_end). peerDependencies declare @earendil-works/pi-coding-agent and typebox as optional so non-pi consumers install Mulch without the extra weight. Adds the pi-package keyword and an extensions: [./extensions/pi/index.ts] manifest to package.json; extensions/ is now part of files, biome, tsconfig, and the lint scripts.
  • Auto-prime on session_start (mulch-7359): the extension shells out to ml prime once at session_start and stashes the rendered markdown in a closure-cached string. before_agent_start injects it as a systemPrompt append fenced by <!-- mulch:prime:start --> / <!-- mulch:prime:end --> banners so chained extension prompts and /reload re-primes replace the previous body instead of duplicating. Shells out to ml (vs. importing commands/prime.ts in-process) so auto-flip-to-manifest, pre-prime hooks, and any future CLI behavior land in pi without code churn.
  • Per-file scope-load on tool_call (mulch-71cf): the extension fires ml prime --files <path> --budget <n> whenever the LLM reads/edits/writes a file and steers the rendered records into the message stream as a mulch-scope-load steer (display:false). Per-path debounce (default 500ms) coalesces rapid edit→read→edit sequences into one exec; paths canonicalize to absolute against ctx.cwd before keying the dedup set; an in-flight set blocks a second exec on the same path while the first awaits. Each successful scope-load calls pi.appendEntry("mulch-scope-load", { path }), and session_start walks ctx.sessionManager.getEntries() to seed primedPaths so post-/reload edits short-circuit before debounce — the user pays the prime cost once per file per session.
  • record_expertise + query_expertise custom pi tools (mulch-4d87): registered on session_start when pi.tools is true. Both rebuild on every session so per-project allowed_types, custom_types, and required_fields show up in the LLM-facing schema/description without restart. record_expertise writes a single-record JSON to mkdtemp() and invokes ml record <domain> --batch <tmp> --json (pi.exec has no stdin, so --batch is the path); pre-flight validation surfaces allowed_types / required_fields rules client-side so the LLM gets a targeted error instead of an opaque AJV rejection. query_expertise wraps ml search, ml prime --files, and ml prime <domain> behind one call so the model stops escaping into bash for reads.
  • /ml:prime slash command + agent_end learn-nudge widget (mulch-903f): /ml:prime [domain] re-runs ml prime (full or single-domain) and pushes the rendered markdown back into the conversation as a steer message; the [domain] argument autocompletes from the live mulch.config.yaml on every keystroke. Registered once at extension load with late-bound deps (cwd / sendMessage / notify) so the command becomes a no-op between sessions rather than throwing. On agent_end, the extension shells out to ml learn --json, parses the suggested-domains list, and renders one Record: <domain>/<type>? line per suggestion via ctx.ui.setWidget. The widget is cleared on session_start and session_shutdown so /reload, fork, or quit don't strand stale UI.
  • ml setup pi provider recipe + pi-aware onboarding marker (mulch-d060): ml setup pi writes .pi/settings.json with @os-eco/mulch-cli in packages (preserving existing entries) and refreshes the CLAUDE.md / AGENTS.md mulch section to a short pi-aware variant. The onboarding marker gains a :pi suffix (<!-- mulch-onboard:v0.10.1:pi -->) so detection logic doubles as install-state. --check and --remove round-trip both legs.
  • pi.* config namespace (mulch-be45): full MulchConfig.pi block (auto_prime, scope_load.{enabled,budget,debounce_ms}, tools, commands, agent_end_widget) with matching JSON schema parity so ml config set pi.<path> <value> validates atomically. Defaults: auto_prime: true, scope_load.budget: 2000, scope_load.debounce_ms: 500, all sub-toggles true. Read on every hook invocation via readPiConfig() so edits to mulch.config.yaml take effect on /reload without restart.

Core CLI

  • prime.session_close config knob — configurable + richer session-close footer (mulch-cc0f): the prose ml prime appends as the session-close marker (and the snippet ml setup / ml onboard write into CLAUDE.md / AGENTS.md / .cursor/rules/mulch.mdc) is now driven by prime.session_close in mulch.config.yaml. style: directive | conditional | minimal | none selects a built-in preset (default conditional — back-compat with the v0.10.0 reframe); custom: <string> overrides the preset with verbatim prose. The new directive preset ships imperative + numbered steps, the type glossary inline (convention=norm, pattern=how-to, failure=anti-pattern+fix, decision=we-picked-X, reference=external spec, guide=walk-through), the dedup nudge (--name upserts merge — re-recording is safe; outcomes accumulate, fields update in place), and concrete anti-filler examples (don't record CLAUDE.md restatements, generic truisms like "use TypeScript", single-PR-scoped facts, ritual confirmations). minimal collapses to a one-line nudge; none suppresses the footer entirely. The 🚨 anchor stays on markdown/plain directive for memory-anchor function (V1_PLAN §5.2); the embedded variant drops it because it lives at the top of CLAUDE.md, not at end-of-session. Custom always wins over style. Wired through every surface: getSessionEndReminder(format, config) in src/utils/format.ts, the two prime footer call sites in src/commands/prime.ts, the cursor/codex builders in src/commands/setup.ts, and buildSnippet in src/commands/onboard.ts (setup/onboard read config gracefully — pre-ml init projects fall back to the default preset rather than erroring).

Changed

  • ml audit generalizes from seeds-only to tracker-agnostic (mulch-1334): the evidence-coverage block and the citation-resolution block both treat seeds/gh/linear/bead as peers, so gh-only / linear-only / bead-only repos no longer see the report collapse into with seeds-ev: 0 (0%) plus a missing citation section. Human output emits with any tracker: as the headline and a per-tracker breakdown beneath (lines for trackers with zero records are omitted, so a seeds-only repo still prints one tracker line just like before). The renamed top-cited tracker ids: block renders gh ids as gh#42 (the GitHub-native form), linear as linear:ENG-123, bead as bead:b-abc123, and seeds bare (mulch-007) for visual back-compat. gh/linear/bead citations bucket into status_counts.unresolved because mulch does not yet have networked status lookups for those trackers — a future seed can layer in gh CLI / linear API resolution and turn the unresolved bucket into real per-tracker statuses. The JSON shape adds report.evidence.with_tracker: { seeds, gh, linear, bead } and report.tracker_citations (same shape as the old seed_citations with missing_in_seedsmissing_in_index and a new tracker: TrackerName field on each top_cited entry).
  • ml onboard snippet now carries a :pi suffix on the version marker when emitted by the pi recipe (<!-- mulch-onboard:v0.10.1:pi -->), so a repo that has run ml setup pi is distinguishable from one that only ran ml onboard. Legacy markers without the suffix are still detected as outdated and migrated on the next run.

Deprecated

  • report.evidence.with_seeds and report.seed_citations in ml audit --ci / --json output (mulch-1334): both fields stay readable for one release so existing JSON consumers don't break — with_seeds mirrors with_tracker.seeds, and seed_citations is populated with only the seeds entries (filtered) from the new tracker_citations. Migrate to evidence.with_tracker.seeds and tracker_citations; the deprecated fields will be removed in v0.11.

Testing

  • 1465 tests across 72 files, 3856 expect() calls (up from 1225 / 61 / 3047 in 0.10.0). New suites under test/extensions/ cover the pi config resolver, prime injection, scope-load (including debounce + canonicalization + /reload re-seeding), the record_expertise / query_expertise tools (all four validation gates, batch-file exec path, mid-session config re-read), commands, and the learn-nudge widget. test/commands/setup.test.ts adds pi recipe coverage (.pi/settings.json write / preserve / idempotency, :pi marker flip, check states, remove paths including the malformed-JSON safety case). test/commands/prime.test.ts covers the new prime.session_close presets; test/commands/audit.test.ts exercises the tracker-agnostic output.

v0.10.0

The visibility + prime overhaul release (pl-0752 / mulch-105d). Twelve PR-sized steps cover four V1_PLAN.md §3 deliverables: a first-class ml audit command for floater rate / evidence coverage / convention rule-density / per-domain mix; age-aware ml status surfacing rotting domains; a centralized and softened close-session prompt; and a three-slice ml prime overhaul that leads with the project contract, auto-flips to manifest above the size threshold, context-scopes by default in full mode, and ranks surfaced records by trust tier with a per-record "why surfaced now" suffix. A mid-cycle expansion (rev 2) adds the curation-surface gaps that make the new visibility primitives actionable — ml archive for direct soft-archive without waiting for ml prune, an archive_reason field on every archived record, granular per-record ml prune --dry-run output by default, and a ml compact overhaul that adds a pre-compact hook for semantic summarization and soft-archives originals instead of deleting them. The schema is unchanged for live records; archive_reason lands only on archived rows (V1_PLAN §2 frozen live-BaseRecord envelope preserved). One behavioral breaking change: ml prime default output now auto-flips to manifest above 100 records or 5 domains — pin --full --all for the legacy shape.

Added

  • ml audit — first-class corpus-health command (mulch-a051 / pl-0752, v0.10 step 1): ports the mulch-audit.py prototype (V1_PLAN §4.2) into the CLI so teams can measure floater rate, evidence coverage, convention rule-density, per-domain mix, and seed-citation status from a single command — and act on the results without leaving the terminal. Default output reproduces the Python prototype's signal layout (type mix → evidence → seed citations → convention quality → per-domain mix → top-cited seeds → domain age → summary signals) with PASS/WARN/FAIL verdicts per metric.
    • ml audit --ci exits 1 when any signal is in the FAIL band and emits the report as JSON so CI pipelines can gate on corpus health without parsing human output.
    • ml audit --suggest groups specific record IDs into archive (stale, non-foundational records), revise (conventions without rule-signal language), and attribute (floaters with no tracker / relates_to / commit) buckets — each bucket prints a copy-paste-able ml prune --ids … or ml edit <id> … command. This is the ROI multiplier per V1_PLAN: "your corpus is bad" is uncomforting; "here are the 47 specific records to fix" is actionable.
    • ml audit --domain <name> scopes every metric and verdict to one domain.
    • ml audit --ignore-domains <a,b> excludes domains from the audit (CLI list merges with audit.ignore_domains from config).
    • audit.thresholds config block overrides every default (evidence_coverage 0.5, evidence_coverage_warn 0.3, floater_max 0.2, rule_density_min 0.25, rule_density_warn 0.15, max_records_per_domain 200, max_stale 0). Per-domain overrides via audit.per_domain.<name> layer on top of the global thresholds — partial overrides inherit unspecified knobs from the global. Defaults relaxed from the Python prototype per V1_PLAN §4.2 ("0.7 evidence coverage is empirically unreachable today"); recalibrate after one quarter of real-corpus data.
  • ml archive <domain> [id] — direct archive without ml prune (mulch-d563, v0.10): a new write command that moves a specific live record (or several, via --records mx-a,mx-b) to .mulch/archive/<domain>.jsonl without waiting for shelf-life decay. Symmetric to ml restore; pairs with the archive_reason field (mulch-b41a) so manual archives are auditable. --reason <text> is required and stamped on disk as manual: <text> (e.g. archive_reason: "manual: wrong domain"); --dry-run previews without writing; --json emits { success, command: "archive", domain, dryRun, archived: [{id, type, summary, reason}], kept }. ID resolution reuses the same prefix/mx-/bare-hash matcher as ml delete and ml restore. The live-file read+rewrite happens inside a single withFileLock(getExpertisePath(domain)) acquisition so concurrent writers can't lose data; archive writing happens after (matches ml prune phase 3). Closes the soft-archive UX gap: prune handles bulk decay; ml archive handles targeted intent. See src/commands/archive.ts.
  • archive_reason field on archived records (mulch-b41a, v0.10): every record moved to .mulch/archive/<domain>.jsonl now carries an archive_reason field alongside status: "archived" and archived_at. Convention values: "stale" | "superseded" | "anchor_decay" | "manual" | "compacted" (free-text suffix permitted, e.g. "manual: wrong domain"). ml prune stamps "stale" on records that aged out of their classification shelf life, "superseded" on records that bottom out via supersession decay, "anchor_decay" on records that bottom out via --check-anchors, and "superseded+anchor_decay" on the rare overlap. ml restore's rollback-on-conflict path preserves the original reason so the round-trip is invisible to anyone reading the archive. ml search --archived now renders the reason in its output line: [ARCHIVED 2026-04-12 anchor_decay] mx-abc [pattern] …. ml restore <id> includes the reason in its success message: ✓ Restored pattern mx-abc to testing (archived: stale): … (JSON mode adds an archive_reason field to the success payload). Field is optional — archives written before this seed lands continue to load and render without the suffix. Lives only on archived records; the v1.0-frozen live BaseRecord envelope is unchanged. See archiveRecords / stripArchiveFields in src/utils/archive.ts.
  • Active-work resolver chain (mulch-f3d0 / pl-0752, v0.10 step 3): src/utils/active-work.ts exposes symmetric per-tracker resolvers (seedsResolver, ghResolver, linearResolver, beadResolver) plus a resolveActiveWork() orchestrator that returns the first non-empty match across all four. Each resolver looks at the current branch name (parsed for tracker-style IDs: seeds xxx-abc123, gh [#42](https://github.com/jayminwest/mulch/issues/42), linear ENG-123, bead b-abc123) and the relevant external state (in-progress seeds via sd, current PR via gh pr view, environment variables). Conservative auto-link behavior: a single resolved match writes through to evidence, multi-match emits a formatted stderr warning listing each candidate so the operator self-corrects via explicit --evidence-* flags. Explicit overrides short-circuit any resolver. The schema already supported seeds/gh/linear/bead symmetrically (src/schemas/record.ts) — this lands the helper that consumes them at the resolver layer so v0.10 prime context-scope (mulch-244c) and v0.11 auto-link-on-record can share one implementation. See src/utils/active-work.ts.
  • pre-compact lifecycle hook + ml compact --apply archives originals (mulch-184b / pl-0752, v0.10 step 11): two changes that together replace ml compact's mechanical concatenate-and-delete with an auditable, undoable, optionally-semantic flow. (1) A new pre-compact event joins the existing hook contract (pre-record / post-record / pre-prime / pre-prune / pre-compact). The hook receives { event: "pre-compact", payload: { domain, candidates: [...], merged: <mechanical-merge-record> } } on stdin; if it prints { replacement: <RecordShape> } on stdout, the replacement is validated against the type registry and substituted for the mechanical merge. Absent hook → existing mergeRecords() strategy (back-compat for every existing ml compact test). Malformed hook output (parse error, missing fields, validation failure) rejects the compaction with a copy-paste retry hint matching the standard record-validation error shape. (2) The candidate records that get rolled into the merged output are now soft-archived to .mulch/archive/<domain>.jsonl with archive_reason: "compacted" instead of being silently deleted, so ml restore <id> round-trips a compacted record back to live expertise. ml compact --auto and ml compact --apply both archive; ml compact --analyze and ml compact --dry-run are unchanged (no writes). ml doctor adds a new informational compact-summarizer check that reports configured (pre-compact: <script-path>) or not configured (mechanical merge in use). See src/commands/compact.ts and runHooks("pre-compact", …) wiring.

Changed

... (truncated)

Changelog

Sourced from @​os-eco/mulch-cli's changelog.

[0.10.1] - 2026-05-15

A polish release that ships the @os-eco/pi-mulch extension (pl-5563), makes the close-session footer configurable, and generalizes ml audit from seeds-only to tracker-agnostic. The pi extension is the first first-class runtime integration — ml prime auto-fires on session_start, scope-load fires on tool_call, and record_expertise / query_expertise tools register inside the agent process so the model stops escaping into bash for record I/O. 1465 tests across 72 files / 3856 expect() calls (up from 1225 / 61 / 3047 in 0.10.0).

Added

pi-mulch extension (pl-5563)

  • @os-eco/pi-mulch extension shipped in-tree under extensions/pi/ (mulch-be45 / mulch-7359 / mulch-71cf / mulch-4d87 / mulch-903f / mulch-d060 / mulch-7229): a first-class integration for the pi-coding-agent runtime. The package exports a single ExtensionAPI factory wired into pi's lifecycle hooks (session_start, before_agent_start, tool_call, agent_end). peerDependencies declare @earendil-works/pi-coding-agent and typebox as optional so non-pi consumers install Mulch without the extra weight. Adds the pi-package keyword and an extensions: [./extensions/pi/index.ts] manifest to package.json; extensions/ is now part of files, biome, tsconfig, and the lint scripts.
  • Auto-prime on session_start (mulch-7359): the extension shells out to ml prime once at session_start and stashes the rendered markdown in a closure-cached string. before_agent_start injects it as a systemPrompt append fenced by <!-- mulch:prime:start --> / <!-- mulch:prime:end --> banners so chained extension prompts and /reload re-primes replace the previous body instead of duplicating. Shells out to ml (vs. importing commands/prime.ts in-process) so auto-flip-to-manifest, pre-prime hooks, and any future CLI behavior land in pi without code churn.
  • Per-file scope-load on tool_call (mulch-71cf): the extension fires ml prime --files <path> --budget <n> whenever the LLM reads/edits/writes a file and steers the rendered records into the message stream as a mulch-scope-load steer (display:false). Per-path debounce (default 500ms) coalesces rapid edit→read→edit sequences into one exec; paths canonicalize to absolute against ctx.cwd before keying the dedup set; an in-flight set blocks a second exec on the same path while the first awaits. Each successful scope-load calls pi.appendEntry("mulch-scope-load", { path }), and session_start walks ctx.sessionManager.getEntries() to seed primedPaths so post-/reload edits short-circuit before debounce — the user pays the prime cost once per file per session.
  • record_expertise + query_expertise custom pi tools (mulch-4d87): registered on session_start when pi.tools is true. Both rebuild on every session so per-project allowed_types, custom_types, and required_fields show up in the LLM-facing schema/description without restart. record_expertise writes a single-record JSON to mkdtemp() and invokes ml record <domain> --batch <tmp> --json (pi.exec has no stdin, so --batch is the path); pre-flight validation surfaces allowed_types / required_fields rules client-side so the LLM gets a targeted error instead of an opaque AJV rejection. query_expertise wraps ml search, ml prime --files, and ml prime <domain> behind one call so the model stops escaping into bash for reads.
  • /ml:prime slash command + agent_end learn-nudge widget (mulch-903f): /ml:prime [domain] re-runs ml prime (full or single-domain) and pushes the rendered markdown back into the conversation as a steer message; the [domain] argument autocompletes from the live mulch.config.yaml on every keystroke. Registered once at extension load with late-bound deps (cwd / sendMessage / notify) so the command becomes a no-op between sessions rather than throwing. On agent_end, the extension shells out to ml learn --json, parses the suggested-domains list, and renders one Record: <domain>/<type>? line per suggestion via ctx.ui.setWidget. The widget is cleared on session_start and session_shutdown so /reload, fork, or quit don't strand stale UI.
  • ml setup pi provider recipe + pi-aware onboarding marker (mulch-d060): ml setup pi writes .pi/settings.json with @os-eco/mulch-cli in packages (preserving existing entries) and refreshes the CLAUDE.md / AGENTS.md mulch section to a short pi-aware variant. The onboarding marker gains a :pi suffix (<!-- mulch-onboard:v0.10.1:pi -->) so detection logic doubles as install-state. --check and --remove round-trip both legs.
  • pi.* config namespace (mulch-be45): full MulchConfig.pi block (auto_prime, scope_load.{enabled,budget,debounce_ms}, tools, commands, agent_end_widget) with matching JSON schema parity so ml config set pi.<path> <value> validates atomically. Defaults: auto_prime: true, scope_load.budget: 2000, scope_load.debounce_ms: 500, all sub-toggles true. Read on every hook invocation via readPiConfig() so edits to mulch.config.yaml take effect on /reload without restart.

Core CLI

  • prime.session_close config knob — configurable + richer session-close footer (mulch-cc0f): the prose ml prime appends as the session-close marker (and the snippet ml setup / ml onboard write into CLAUDE.md / AGENTS.md / .cursor/rules/mulch.mdc) is now driven by prime.session_close in mulch.config.yaml. style: directive | conditional | minimal | none selects a built-in preset (default conditional — back-compat with the v0.10.0 reframe); custom: <string> overrides the preset with verbatim prose. The new directive preset ships imperative + numbered steps, the type glossary inline (convention=norm, pattern=how-to, failure=anti-pattern+fix, decision=we-picked-X, reference=external spec, guide=walk-through), the dedup nudge (--name upserts merge — re-recording is safe; outcomes accumulate, fields update in place), and concrete anti-filler examples (don't record CLAUDE.md restatements, generic truisms like "use TypeScript", single-PR-scoped facts, ritual confirmations). minimal collapses to a one-line nudge; none suppresses the footer entirely. The 🚨 anchor stays on markdown/plain directive for memory-anchor function (V1_PLAN §5.2); the embedded variant drops it because it lives at the top of CLAUDE.md, not at end-of-session. Custom always wins over style. Wired through every surface: getSessionEndReminder(format, config) in src/utils/format.ts, the two prime footer call sites in src/commands/prime.ts, the cursor/codex builders in src/commands/setup.ts, and buildSnippet in src/commands/onboard.ts (setup/onboard read config gracefully — pre-ml init projects fall back to the default preset rather than erroring).

Changed

  • ml audit generalizes from seeds-only to tracker-agnostic (mulch-1334): the evidence-coverage block and the citation-resolution block both treat seeds/gh/linear/bead as peers, so gh-only / linear-only / bead-only repos no longer see the report collapse into with seeds-ev: 0 (0%) plus a missing citation section. Human output emits with any tracker: as the headline and a per-tracker breakdown beneath (lines for trackers with zero records are omitted, so a seeds-only repo still prints one tracker line just like before). The renamed top-cited tracker ids: block renders gh ids as gh#42 (the GitHub-native form), linear as linear:ENG-123, bead as bead:b-abc123, and seeds bare (mulch-007) for visual back-compat. gh/linear/bead citations bucket into status_counts.unresolved because mulch does not yet have networked status lookups for those trackers — a future seed can layer in gh CLI / linear API resolution and turn the unresolved bucket into real per-tracker statuses. The JSON shape adds report.evidence.with_tracker: { seeds, gh, linear, bead } and report.tracker_citations (same shape as the old seed_citations with missing_in_seedsmissing_in_index and a new tracker: TrackerName field on each top_cited entry).
  • ml onboard snippet now carries a :pi suffix on the version marker when emitted by the pi recipe (<!-- mulch-onboard:v0.10.1:pi -->), so a repo that has run ml setup pi is distinguishable from one that only ran ml onboard. Legacy markers without the suffix are still detected as outdated and migrated on the next run.

Deprecated

  • report.evidence.with_seeds and report.seed_citations in ml audit --ci / --json output (mulch-1334): both fields stay readable for one release so existing JSON consumers don't break — with_seeds mirrors with_tracker.seeds, and seed_citations is populated with only the seeds entries (filtered) from the new tracker_citations. Migrate to evidence.with_tracker.seeds and tracker_citations; the deprecated fields will be removed in v0.11.

Testing

  • 1465 tests across 72 files, 3856 expect() calls (up from 1225 / 61 / 3047 in 0.10.0). New suites under test/extensions/ cover the pi config resolver, prime injection, scope-load (including debounce + canonicalization + /reload re-seeding), the record_expertise / query_expertise tools (all four validation gates, batch-file exec path, mid-session config re-read), commands, and the learn-nudge widget. test/commands/setup.test.ts adds pi recipe coverage (.pi/settings.json write / preserve / idempotency, :pi marker flip, check states, remove paths including the malformed-JSON safety case). test/commands/prime.test.ts covers the new prime.session_close presets; test/commands/audit.test.ts exercises the tracker-agnostic output.

[0.10.0] - 2026-05-13

The visibility + prime overhaul release (pl-0752 / mulch-105d). Twelve PR-sized steps cover four V1_PLAN.md §3 deliverables: a first-class ml audit command for floater rate / evidence coverage / convention rule-density / per-domain mix; age-aware ml status surfacing rotting domains; a centralized and softened close-session prompt; and a three-slice ml prime overhaul that leads with the project contract, auto-flips to manifest above the size threshold, context-scopes by default in full mode, and ranks surfaced records by trust tier with a per-record "why surfaced now" suffix. A mid-cycle expansion (rev 2) adds the curation-surface gaps that make the new visibility primitives actionable — ml archive for direct soft-archive without waiting for ml prune, an archive_reason field on every archived record, granular per-record ml prune --dry-run output by default, and a ml compact overhaul that adds a pre-compact hook for semantic summarization and soft-archives originals instead of deleting them. The schema is unchanged for live records; archive_reason lands only on archived rows (V1_PLAN §2 frozen live-BaseRecord envelope preserved). One behavioral breaking change: ml prime default output now auto-flips to manifest above 100 records or 5 domains — pin --full --all for the legacy shape.

Added

  • ml audit — first-class corpus-health command (mulch-a051 / pl-0752, v0.10 step 1): ports the mulch-audit.py prototype (V1_PLAN §4.2) into the CLI so teams can measure floater rate, evidence coverage, convention rule-density, per-domain mix, and seed-citation status from a single command — and act on the results without leaving the terminal. Default output reproduces the Python prototype's signal layout (type mix → evidence → seed citations → convention quality → per-domain mix → top-cited seeds → domain age → summary signals) with PASS/WARN/FAIL verdicts per metric.
    • ml audit --ci exits 1 when any signal is in the FAIL band and emits the report as JSON so CI pipelines can gate on corpus health without parsing human output.
    • ml audit --suggest groups specific record IDs into archive (stale, non-foundational records), revise (conventions without rule-signal language), and attribute (floaters with no tracker / relates_to / commit) buckets — each bucket prints a copy-paste-able ml prune --ids … or ml edit <id> … command. This is the ROI multiplier per V1_PLAN: "your corpus is bad" is uncomforting; "here are the 47 specific records to fix" is actionable.
    • ml audit --domain <name> scopes every metric and verdict to one domain.
    • ml audit --ignore-domains <a,b> excludes domains from the audit (CLI list merges with audit.ignore_domains from config).
    • audit.thresholds config block overrides every default (evidence_coverage 0.5, evidence_coverage_warn 0.3, floater_max 0.2, rule_density_min 0.25, rule_density_warn 0.15, max_records_per_domain 200, max_stale 0). Per-domain overrides via audit.per_domain.<name> layer on top of the global thresholds — partial overrides inherit unspecified knobs from the global. Defaults relaxed from the Python prototype per V1_PLAN §4.2 ("0.7 evidence coverage is empirically unreachable today"); recalibrate after one quarter of real-corpus data.
  • ml archive <domain> [id] — direct archive without ml prune (mulch-d563, v0.10): a new write command that moves a specific live record (or several, via --records mx-a,mx-b) to .mulch/archive/<domain>.jsonl without waiting for shelf-life decay. Symmetric to ml restore; pairs with the archive_reason field (mulch-b41a) so manual archives are auditable. --reason <text> is required and stamped on disk as manual: <text> (e.g. archive_reason: "manual: wrong domain"); --dry-run previews without writing; --json emits { success, command: "archive", domain, dryRun, archived: [{id, type, summary, reason}], kept }. ID resolution reuses the same prefix/mx-/bare-hash matcher as ml delete and ml restore. The live-file read+rewrite happens inside a single withFileLock(getExpertisePath(domain)) acquisition so concurrent writers can't lose data; archive writing happens after (matches ml prune phase 3). Closes the soft-archive UX gap: prune handles bulk decay; ml archive handles targeted intent. See src/commands/archive.ts.
  • archive_reason field on archived records (mulch-b41a, v0.10): every record moved to .mulch/archive/<domain>.jsonl now carries an archive_reason field alongside status: "archived" and archived_at. Convention values: "stale" | "superseded" | "anchor_decay" | "manual" | "compacted" (free-text suffix permitted, e.g. "manual: wrong domain"). ml prune stamps "stale" on records that aged out of their classification shelf life, "superseded" on records that bottom out via supersession decay, "anchor_decay" on records that bottom out via --check-anchors, and "superseded+anchor_decay" on the rare overlap. ml restore's rollback-on-conflict path preserves the original reason so the round-trip is invisible to anyone reading the archive. ml search --archived now renders the reason in its output line: [ARCHIVED 2026-04-12 anchor_decay] mx-abc [pattern] …. ml restore <id> includes the reason in its success message: ✓ Restored pattern mx-abc to testing (archived: stale): … (JSON mode adds an archive_reason field to the success payload). Field is optional — archives written before this seed lands continue to load and render without the suffix. Lives only on archived records; the v1.0-frozen live BaseRecord envelope is unchanged. See archiveRecords / stripArchiveFields in src/utils/archive.ts.
  • Active-work resolver chain (mulch-f3d0 / pl-0752, v0.10 step 3): src/utils/active-work.ts exposes symmetric per-tracker resolvers (seedsResolver, ghResolver, linearResolver, beadResolver) plus a resolveActiveWork() orchestrator that returns the first non-empty match across all four. Each resolver looks at the current branch name (parsed for tracker-style IDs: seeds xxx-abc123, gh [#42](https://github.com/jayminwest/mulch/issues/42), linear ENG-123, bead b-abc123) and the relevant external state (in-progress seeds via sd, current PR via gh pr view, environment variables). Conservative auto-link behavior: a single resolved match writes through to evidence, multi-match emits a formatted stderr warning listing each candidate so the operator self-corrects via explicit --evidence-* flags. Explicit overrides short-circuit any resolver. The schema already supported seeds/gh/linear/bead symmetrically (src/schemas/record.ts) — this lands the helper that consumes them at the resolver layer so v0.10 prime context-scope (mulch-244c) and v0.11 auto-link-on-record can share one implementation. See src/utils/active-work.ts.
  • pre-compact lifecycle hook + ml compact --apply archives originals (mulch-184b / pl-0752, v0.10 step 11): two changes that together replace ml compact's mechanical concatenate-and-delete with an auditable, undoable, optionally-semantic flow. (1) A new pre-compact event joins the existing hook contract (pre-record / post-record / pre-prime / pre-prune / pre-compact). The hook receives { event: "pre-compact", payload: { domain, candidates: [...], merged: <mechanical-merge-record> } } on stdin; if it prints { replacement: <RecordShape> } on stdout, the replacement is validated against the type registry and substituted for the mechanical merge. Absent hook → existing mergeRecords() strategy (back-compat for every existing ml compact test). Malformed hook output (parse error, missing fields, validation failure) rejects the compaction with a copy-paste retry hint matching the standard record-validation error shape. (2) The candidate records that get rolled into the merged output are now soft-archived to .mulch/archive/<domain>.jsonl with archive_reason: "compacted" instead of being silently deleted, so ml restore <id> round-trips a compacted record back to live expertise. ml compact --auto and ml compact --apply both archive; ml compact --analyze and ml compact --dry-run are unchanged (no writes). ml doctor adds a new informational compact-summarizer check that reports configured (pre-compact: <script-path>) or not configured (mechanical merge in use). See src/commands/compact.ts and runHooks("pre-compact", …) wiring.

... (truncated)

Commits
  • b6e5133 chore: release v0.10.1
  • f14c69a test(pi): cover pi recipe + record/query tools, rewrite README (mulch-7229)
  • bc30f94 seeds: sync 2026-05-15
  • 15999c8 mulch: update expertise
  • 26db970 feat(pi): ml setup pi recipe + pi-aware onboarding marker (mulch-d060)
  • 1fcaeeb seeds: sync 2026-05-15
  • 74c1c88 feat(pi): /ml:prime command + agent_end learn-nudge widget (mulch-903f)
  • c066bad seeds: sync 2026-05-15
  • 19c4a67 mulch: update expertise
  • a138bf0 feat(pi): record_expertise + query_expertise tools (mulch-4d87)
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [@os-eco/mulch-cli](https://github.com/jayminwest/mulch) from 0.6.5 to 0.10.1.
- [Release notes](https://github.com/jayminwest/mulch/releases)
- [Changelog](https://github.com/jayminwest/mulch/blob/main/CHANGELOG.md)
- [Commits](jayminwest/mulch@v0.6.5...v0.10.1)

---
updated-dependencies:
- dependency-name: "@os-eco/mulch-cli"
  dependency-version: 0.10.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code labels May 16, 2026
@dependabot
dependabot Bot requested a review from jayminwest as a code owner May 16, 2026 03:02
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants