Skip to content

Configuration reference

The config loader parses strict JSONC, with comments and trailing commas. Every section is optional except embedding: without models, there is nothing to embed or route.

dimple init writes the full annotated schema. ${ENV_VAR} placeholders resolve from the environment, so tokens stay out of the config file. Validation reports all problems in one pass.

{
// store
"storeUrl": "file:./.dimple/dimple.db",
// remote (Turso): "libsql://<org>-<db>.turso.io?authToken=${TURSO_MEMORIES_TOKEN}"
// durable jobs
"jobs": {
"dbUrl": "file:./.dimple/jobs.db", // separate DB for the job queue
"execution": "background", // background | inline | external (RESERVED — not yet
// wired; the background worker is always installed)
"concurrency": 4,
"leaseTimeoutMs": 120000, // RESERVED — not yet wired to the executor
"maxAttempts": 10, // clamped to [1, 100] → take maxAttempts
"pollIntervalMs": 1000, // RESERVED — not yet wired
},
// embeddings (REQUIRED)
"embedding": {
"defaultModel": "minilm", // the ACTIVE model for writes/queries
// ONNX Runtime session options EVERY model inherits (per-model blocks
// override them field by field). Split cores across parallel workers:
// "intraOpNumThreads": 4, // 4 on 8 cores with 2 workers (0 = runtime default = 1/core)
// "interOpNumThreads": 1, // only used when executionMode is "parallel"
// "executionMode": "sequential", // sequential | parallel
// "graphOptimizationLevel": "all", // disabled | basic | extended | all | layout
// "enableCpuMemArena": false, // dimple default (bulk ingest does not need the arena)
// "enableMemPattern": true,
// "gpuMemLimit": 2147483648, // CUDA arena cap in bytes
// "arenaExtendStrategy": 0, // 0 = next power of two, 1 = as requested
"models": [
// local, any Transformers.js ONNX model (auto-installed on first use)
{
"id": "minilm",
"provider": "transformers",
"model": "Xenova/all-MiniLM-L6-v2",
"dimensions": 384,
"autoInstall": true, // optional peer auto-install (default true)
// per-model runtime options (all optional, defaults shown):
// "device": "cpu", // auto|gpu|cpu|wasm|webgpu|cuda|dml|coreml|webnn
// "dtype": "q8", // fp32|fp16|q8|int8|uint8|q4|bnb4|q4f16|q2|q2f16|q1|q1f16
// "pooling": "mean", // mean|cls|none
// "normalize": true,
// "cacheDir": "~/.cache/dimple",
// "vectorType": "float32", // float32|float16|float8|float1bit
// per-model ORT session options, override the global block per field:
// "sessionOptions": { "intraOpNumThreads": 2, "enableCpuMemArena": true },
// "wasm": { "numThreads": 4 }, // wasm backend ONLY, intra-op threads do not reach it
},
// hosted, any OpenAI-compatible endpoint (default https://api.openai.com/v1)
{
"id": "openai",
"provider": "openai",
"model": "text-embedding-3-small",
"dimensions": 1536,
"apiKey": "${OPENAI_API_KEY}",
"baseURL": "https://api.openai.com/v1",
},
// native provider families, baseURL baked in, no baseURL needed
// { "id": "gemini", "provider": "google", "model": "gemini-embedding-2", "dimensions": 3072, "apiKey": "…" }
// { "id": "cohere", "provider": "cohere", "model": "embed-english-v3.0", "dimensions": 1024, "apiKey": "…" }
// { "id": "titan", "provider": "bedrock", "model": "amazon.titan-embed-text-v2:0", "dimensions": 1024 }
],
},
// topic tree shape (all optional, defaults shown)
"topics": {
"maxLeafItems": 128, // leaf overflow -> split
"minLeafItems": 32, // leaf underflow -> borrow/merge
"maxChildren": 16, // fan-out cap per split
"minChildren": 4,
"maxDepth": 6,
"beamWidth": 3, // beam width for the leaf resolver (Store.resolveTopics)
"splitDeferredHardLimit": 512, // force-split threshold for deferred leaves
"rebalanceCooldownMs": 60000, // min delay between rebalances
"lloydPasses": 2, // k-means refinement passes
},
// artifact graph (all optional, defaults shown)
"graph": {
"enabled": true,
"maxDepth": 2, // traversal depth
"maxNeighbors": 12, // per-node fan-out
"maxTotal": 80, // total neighborhood cap
"supersedeDemotion": 0.5, // score penalty for superseded results
"conflictBands": { "nearDuplicate": 0.9, "conflictLow": 0.6 },
"clusterK": 8, // dream concept-clustering K
"clusterMinSize": 3, // min members for a concept
},
// dream/repair LLM (optional, enables `dimple dream`)
"llm": {
"baseURL": "https://api.openai.com/v1", // any OpenAI-compatible endpoint
"apiKey": "${OPENAI_API_KEY}",
"modelId": "gpt-4o-mini",
"temperature": 0.2, // 0 to 2
"maxOutputTokens": 512, // positive integer
"reasoningEffort": "low", // low | medium | high
},
// logging (all optional, console is silent by default)
"logging": {
"enabled": true,
"level": "info", // trace | debug | info | warn | error
"format": "jsonl", // jsonl | pretty (console rendering)
"file": "./.dimple/logs.jsonl", // durable JSONL sink (off unless set)
"scopes": { "@dimple/store": "debug" }, // scope names are runtime logger names, not installable packages
"ringSize": 4096, // in-memory live tail
},
// retrieval/write defaults (all optional)
"defaultK": 60, // RRF smoothing constant
"defaultLimit": 10, // default result count
"defaultTtlSecs": 604800, // default write TTL in seconds; set ttlSecs:null per memory for no expiry
"sweepIntervalMs": 300000, // expiry sweep cadence (5 minutes)
}

