Skip to content

CLI changelog

  • Reliable self-update — dimple upgrade now runs the package manager with its own arguments, resolves npm, pnpm, Bun, or Yarn from the real executable path (including a standalone Bun binary’s virtual argv[1]), and probes the installed managers when the path is inconclusive. It also serializes concurrent upgrades with an owner-PID lock, keeps a Windows hard link to the running image while installing, and rejects non-semver registry versions before they reach a command. --check still reports the available version without installing.

  • MCP search paging, filters, and recency — memory_search enforces offset + limit <= 200, matching the real candidate window, and reports a saturated window as hasMore. pathPrefix and sourceOnly prefer metadata.filePath and match whole path segments. The dimple://memory resource reads Dimple.recent instead of running an empty search, with a 1..200 limit.

  • Search and index — empty queries are rejected with Sdk.InputError, --limit and MCP pages are bounded, and dimple docs-index reconciles removed docs after a walk. The changed-file index reads at most the configured byte caps, and a model change is visible to index --check and the stale backfill.

  • Startup and platform — the CLI entry lazy-loads commands, serve, MCP, and upgrade, and builds with splitting. The changed-file scan uses Effect FileSystem, Path, and ChildProcessSpawner instead of node:* APIs. Measured node dist/cli.js --version dropped from about 449 ms to 55 to 75 ms (Bun about 44 ms).

  • Alpha.16 upgrade caveat — the published 0.0.0-alpha.16 binary contains the old upgrade command, which passed the manager name twice and failed with Unknown command: "npm". Users on that version need one manual reinstall; later upgrades use the fixed flow:

    Terminal window
    npm install -g @ponraaj/dimple@latest
    # or
    bun add -g @ponraaj/dimple@latest
  • MCP capability surface and filtering — the 21 tools are defined once as capability contracts and projected through one toolkit. The daemon adds ?features= and ?exclude_tools= filters plus matching x-dimple-read-only, x-dimple-tools, x-dimple-features, and x-dimple-exclude-tools headers; a header wins over the query parameter. readonly is applied after the tools/features allowlist, so a write tool cannot be re-added with ?tools=. Always-available docs tools remain visible under a narrowed surface, and maintenance_dream is not advertised when the resolved config has no llm section. memory_index accepts changed: true through the daemon’s git adapter and force: true; explicit paths still work.

  • Index defaults and forced re-embedding — dimple index with no path indexes the git-changed files under the current directory. --changed selects every changed file in the repo, --all walks the whole tree, and --force re-embeds every selected unit (the whole tree when no path is given). --force --changed re-embeds every unit in the changed files only. A normal index re-embeds unchanged units whose vector is missing or belongs to another model, so a model change backfills on the next full run.

  • Code-search and index-freshness — memory_search gains pathPrefix, kind (function, class, file, definition), and sourceOnly filters with file dedupe; memory_get accepts inclusive file-line windows; dimple index --check reports stale and missing units; dimple docs-index indexes docs, changesets, and recent commits. dimple mcp status|stop|reload|--print no longer boot the store, and --print carries the absolute config path and selected environment.

  • Read-only filter bypass fixed — ?readonly=1 combined with ?tools= was a union, so memory_forget could be re-added. It is now an AND after the allowlist.

  • dimple index --changed fixed — the computed changed-file list was discarded (only positionals reached dimple.index, so a no-path run failed the non-empty paths validation), and git paths from a subdirectory resolved against the wrong root. Changed paths now resolve from git rev-parse --show-toplevel and scope to the requested roots.

  • Docs ranking — docs_search now ranks title and description evidence above repeated body mentions (body occurrences are capped), so the architecture page wins over incidental mentions in the MCP guide.

  • Quantized search and topic-tree maintenance fixes — float8 and float1bit models now use the exact scan; the ANN vector_top_k index is created for float32 only, so quantized queries no longer fail with failed to parse vector index parameters. topic.split jobs carry a power-of-two sizeBucket derived from the routed leaf count, so a rejected split retries after the leaf grows instead of being deduped into the completed rejection. processSplits attempts each over-limit leaf once per pass, largest first. Routing and topic resolution treat maxDepth as a soft budget and continue to a real leaf; the old fallback attached memories to the internal __unassigned_active__ node.

  • Latest dependency stack — Effect 4.0.6, AI SDK v4 providers (@ai-sdk/cohere 4, @ai-sdk/google 4, ai 7.0.150), drizzle-orm 1.0.0-rc.5, @libsql/client 0.18.0, web-tree-sitter 0.27.1, @huggingface/transformers 4.3.1, and TypeScript 7.0.2. The sandbox’s TS guest transpiler uses Bun’s transpiler under Bun and module.stripTypeScriptTypes under Node.

  • MCP: bounded search payloads, recovery hints, and a findable update path — memory_search rows are ≤400-char snippets cut at a word boundary and ending in … [truncated — read with memory_get], with contentChars/contentTruncated marking the cut (memory_get stays whole), so a search over indexed code can no longer put a whole 64 KB file unit on the wire. An empty search carries a recovery hint instead of a bare []. memory_write gains replace: true for one-call updates (forget the active version, write the new content under the same key), and its description plus the MCP guide teach both update paths. docs_search drops question-phrasing stopwords, so filler-only queries find nothing and intent queries rank their page first. updateEmbedding now fails with a typed dimension error (invalid_params over MCP) instead of the vector index’s raw message.

  • Drain visibility on the status surfaces — dimple health, the dimple://health resource, and maintenance_health now report jobs: the outstanding (offered, not yet finished) elements per job queue ({ queue, pending }). It answers the question a deferred memory_index leaves open — “is the embedding batch still running?” — and an empty array means everything is drained (the internal resume-signal queue is excluded). The counts come from a new QueueStats service in @dimple/workflow, one grouped COUNT(*) over the queue table on the same libSQL client the queue store uses.

  • MCP: paged search, bounded candidate review, offline docs pages — memory_search returns at most 25 rows per call (10 by default) with hasMore and a new offset input (≤ 1000; deeper pages are refused as invalid_params). graph_candidates caps at 25 per call with hasMore. Every documentation page is served as a dimple://docs/<path> resource, and docs_search hits and open_in_dimple results carry that URI, so following a docs pointer works offline.

  • Bulk routing no longer overwrites topic-tree member counts — routeInsertMany persisted the call-local unit count into topics.member_count, so every bulk pass (indexing, memory_write_many, the embed batch) replaced each topic’s total with the size of that pass; the health sweep reported a count mismatch and split/merge decisions read the wrong leaf size. Batch routing now accumulates the absolute final state per touched topic, matching sequential routeInsert calls.

  • dimple mcp start works from the standalone executable — the daemon re-launch passed process.argv[1] unconditionally; inside a compiled binary that is Bun’s virtual entry (/$bunfs/root/<name>), so the child parsed the entry as the command, printed usage to .dimple/mcp.log and never listened while mcp start reported a pid. The launcher now detects the standalone runtime (Bun.isStandaloneExecutable, or the virtual entry in Bun.main on the pinned 1.3.11 runtime, which predates that flag) and omits the entry argument; mcp start also waits until the daemon is listening before reporting success, so a crashed child fails the command with the log path.

  • Session options in dimple.jsonc: embedding.sessionOptions sets ONNX Runtime session options for every local model, and each model’s own sessionOptions overrides it field by field: thread counts, execution mode, graph optimization level, the CPU arena and memory-pattern switches, the CUDA pair, and a per-model wasm.numThreads for the WASM backend. The parallel-ingest recipe is intraOpNumThreads = floor(physicalCores / workers); the configuration reference carries the tuning guide.

  • CPU-only session options no longer request CUDA: a session-options block emits a CUDA execution provider only when gpuMemLimit or arenaExtendStrategy is set, so a CPU-only model is never pinned to a provider the runtime may not have.

  • dimple index --defer-embed: Write units and defer their embeddings plus topic routing to the durable memory.embed.batch jobs. The command returns once the units are stored and lexically searchable, and the summary reports the pending count; a later run or the MCP server’s workers drain them. The default stays fully synchronous.

  • Faster indexing: New-unit writes go through the batched store path, measured on a pinned 235-unit corpus at 9,218 ms → 6,944 ms minimum for index plus 20 queries. ORT session options now reach the runtime (they were silently dropped) and the CPU arena is bounded.

  • MCP SDK 2.3.0: dimple mcp runs on @modelcontextprotocol/server 2.3.0 and @modelcontextprotocol/client 2.3.0. Tool-schema conversion moved off the per-request path, tasks/get and tasks/cancel are servable on the 2026-07-28 era, and the one-server-per-request rule matches the existing per-request factory.

  • Standalone binaries + launcher: The dimple CLI now ships as prebuilt standalone binaries, with the npm package’s dimple command acting as a launcher. Six platform packages (@ponraaj/dimple-linux-x64, -linux-arm64, -linux-x64-musl, -darwin-arm64, -darwin-x64, -win32-x64) carry a single-file build of the CLI with the wasm ONNX engine embedded, so the local embedder runs offline without an install script; each package declares its os/cpu/libc and ships the binary alone. The launcher resolves the platform package for the current machine, runs it with inherited stdio, and propagates its exit code; DIMPLE_BINARY overrides the path. When no prebuilt package is present (unsupported platform, --omit=optional, or a failed resolution) it falls back to the Node bundle (dist/cli.js) with a message saying so.

    The six platform packages are exact optionalDependencies of @ponraaj/dimple and ship in lockstep with it; no published tarball carries install scripts (npm 12 blocks dependency install scripts by default). This release verifies the cross-target binaries structurally (file type, pinned Bun runtime label, matching @libsql native) but has no macOS/Windows/arm64 runner, so those binaries are not executed by CI yet. Image models are unsupported (sharp is stubbed with a named error); text and code embeddings are the supported path.

  • One MCP answer per call: MCP tool results now ship one answer instead of two copies of it. A successful tool call returns the payload once, minified, in content[0].text, and no longer repeats it in structuredContent; every MCP client already reads that channel because content is the mandatory one. Failures are unchanged: isError: true plus the small structuredContent.error.{code,message} machine envelope (still documented in the MCP guide), and so is the dormant task-handle path, which keeps both channels because its top-level fields are a wire contract (the Tasks extension is not advertised in this build, pending the upstream era-gate fix).

    Effect on a real call, measured on a pinned fixture of five 720 B memories: memory_search(limit=5) drops from 10,815 B to 5,056 B (−53%), and memory_get from 2,161 B to 1,111 B (−48.6%). Both figures are the returned result object serialized as JSON; the JSON-RPC envelope adds ~35 B on top. Clients that read payloads from structuredContent must read the text channel instead; the payload bytes are identical, only the indentation and the duplicate are gone.

    Also enforced now, with tests that refuse to be weakened: a per-tool inputSchema budget of 4,000 characters (the 16,384-character client drop is a silent failure mode) and a 24,000-character budget for the whole advertised tools/list. Today’s surface is 21 tools, 11,970 B, with memory_search the largest schema at 1,901 B.

    No tool was added, removed, renamed, or reshaped: the 21 names, titles, descriptions, and input schemas are byte-identical. The plan and the measured baseline live in docs/mcp-efficiency-design.md; the rationale is borrowed from the Sentry and PostHog MCP servers.

  • MCP annotations and opt-in narrowing: Every tool in the dimple MCP surface now carries the full annotation quartet (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), so a client can gate on it without guessing: the read-only tools are memory_get, memory_search, memory_embed, graph_candidates, graph_coverage, graph_explain, maintenance_health, docs_search and open_in_dimple; openWorldHint is false everywhere, because dimple is a local, closed world and a constant hint would carry no signal.

    destructiveHint follows the MCP definition (false means the call performs only additive updates), applied through one rule: a tool is destructive when it can irreversibly hide, remove, or repurpose a live entity the caller did not name. Seven tools qualify: memory_forget, memory_index, graph_add_edge, graph_confirm, graph_reject, graph_expire and maintenance_dream. The three that remove or retire the entity the caller named are the obvious set (memory_forget deletes the memory; graph_reject and graph_expire retire the edge); the other four matter because confirming (or inserting as confirmed) a memory_supersedes edge flips the old memory active → superseded, which drops it out of every read path and releases its logical key for reuse: graph_confirm, a confirmed: true graph_add_edge, memory_index’s superseding write plus its reconcile of vanished units, and the dream job’s confirmed supersedes relation all reach it.

    The loopback HTTP endpoint honours two opt-in query parameters for clients that want a narrower surface (stdio is unaffected: it has no URL and always serves everything):

    • ?readonly=1: only the tools annotated readOnlyHint: true
    • ?tools=memory_get,graph_explain: exactly the named tools
    • both together: the union of the two sets

    Tool names are matched exactly (no hyphen/underscore rewriting); an unknown name is answered 400 with a message listing the valid tools. That body enumerates the tool surface, so it is produced only for a local caller: a request with no Origin, or with a loopback origin (127.0.0.1, localhost, ::1 over http/https). Any other origin goes to the SDK handler untouched, where the daemon’s own localhost host/origin guards decide. With no query parameters the full 21-tool surface is served, exactly as before: nothing is hidden unless the client asks.

  • Updated dependencies

    • @ponraaj/dimple-sdk@0.0.0-alpha.11
  • CUDA session options for local embeddings (see the SDK changelog)
  • Updated dependencies
    • @ponraaj/dimple-sdk@0.0.0-alpha.10
  • Queries are faster across the board (ANN vector search, lighter result payloads, single-pass graph context): see the SDK changelog
  • Updated dependencies
    • @ponraaj/dimple-sdk@0.0.0-alpha.9
  • dimple upgrade: checks the npm registry for a newer CLI release and installs it with the package manager that installed you (auto-detected; --manager overrides). --check prints the available version without installing; no project config needed
  • code.exec auto-install: the sandbox’s secure-exec peer (and its platform sidecar) installs itself on first code-mode run
  • Keyword search matches again: FTS5 treated the whole query as a verbatim phrase, so multi-word queries (e.g. import helper main) returned nothing unless the exact phrase appeared contiguously. Queries are now AND over tokens: every word must appear, anywhere.
  • Updated dependencies
    • @ponraaj/dimple-sdk@0.0.0-alpha.8
  • MCP server: dimple mcp exposes dimple to any MCP client over the 2026-07-28 protocol: a search tool to discover the API surface, and a sandboxed code.exec tool with the full dimple API available inside the sandbox (dimple.write, dimple.search, dimple.graph.*, …), plus resources, prompts, and change notifications
  • Code-mode execution: run TS/JS in a secure, fresh-per-run sandbox with the whole API as a dimple namespace: one line per operation, native control flow, and Promise.all for parallel calls (deny-by-default permissions; secure-exec is an optional peer)
  • API discovery: the search tool returns matching methods with signatures, when-to-use scenarios, and examples, so agents pick the right operation before writing code
  • Daemon lifecycle: dimple mcp start / stop / reload / status plus --print for client config
  • semantic / keyword search profiles now actually switch the retrieval legs (previously accepted but ignored in ranking)
  • updateEmbedding is idempotent: re-embedding an existing memory replaces it in place instead of failing
  • MCP results exclude embedding vectors (~1.5 KB of JSON noise per result): smaller agent context, faster round-trips
  • Prompt arguments with options (limit, includePending) work with standard MCP clients (the 2026 spec passes them as strings)
  • TypeScript guests run on plain Node (typescript ^5; newer majors are rejected with a clear pin hint)
  • The packed CLI runs on plain Node (no Bun-only runtime APIs) and installs cleanly in consumer projects
  • dimple init produced an invalid config template (baseUrl vs baseURL): every command after a fresh init failed; the template now boots as-is with zero env vars
  • First-boot races when the jobs database / log files’ directories did not exist yet
  • Runtime config reload: swap config (models, DB, settings) without restarting; failed reloads leave the current stack untouched
  • Indexing lifecycle: re-indexing a changed file updates its memory in place; deleted files and removed definitions are demoted; renames surface as review candidates; code units never expire
  • Call-graph edges: indexed code links callers to callees, same-file and across imports
  • Query budgets: cap results by units, characters, or time
  • Edge review: confirm / reject / expire candidate edges and explain a memory’s graph neighborhood
  • Optional local models: transformers is auto-installed on first use; hosted embedding providers need nothing installed
  • Remote databases: Turso (libsql://) for store + jobs with env-var token resolution
  • CLI polish: stdout is data-only (logs go to stderr), compact --json, dimple db-schema, fully annotated dimple init
  • Search profiles: semantic / keyword modes plus content-type filtering
  • Worker-ready builds: runs on edge runtimes without a filesystem service
  • Confirming a supersede edge now flips the old memory in the same transaction; get / forget / updateEmbedding accept logical keys
  • Updated dependencies
    • @ponraaj/dimple-sdk@0.0.0-alpha.5
  • Hosted embedding providers: OpenAI-compatible endpoints (OpenAI, ollama, vLLM, org gateways), Google, Cohere, and Amazon Bedrock
  • Per-model runtime options: device, precision/dtype, pooling, normalization, cache directory
  • Smaller embeddings on disk: quantized vector types (float8 is 4× smaller)
  • Multiple models side by side: per-model trees; switching models backfills embeddings idempotently
  • Tag-based publishing: v<version> tags trigger verified npm publishes
  • Packaging: self-contained type declarations, READMEs, changelog in tarballs
  • --version now reports the real package version
  • Updated dependencies
    • @ponraaj/dimple-sdk@0.0.0-alpha.4
  • --version now reports the real package version (was hardcoded)
  • Updated dependencies
    • @ponraaj/dimple-sdk@0.0.0-alpha.3
  • Per-model embedding options (device/dtype/pooling/normalize/cacheDir), full transformers dtype list, DB-level vector quantization (vectorType), package READMEs
  • Updated dependencies
    • @ponraaj/dimple-sdk@0.0.0-alpha.2