In the jobs section, dbUrl, concurrency, and maxAttempts affect the SDK and CLI runtime. execution, leaseTimeoutMs, and pollIntervalMs are accepted, but they do not change runtime behavior yet. The SDK and CLI run workers in the process.

storeUrl and jobs.dbUrl accept remote libSQL URLs (libsql://, https://, and ws://) for Turso or any libSQL-compatible host. The same engine runs FTS5, vector search, the topic tree, and durable jobs over the network. This setup is verified against the Turso service.

Turso tokens are per database, so each URL carries its own token. ${ENV_VAR} resolution keeps them out of the config file:

{
"storeUrl": "libsql://<org>-<memdb>.turso.io?authToken=${TURSO_MEMORIES_TOKEN}",
"jobs": { "dbUrl": "libsql://<org>-<memdb>.turso.io?authToken=${TURSO_MEMORIES_TOKEN}" },
}

Notes:

  • One database can serve both memories and the durable queue, in separate table namespaces. The simplest setup shares one URL and one token. TURSO_TOKEN works as the fallback. A dedicated jobs database stays possible with TURSO_JOBS_URL and TURSO_JOBS_TOKEN.
  • The jobs database must also be remote when the store is remote, because the queue and workflow state cross invocations.
  • Remote URLs skip two file:-only behaviors: parent-directory creation and the migration lock.
  • On edge runtimes, use a hosted embedding provider. The local ONNX runtime is local and CLI-only.
providerModelsbaseURL needed?
transformersTransformers.js ONNX models. Runs locally and installs on first use.No
openai (default)OpenAI-compatible endpoints, including OpenAI, vLLM, Ollama, Groq, and Mistral.Optional. Defaults to OpenAI.
googleGoogle Gemini embedding models.No
cohereCohere Embed models.No
bedrockAmazon Titan and Nova embedding models. Uses AWS credentials from the environment.No

dimensions must match the model output. A mismatch returns a typed error on first use.

Multiple models can coexist. Each model gets its own vector tables and its own topic tree. defaultModel picks the active model. Queries route per model, and a backfill uses the durable memory.embed job.

Transformers runtime options (per model, all optional)

Section titled “Transformers runtime options (per model, all optional)”
FieldValuesDefaultWhat it does
deviceauto | gpu | cpu | wasm | webgpu | cuda | dml | coreml | webnncpuExecution backend. cpu and wasm are tested. CUDA on Linux x64 needs the provider and CUDA 12; see CUDA on Linux x64.
dtypefp32 | fp16 | q8 | int8 | uint8 | q4 | bnb4 | q4f16 | q2 | q2f16 | q1 | q1f16q8Quantizes model weights for inference. It does not quantize output vectors.
poolingmean | cls | nonemeanSentence-pooling strategy.
normalizebooleantrueL2-normalize the output.
cacheDirpathHF cacheOverride the model download cache.
autoInstallbooleantrueAuto-install the optional @huggingface/transformers peer on first use. Scripts are skipped.
sessionOptionsSee Session options.ORT defaults, except enableCpuMemArena: falseSet thread counts, execution mode, graph optimization, and memory arena options. gpuMemLimit caps GPU memory in bytes. arenaExtendStrategy selects the growth policy: 0 for the next power of two, 1 as requested. Set device: "cuda" to use the CUDA options. Tested at about 3.7 times CPU speed on a 4 GB card.
wasm{ numThreads? }ORT environment defaultSet the WASM backend thread count. Intra-op thread settings do not apply to WASM.

sessionOptions is one shared struct, accepted at two levels. embedding.sessionOptions is the default every model inherits. A model’s own block overrides it field by field.

The precedence is built-in defaults, then global, then model. A field left out keeps the ONNX Runtime default.

FieldValuesDefaultWhat it does
intraOpNumThreadsinteger 0 to 10240 (runtime)Threads used inside each operator. 0 means one thread per physical core for each session, so multiple Dimple processes can oversubscribe the machine.
interOpNumThreadsinteger 0 to 10240 (runtime)Threads used between operators. Read only when executionMode is parallel.
executionModesequential | parallelsequentialRun operators one after another, or in parallel.
graphOptimizationLeveldisabled | basic | extended | all | layoutallHow much the graph is fused or rewritten before inference. This is load-time work.
enableCpuMemArenabooleanfalseDimple default. The CPU arena preallocates and holds memory across runs (onnxruntime#11627), which bulk ingest does not need.
enableMemPatternbooleanORT defaultRecord and reuse an allocation for repeated input shapes. ONNX Runtime applies this only in sequential mode.
gpuMemLimitnumber (bytes)unboundedCap the CUDA arena. ONNX Runtime grows the arena by powers of two. Cards with 8 GB or less can run out of memory during a batch.
arenaExtendStrategy0 | 10CUDA arena growth policy. 0 is kNextPowerOfTwo. 1 is kSameAsRequested.

ONNX Runtime gives every session its own intra-op thread pool, sized at one thread per physical core. Two Dimple processes on an 8-core machine therefore run 16 threads. The processes share the same cores, so ingestion may not be faster than with one process.

Split the threads explicitly:

{
"embedding": {
// 8 physical cores, 2 ingest workers -> 4 threads each
"sessionOptions": { "intraOpNumThreads": 4 },
"defaultModel": "minilm",
"models": [
{
"id": "minilm",
"provider": "transformers",
"model": "Xenova/all-MiniLM-L6-v2",
"dimensions": 384,
},
],
},
}

The recipe is intraOpNumThreads = floor(physicalCores / workers). Set it once globally, because each worker process reads the same config. Override it per model when one model deserves a different share. Two caveats:

  • enableCpuMemArena stays false by default. The arena can add a small amount of single-process speed while holding memory across runs. Set "enableCpuMemArena": true globally or per model when you run one process and want that speed.
  • On the wasm backend, intraOpNumThreads is ignored. ONNX Runtime documents thread counts as Node-binding only, and the WASM backend reads env.wasm.numThreads instead. Set it in the wasm block ("wasm": { "numThreads": 4 }). The standalone dimple binary pins that value to 1. The embedded default is ONNX Runtime’s own (0, system-determined).

device: "cuda" runs inference on the GPU through the ONNX Runtime CUDA execution provider. The provider is not in the npm tarball. onnxruntime-node downloads it from NuGet in its own postinstall, and the CUDA runtime libraries must be visible to the dynamic loader.

bun run setup:cuda does both steps. bun run setup:cuda --check reports what is present and whether the provider resolves.

  1. The script runs the onnxruntime-node installer when the provider is missing. The download is about 196 MB from NuGet, and about 300 MB after extraction. The installer verifies only the HTTPS download and the ZIP structure, with no checksum. Treat it as any postinstall binary download.
  2. It stages the CUDA 12 and cuDNN 9 runtime wheels into ~/.cache/dimple/cuda12 with uv pip install --target and writes an env.sh there.
  3. Source ~/.cache/dimple/cuda12/env.sh before you start Dimple, or pass the printed LD_LIBRARY_PATH inline.

Version constraints: onnxruntime-node 1.24.3 requires CUDA 12.8 or newer and cuDNN 9.x. That is the version transformers.js pins. ONNX Runtime 1.27 ships CUDA 13 builds, but only for PyPI and NuGet. There is no Node binding, so a system CUDA 13 installation does not satisfy it, and the setup script pins the CUDA 12 wheels.

If the provider or a runtime library is missing, model load fails with the provider error naming the missing library, for example libcublasLt.so.12. There is no silent CPU fallback.

Bun is secure by default. It does not run lifecycle scripts for packages outside its trusted list, so the onnxruntime-node postinstall does not run here by default.

The setup script does the same work explicitly. CPU-only users need nothing. The default install stays CPU.

The per-memory search vectors are stored in the model’s vec_<dims>_<model> table and searched with libSQL’s native vector_distance_cos:

vectorTypeEncoding384-dim storedTested
float32 (default)float321536 BYes
float16bfloat16~790 BSeam exists
float8int8395 B (4x)Yes, on write, query, health, and split
float1bitbinary~48 B (32x)Partial. L2 is unsupported for 1-bit.

The topic tree centroids and memories.embedding stay float32. Quantization applies only to stored search vectors.

All failures are typed with precise messages:

  • temperature must be in [0, 2].
  • maxAttempts and maxOutputTokens are positive integers. maxAttempts is at most 100.
  • intraOpNumThreads, interOpNumThreads, and wasm.numThreads are integers in [0, 1024].
  • defaultModel must name a configured model. Unknown keys fail at first use.
  • A dimensions mismatch fails on first embed.
  • JSONC is strict. Duplicate keys are rejected.
  • Multiple problems are reported in one pass.

The loader also reads three variables directly, beyond the ${ENV_VAR} placeholders in the file:

VariableWhat it does
DIMPLE_CONFIGExplicit config file path. Overrides project discovery.
DIMPLE_CONFIG_CONTENTInline JSONC config content. No file is needed.
DIMPLE_CWDTreat this directory as the project root. Config discovery starts there, relative file: URLs resolve against it, and index() relative paths anchor to it. Use it for daemons, systemd units, and tests that run from a different working directory.

DIMPLE_CWD does not change the process working directory. It changes only the paths Dimple resolves. Leave it unset for normal use. Relative file:./.dimple/... defaults keep working against the process working directory.