| layout | single | ||
|---|---|---|---|
| title | Configuration Reference | ||
| sidebar |
|
||
| toc | true | ||
| toc_label | Contents | ||
| toc_icon | sliders-h |
This document lists all environment variables and configuration options available in StratoSort Stack.
The AI stack runs in-process (node-llama-cpp + Orama). You only need models and OCR:
npm run setup:deps # Download models (best-effort)
npm run setup:models # Download GGUF models
npm run setup:models:check # Verify modelsThese variables affect setup scripts and postinstall behavior:
| Variable | Default | Description |
|---|---|---|
SKIP_APP_DEPS |
0 |
Skip postinstall native rebuild and all setup scripts |
SKIP_RUNTIME_VERIFY |
0 |
Skip the post-install verify:runtime-prereqs matrix display |
StratoSort Stack uses the Base (Small & Fast) profile by default (configurable in Settings → AI Configuration). A Better Quality profile with larger models is available during setup.
| Role | Default (Base) | Better Quality |
|---|---|---|
| Text | Llama-3.2-3B-Instruct-Q4_K_M.gguf |
Qwen2.5-7B-Instruct-Q4_K_M.gguf (128K context) |
| Vision | llava-v1.6-mistral-7b-Q4_K_M.gguf |
llava-v1.6-mistral-7b-Q4_K_M.gguf |
| Embedding | all-MiniLM-L6-v2-Q4_K_M.gguf |
nomic-embed-text-v1.5-Q8_0.gguf (768 dimensions) |
To change defaults before install, edit src/shared/aiModelConfig.js or set env vars:
STRATOSORT_TEXT_MODEL, STRATOSORT_VISION_MODEL, STRATOSORT_EMBEDDING_MODEL. See
src/shared/modelRegistry.js for the full catalog.
Users can add new models via Settings → Local AI Engine:
- Download Base Models — One-click download of the three default models (text, vision, embedding)
- Model Management → Add Model — Install any model from the registry by typing its exact
filename (e.g.
Qwen2.5-7B-Instruct-Q4_K_M.gguf,all-MiniLM-L6-v2-Q4_K_M.gguf) - Default AI Models — Select which installed model to use for text, vision, and embeddings
All installable models must be in modelRegistry.js; the catalog lists download URLs and metadata.
Based on node-llama-cpp docs and llama.cpp ecosystem:
| Category | Fastest options | Best quality-speed balance |
|---|---|---|
| Text | Llama-3.2-3B-Instruct-Q4_K_M (default), Phi-3-mini-4k-instruct-q4 |
Qwen2.5-7B-Instruct-Q4_K_M (Better Quality, 128K context) |
| Vision | llava-v1.6-mistral-7b-Q4_K_M (default; benefits from a GPU) |
llava-v1.6-mistral-7b-Q4_K_M |
| Embedding | all-MiniLM-L6-v2-Q4_K_M.gguf (default, ~21MB, 384 dim) |
nomic-embed-text-v1.5-Q8_0.gguf (Better Quality, 768 dim) |
Quantization: Per node-llama-cpp, Q4_K_M offers the best balance between compression and
quality; Q5_K_M is a close second. Q8_0 is higher quality but slower; smaller models (3B, Phi-3)
are faster than 7B on limited hardware.
Embedding dimensions: Changing embedding models changes vector dimensions (e.g. 384 for All-MiniLM vs 768 for Nomic). The index must be rebuilt when switching; the UI prompts for this.
| Variable | Default | Description |
|---|---|---|
TESSERACT_PATH |
- | Override path to the Tesseract binary (skips auto-install logic) |
TESSDATA_PREFIX |
Auto-set | Path to tessdata directory; auto-set for embedded runtime |
STRATOSORT_LOCAL_OCR_WORKERS |
auto | Override Tesseract.js worker pool size for local OCR fallback. Accepts a positive integer; non-numeric values use the auto value. |
AI_OCR_TIMEOUT |
60000 |
Timeout (ms) for AI-powered OCR operations. |
| Variable | Default | Description |
|---|---|---|
MAX_IMAGE_CACHE |
300 |
Maximum cached image analyses (50-1000) |
AUTO_ORGANIZE_BATCH_SIZE |
10 |
Files processed per auto-organize batch (1-100) |
STRATOSORT_INFERENCE_CONCURRENCY |
auto | Override the inference slot count used by ModelAccessCoordinator. Accepts a positive integer; non-numeric / non-positive values fall back to the platform-aware auto value. |
STRATOSORT_ORAMA_COMPRESS |
true |
When false, disables LZ4 compression of persisted Orama indexes (faster writes, larger on-disk footprint). Used for debugging corruption suspected to be compression-related. |
STRATOSORT_ORAMA_BATCH_UPSERT_CONCURRENCY |
auto | Override concurrent batch-upsert workers in OramaVectorService. Non-numeric values fall back to the service default. |
These flags tune where embeddings run and whether the pipeline blocks when the in-process embedding queue is saturated. Defaults favor throughput; enable waits only when debugging queue overload.
| Variable | Default | Description |
|---|---|---|
STRATOSORT_ENABLE_EMBEDDING_WORKER |
off | When true, runs embeddings in a separate embeddingWorker thread (extra VRAM / maxThreads: 1). Omit or false for main-process embeds. |
STRATOSORT_ANALYSIS_EMBEDDING_QUEUE_WAIT |
off | When true, analysis paths call waitForAnalysisQueueCapacity before enqueueing embeddings. |
STRATOSORT_ORGANIZE_EMBEDDING_QUEUE_WAIT |
off | When true, organize / embedding sync waits on waitForOrganizeQueueCapacity before enqueueing. |
STRATOSORT_PRUNE_PHANTOM_FOLDER_EMBEDDINGS |
on | When true/unset, FolderMatchingService.batchUpsertFolders calls pruneStaleFolders to delete vector-DB folder embeddings not in the current smart-folder set (e.g. "Images"/"Documents" left over from a removed default taxonomy). Set to false or 0 to disable the prune step. |
STRATOSORT_ATLAS_FIT_TIMEOUT_MS |
180000 | Max time (ms) the AtlasProjectionService UMAP worker may spend on a full projection fit before the worker is recycled and the fit fails over to the in-process fallback. Raise for very large corpora on slow hardware. |
By default STRATOSORT_ENABLE_EMBEDDING_WORKER is unset and treated as off: embeddings run through
LlamaService in the main process, so ParallelEmbeddingService can use the recommended
concurrency and VRAM is accounted for by the model memory manager.
Setting STRATOSORT_ENABLE_EMBEDDING_WORKER=true starts a separate embeddingWorker thread that
loads its own node-llama-cpp stack. That pool runs with maxThreads: 1, which caps parallel
embedding throughput, and it can hold a second copy of the embedding model in VRAM that the
main-process memory manager does not see. Enable it only for isolation experiments or debugging. The
worker selects its GPU backend the same way as the main process (supported-backend filter and the
remembered backend from gpu-backend-cache.json, read-only), so it does not re-test GPU binaries
the main process has already ruled out.
The two queue waits are off by default for the same throughput reason.
STRATOSORT_ANALYSIS_EMBEDDING_QUEUE_WAIT=true restores the per-file waitForAnalysisQueueCapacity
call in the folder and image enqueue paths (the batch orchestrator still applies the primary
backpressure). STRATOSORT_ORGANIZE_EMBEDDING_QUEUE_WAIT=true restores the
waitForOrganizeQueueCapacity wait before organize-queue enqueue.
These settings are configurable via Settings > Performance > Processing limits:
| Setting | Default | Description |
|---|---|---|
autoConcurrency |
true |
Hardware-aware concurrency. When on, the effective analysis concurrency is chosen automatically from detected GPU VRAM, CPU threads, and RAM, and maxConcurrentAnalysis is ignored. Turn off to pin a manual value. Existing installs adopt this automatically on upgrade. |
maxConcurrentAnalysis |
1 | Manual concurrency override (1–8 effective). Only applied when autoConcurrency is off. Higher values need more VRAM/RAM and can slow analysis or crash on limited hardware. |
maxImageFileSize |
100 MB | Maximum size for image analysis. |
maxDocumentFileSize |
200 MB | Maximum size for document extraction. |
maxTextFileSize |
50 MB | Text files over this limit are analyzed from their first 50 MB. |
captionVideoKeyframes |
false |
Describe extracted video keyframes with the vision model during media analysis (slow on CPU). |
| Variable | Default | Description |
|---|---|---|
SERVICE_CHECK_TIMEOUT |
(unset) | Validated at preflight (must be 100–60000ms when set) but not yet applied to the hardcoded health-check timeouts. Reserved for future wiring. |
STRATOSORT_STRICT_FILE_OPS |
off | When true, the file-operation IPC handlers (single move, copy and delete, and batch organize) accept only sources and destinations under the app data directory or a watched Smart Folder root. Symlink, traversal and system-directory checks apply whether or not this is set. Use to harden non-default install profiles or run security tests. |
| Variable | Default | Description |
|---|---|---|
STRATOSORT_FORCE_SOFTWARE_GPU |
0 |
Set to 1 to force software rendering |
ELECTRON_FORCE_SOFTWARE |
0 |
Alternative software rendering flag |
ANGLE_BACKEND |
d3d11 |
ANGLE backend for GPU rendering (Windows) |
STRATOSORT_GL_IMPLEMENTATION |
- | Override OpenGL implementation |
STRATOSORT_IGNORE_GPU_BLOCKLIST |
0 |
Ignore Electron GPU blocklist (advanced) |
STRATOSORT_DISABLE_BACKGROUND_THROTTLING |
0 |
Set 1 to disable Chromium background-page throttling so analysis keeps running at full speed when the window is hidden. Increases idle CPU. |
STRATOSORT_FORCE_SOFTWARE_GPU, ELECTRON_FORCE_SOFTWARE and --safe-mode also run the AI engine
on the CPU. On Windows and macOS the app no longer appends Chromium's enable-gpu-rasterization or
enable-zero-copy switches, so GPU rasterization follows Chromium's own per-driver decision. Linux
still appends both, as every earlier release did on all platforms, because Chromium's Linux default
varies with version and driver and the AppImage has not been measured without them. Software mode
appends neither.
Automatic software fallback (.gpu-fallback). After three GPU process exits in one session,
each within an hour of the one before (the count restarts after an hour with no exit), the app
writes .gpu-fallback to its data directory (%APPDATA%\StratoSort Stack on Windows). While the
file is less than 3 days old, counted from when it was last written, every launch renders in
software; this does not move the AI engine to the CPU. The file is not deleted when it is read, and
a software-rendered session never deletes it. Once it is older than 3 days, launches use hardware
acceleration again, and the first one whose window is visible 30 seconds
(TIMEOUTS.GPU_FALLBACK_STABLE_RUN) after it was created, with no GPU process exit in that time,
deletes the file and logs [GPU] Hardware acceleration ran stably; GPU fallback flag cleared. Three
more such exits write it again. To retry hardware acceleration sooner, quit the app and delete the
file. The log lines for each case are listed in
DEBUGGING_GUIDE.md.
| Variable | Default | Description |
|---|---|---|
STRATOSORT_DEBUG |
0 |
Enable debug mode with verbose logging |
STRATOSORT_REDACT_PATHS |
0 |
Redact file/folder paths in the UI (demo-safe) |
STRATOSORT_TOUR_HEADED |
0 |
Show the Electron window while npm run tour:record captures the product tour (scripts/record-product-tour.js) |
STRATOSORT_TOUR_ATLAS |
0 |
Set 1 to add the Atlas map shot to a non-library tour take. Atlas needs WebGPU and a library of a few hundred files, so the default six-file highlight tour leaves it out |
STRATOSORT_GRAPH_ENABLED |
1 / on |
Master toggle for Knowledge Graph / advanced graph UI (src/shared/featureFlags.js; set 0 or false to disable) |
Other STRATOSORT_GRAPH_* names may appear in older docs; they are not read by the codebase.
Graph behavior besides this master toggle is controlled in-app (experience mode and settings).
Run npm run docs:env-audit to list STRATOSORT_* names referenced in src/ (static scan). Use it
when updating this document or .env.example; it does not prove a variable is user-facing.
Packaged builds check the public GitHub Releases feed for updates by default; development and
unpackaged runs never do. Packaged copies that cannot replace themselves never check either: on
Windows, a copy the NSIS installer did not install (the x64 -win-x64.zip extracted by hand; the
app looks for Uninstall StratoSort Stack.exe next to its exe), a Microsoft Store install, and on
Linux anything but the AppImage. Their log shows
[UPDATER] Auto-updates skipped for this build target with a reason, and Check for updates in
Settings → Application shows the same reason as a warning. Users can turn background checks off in
Settings → Application, and STRATOSORT_ENABLE_AUTO_UPDATES=false disables the updater entirely.
See UPDATE_HOST.md for hosting a custom feed.
| Variable | Default | Description |
|---|---|---|
STRATOSORT_ENABLE_AUTO_UPDATES |
on (packaged) | Unset: on in packaged builds, off otherwise. Set to false to disable startup and manual update checks; set to true to force them on. |
STRATOSORT_UPDATE_FEED_URL |
- | Optional HTTPS base URL of a generic feed (directory containing latest.yml and referenced .exe / .blockmap files). Overrides the packaged GitHub provider when set. |
STRATOSORT_UPDATE_FEED_ALLOWED_HOSTS |
- | Comma-separated hostname allowlist for STRATOSORT_UPDATE_FEED_URL. Required in packaged builds when a custom feed is configured — prevents arbitrary update endpoints from being injected at runtime. Example: updates.example.com,backup-updates.example.com. |
STRATOSORT_BUILD_SHA |
- | Optional commit SHA injected at build time. When set, the value is surfaced in the in-app About dialog and prefilled into bug reports so support can correlate a user's running build with a specific commit. Typically wired in CI (e.g. cross-env STRATOSORT_BUILD_SHA=$GITHUB_SHA). |
STRATOSORT_LICENSE_SIGNING_KEY |
- | Vendor-side only — never set on user machines or in CI. Path to the Ed25519 private key PEM used by scripts/license/sign-license.js to mint offline-verifiable license keys at purchase-fulfillment time. The app itself only embeds the public half (src/shared/licensePublicKey.js) and never reads this variable. |
| Variable | Default | Description |
|---|---|---|
STRATOSORT_CONSOLE_LOGS |
0 |
Enable console logging in production (1 to enable) |
STRATOSORT_MAX_LOG_MB |
100 |
Size threshold (megabytes) at which the active session log rolls over to stratosort-<timestamp>-N.log. The rotation poll runs every 15s. ENOSPC / EDQUOT / EROFS / EACCES / EPERM on the file stream raises a user-visible degraded flag and stops further file writes. |
| Variable | Default | Description |
|---|---|---|
STRATOSORT_WATCHER_DEPTH |
10 |
Maximum subdirectory recursion depth used by SmartFolderWatcher for both chokidar live-watch and the manual _scanDirectory rescan path. Accepted range 0-32; out-of-range or non-numeric values fall back to the default. Raise only for unusually deep trees — higher values multiply watch-handle cost. |
| Variable | Default | Description |
|---|---|---|
NODE_ENV |
production |
Set to development for dev mode features |
FORCE_DEV_TOOLS |
unset | Set to enable Chromium DevTools even when not in the usual unpackaged-dev path. Dev-only. |
USE_DEV_SERVER |
unset | Set to load the renderer from the webpack-dev-server instead of dist/index.html. Dev-only. |
DEV_SERVER_PORT |
(webpack default) | Override the webpack-dev-server port when USE_DEV_SERVER is set. |
LLAMA_ARG_LOG_VERBOSITY |
2 |
Passed through to the vision llama-server child via buildLlamaChildEnv. Higher values increase llama.cpp log noise. |
REACT_DEVTOOLS |
false |
Set to true to enable React DevTools in dev |
STRATOSORT_SCAN_STRUCTURE_DELAY_MS |
- | Dev-only delay for folder scan IPC (ms) |
STRATOSORT_E2E_USER_DATA |
- | Override Electron userData directory for Playwright E2E isolation. Set only during automated tests. |
STRATOSORT_E2E |
- | Set to 1 by the Playwright E2E harness to mark end-to-end test mode. Enables the DevTools capability on app windows (unpackaged builds only; does not auto-open them) so the window-state DevTools spec can exercise open/close. Not for production use. |
STRATOSORT_DISABLE_PISCINA |
false |
Set true to disable the Piscina worker pools (fall back to inline execution). For debugging hangs / native crashes in workers; significant throughput regression. |
STRATOSORT_FORCE_LAUNCH |
0 |
Set 1 to bypass the single-instance lock check. Intended for debugging only — concurrent instances can corrupt the Orama / SQLite databases. It cannot bypass the user-data lock file (.stratosort.userdata.lock); a lock left by an unclean exit is reclaimed five minutes after its last heartbeat. |
STRATOSORT_USERDATA |
- | Override path used by scripts/monitor-batch-progress.js to locate analysis-history.json. Useful when inspecting a packaged build's userData from the host shell. |
STRATOSORT_ALLOW_DEV_CLEAN |
0 |
Set 1 to let npm run dev's clean step delete dist/ and .webpack-cache even while another StratoSort instance is running. Escape hatch for wedged userData locks — ordinarily the running app holds the lock and the dev script aborts to prevent ripping dist/preload.js out from under the live renderer. See scripts/check-running-instance.js. |
| Variable | Default | Description |
|---|---|---|
STRATOSORT_RUNTIME_DIR |
- | Override bundled runtime root (deprecated; only used for embedded OCR binaries) |
The AI stack runs fully in-process. No external runtime staging is required.
All timing and tuning constants are centralized in src/shared/performanceConstants.js. These are
organized into categories:
| Constant | Value | Description |
|---|---|---|
DEBOUNCE_INPUT |
300 | Input debounce delay |
AI_ANALYSIS_SHORT |
30,000 | Short AI analysis timeout |
AI_ANALYSIS_MEDIUM |
60,000 | Medium AI analysis timeout |
AI_ANALYSIS_LONG |
300,000 | Long AI analysis timeout (5 min; CPU vision) |
AI_ANALYSIS_BATCH |
1,800,000 | Batch analysis timeout (30 min) |
ANALYSIS_LOCK |
300,000 | Max lock duration before force release |
GLOBAL_ANALYSIS |
600,000 | Max total analysis time (10 min) |
WINDOW_SHOW_FALLBACK |
4,000 | Show the main window if ready-to-show has not fired |
FIRST_PAINT_GATE |
3,000 | Longest wait for the first paint before AI bring-up starts |
DEFAULT_FOLDER_PROBE |
3,000 | Cap on each stat or mkdir of the Uncategorized folder before the window exists; startup continues without it |
GPU_FALLBACK_STABLE_RUN |
30,000 | Time after window creation at which a stable hardware-accelerated run clears .gpu-fallback |
| Constant | Value | Description |
|---|---|---|
MAX_ATTEMPTS_LOW |
2 | Low-priority retry attempts |
MAX_ATTEMPTS_MEDIUM |
3 | Medium-priority retry attempts |
MAX_ATTEMPTS_HIGH |
5 | High-priority retry attempts |
FILE_OPERATION |
3 attempts | File operation retry config |
AI_ANALYSIS |
2 attempts | AI analysis retry config |
| Constant | Value | Description |
|---|---|---|
MAX_FILE_CACHE |
500 | Maximum cached files |
MAX_IMAGE_CACHE |
300 | Maximum cached images |
MAX_EMBEDDING_CACHE |
1000 | Maximum cached embeddings |
MAX_ANALYSIS_CACHE |
200 | Maximum cached analyses |
| Constant | Value | Description |
|---|---|---|
MAX_CONCURRENT_FILES |
5 | Max files processed concurrently |
MAX_CONCURRENT_ANALYSIS |
3 | Max concurrent AI analyses |
EMBEDDING_BATCH_SIZE |
50 | Embeddings per batch |
EMBEDDING_PARALLEL_SIZE |
10 | Parallel embedding operations |
| Constant | Value | Description |
|---|---|---|
CONFIDENCE_LOW |
0.3 | Low confidence threshold |
CONFIDENCE_MEDIUM |
0.6 | Medium confidence threshold |
CONFIDENCE_HIGH |
0.8 | High confidence threshold |
DEFAULT_CONFIDENCE_PERCENT |
70 | Default document confidence |
DEFAULT_IMAGE_CONFIDENCE_PERCENT |
75 | Default image confidence |
FOLDER_MATCH_CONFIDENCE |
0.55 | Min score for folder matching |
| Constant | Value | Description |
|---|---|---|
MAX_TEXT_FILE_SIZE |
50 MB | Maximum text/code file size |
MAX_IMAGE_FILE_SIZE |
100 MB | Maximum image file size |
MAX_DOCUMENT_FILE_SIZE |
200 MB | Maximum document file size |
MAX_AUDIO_FILE_SIZE |
1 GB | Maximum audio file (selection) |
MAX_VIDEO_FILE_SIZE |
2 GB | Maximum video file (selection) |
| Constant | Value | Description |
|---|---|---|
MIN_WORKERS |
1 | Minimum analysis workers |
DEFAULT_WORKERS |
1 | Default analysis workers |
MAX_WORKERS |
8 | Maximum analysis workers |
FOLDER_SCAN |
50 | Concurrent folder scan operations |
User settings are persisted in the application's data directory:
- Windows:
%APPDATA%\StratoSort Stack\settings.json - macOS:
~/Library/Application Support/StratoSort Stack/settings.json - Linux:
~/.config/StratoSort Stack/settings.json
The file holds only the settings the user has changed, plus settingsSchemaVersion,
experienceMode and autoConcurrency, whose presence carries meaning on load. Anything equal to a
current default, or to a default an earlier build shipped (SUPERSEDED_DEFAULTS in
src/shared/defaultSettings.js), is dropped on save and ignored on load, so a default that changes
in a later release reaches every install that never touched that setting. A hand-edited value that
happens to equal the current default is treated as "not set" and will follow future defaults.
The app also keeps these files in the same data directory. Both are safe to delete while the app is closed.
.gpu-fallback: present while software rendering is forced after repeated GPU process exits; see GPU Configuration.gpu-backend-cache.json: the last GPU backend the AI engine used successfully; see llama.cpp binary management.
The default Uncategorized smart folder is created in the user's Documents folder. Startup does not
wait more than 3 seconds (TIMEOUTS.DEFAULT_FOLDER_PROBE) on any check or creation of it: a slow
Documents folder is logged and skipped for that launch, and the folder is then created in the
background or by the first organize into it. When Documents refuses the folder (for example under
Controlled folder access), the folder keeps its Documents path and the app shows a warning; it is
tried again on every launch. It is never moved under the data directory, because organize moves user
files into it and the uninstaller's "remove settings and data" option deletes that directory.
Configuration validation is defined in src/shared/config/configSchema.js. The schema ensures type
safety and provides default values for all settings.
Set environment variables before launching the application:
# Linux/macOS
export MAX_IMAGE_CACHE=500
./stratosort
# Windows (PowerShell)
$env:MAX_IMAGE_CACHE = "500"
.\stratosort.exeMost user-facing settings can be configured through the Settings phase in the application UI.
If experiencing rendering problems:
export STRATOSORT_FORCE_SOFTWARE_GPU=1If the app switched itself to software rendering after repeated GPU crashes, it stays there for up
to 3 days; delete .gpu-fallback from the data directory while the app is closed to retry hardware
acceleration sooner. For a slow first window on Windows, follow
First window takes a long time on Windows.
If AI analysis fails due to missing models:
npm run setup:models
npm run setup:models:checkThe Orama index is stored locally and rebuilt on demand. If results look stale, re-run analysis or trigger a rebuild from the app UI.
These variables tune internal behavior and are intentionally undocumented in the main settings UI. They are listed here for support engineers and contributors who need to debug edge cases.
| Variable | Default | Purpose |
|---|---|---|
STRATOSORT_LLAMA_CPP_TAG |
b9000 |
Pinned llama.cpp release tag downloaded on first run |
STRATOSORT_LLAMA_CPP_URL |
(auto) | Override the binary download URL. Pair with STRATOSORT_LLAMA_CPP_SHA256 to keep integrity checking — overriding without a matching SHA256 disables verification |
STRATOSORT_LLAMA_CPP_SHA256 |
(auto) | Expected SHA-256 of the downloaded binary; mismatches abort with a clear error |
STRATOSORT_LLAMA_CPP_ALLOWED_HOSTS |
github releases | Comma-separated allowlist of hosts that may serve the binary download |
STRATOSORT_CUDA_VERSION |
12.4 |
CUDA release variant of the Windows GPU vision runtime to download (12.4 or 13.1) |
STRATOSORT_LLM_GPU_BACKEND |
(auto-detected) | cuda, metal, vulkan, or cpu — overrides backend autoselection; an explicit value also bypasses node-llama-cpp's supported-backend filter |
STRATOSORT_LLAMA_SERVER_PATH |
(bundled) | Absolute path to the llama-server binary; bypasses the bundled download |
Last-known-good GPU backend (gpu-backend-cache.json). After the text and embedding engine
settles on a GPU backend (cuda, vulkan or metal), the app saves it to gpu-backend-cache.json
in its data directory together with a fingerprint: platform, architecture, app version,
node-llama-cpp version, and the detected GPU type, name and driver version (from nvidia-smi on
NVIDIA GPUs, from Windows' video controller entry otherwise; Linux without nvidia-smi and macOS
report none). A driver update therefore makes the next launch run the full ladder. The record also
keeps the GPU backends node-llama-cpp reported as supported at the time, so installing a CUDA
toolkit (or anything else that changes that set) makes the next launch run the full ladder again
instead of keeping an earlier Vulkan result first. On later launches a record whose fingerprint and
supported set match and that is less than 14 days old puts that backend first in the candidate list
([LlamaService] Llama backend candidates ordered by cached selection), so candidates that failed
before are not tested again. It only changes the order: on Windows node-llama-cpp still test-loads
the binary, and if the remembered backend fails, the record is deleted
([LlamaService] Cleared cached Llama backend after it failed) and the normal ladder continues. A
CPU result is never saved, and an unchanged record is not rewritten; a new or changed GPU result
logs [LlamaService] Saved Llama backend selection for the next launch.
STRATOSORT_LLM_GPU_BACKEND, STRATOSORT_FORCE_SOFTWARE_GPU, ELECTRON_FORCE_SOFTWARE and
--safe-mode bypass the record: it is neither read nor changed while they are set. Deleting the
file while the app is closed makes the next launch run the full ladder. With
STRATOSORT_ENABLE_EMBEDDING_WORKER=true the worker thread reads the same record and applies the
same supported-backend filter, but only the main process saves or deletes the record; a failed
attempt there logs [EmbeddingWorker] Cached Llama backend failed; record left to its owner.
| Variable | Default | Purpose |
|---|---|---|
STRATOSORT_PERSISTENCE_BACKEND |
sqlite |
Global backend default for on-disk stores (analysis history, embedding queue). sqlite uses better-sqlite3; any other value (e.g. json) selects the legacy JSON-file backend |
STRATOSORT_EMBEDDINGQUEUE_BACKEND |
(inherits global) | Per-store override for the embedding queue; sqlite vs any other value (JSON-file backend). Takes precedence over STRATOSORT_PERSISTENCE_BACKEND |
STRATOSORT_ANALYSISHISTORY_BACKEND |
(inherits global) | Per-store override for analysis history; sqlite vs any other value (JSON-file backend). Takes precedence over STRATOSORT_PERSISTENCE_BACKEND |
STRATOSORT_SQLITE_COMPRESS |
on | Compresses SQLite payloads on write (read transparently). Set false to store them uncompressed |
STRATOSORT_USE_OFFICIAL_PDFJS |
false |
Set true to load the official pdfjs-dist build instead of the pdf.js bundled with unpdf |
| Variable | Default | Purpose |
|---|---|---|
STRATOSORT_IMAGE_WORKER_THREADS |
(auto) | Override image-worker pool size |
STRATOSORT_OCR_WORKER_THREADS |
(auto) | Override OCR worker pool size |
STRATOSORT_TEXT_EXTRACTION_WORKER_THREADS |
(auto) | Override text-extraction worker pool size |
| Variable | Default | Purpose |
|---|---|---|
STRATOSORT_VISION_BATCH_SIZE |
(model-dependent) | Vision inference batch size |
STRATOSORT_VISION_UBATCH_SIZE |
(model-dependent) | Vision inference micro-batch size |
STRATOSORT_VISION_KEEPALIVE_MS |
60000 |
llama.cpp server idle keepalive (VISION_IDLE_KEEPALIVE) |
STRATOSORT_IMAGE_PREFLIGHT_TTL_MS |
15000 |
Image preflight cache TTL |
STRATOSORT_JSON_REPAIR_TIMEOUT_MS |
15000 |
LLM JSON repair timeout |
STRATOSORT_PROSE_EXTRACTION_TIMEOUT_MS |
15000 |
Prose extraction timeout |
scripts/setup-vision-runtime.js stages the platform-specific vision binary during
npm run package / npm run dist*. These overrides only matter when cross-packaging from a
different host architecture.
| Variable | Default | Purpose |
|---|---|---|
STRATOSORT_VISION_RUNTIME_PLATFORM |
host OS | Override target platform (win32, darwin, linux). |
STRATOSORT_VISION_RUNTIME_ARCH |
process.arch |
Override target arch (x64, arm64). |
MediaTranscoder invokes a bundled LGPL-3 FFmpeg binary via subprocess for audio/video
preprocessing (Whisper PCM, video keyframes). The binary is staged by
scripts/setup-ffmpeg-runtime.js during npm run dist*, into assets/runtime/ffmpeg/. Current
platform matrix (see the script header for details): Windows (BtbN win64-lgpl), macOS x64
- arm64 (StratoSort self-hosted
ffmpeg-mac-{x64,arm64}.zipfrombuild-ffmpeg-lgpl.yml), and Linux x64 + arm64 (BtbNmaster-latest-{linux64,linuxarm64}-lgpl.tar.xz). Windows arm64 ships without a bundled FFmpeg (no upstream LGPL build) and relies on the PATH fallback.
| Variable | Default | Purpose |
|---|---|---|
STRATOSORT_FFMPEG_PATH |
(bundled) | Absolute path to a system-managed ffmpeg binary. Overrides the bundled lookup. Useful for tests and operators who maintain their own ffmpeg. Must exist on disk. |
STRATOSORT_FFMPEG_TAG |
(per-platform) | Release tag pulled by setup:ffmpeg-runtime. Windows/Linux pull a BtbN/FFmpeg-Builds tag; macOS resolves the StratoSort self-hosted tag (ffmpeg-lgpl-latest). Pin for reproducibility. |
STRATOSORT_FFMPEG_URL |
(auto) | Override the download URL entirely. Hostname is allowlist-validated; arbitrary URLs are rejected. |
STRATOSORT_FFMPEG_RUNTIME_PLATFORM |
host OS | Override target platform (win32, darwin, linux) when packaging cross-platform. |
STRATOSORT_FFMPEG_RUNTIME_ARCH |
process.arch |
Override target arch (x64, arm64). |
SKIP_FFMPEG_RUNTIME |
false |
Skip the download step in CI / fast-dev workflows. The runtime resolver falls back to PATH, so any system-installed ffmpeg is used at runtime. |
STRATOSORT_USE_REAL_WHISPER |
false |
Read by scripts/run-real-media.js only. When set to 1, the standalone harness swaps its stub Whisper for the production WhisperService so it loads the real GGML model and produces actual transcripts. Off by default so the harness keeps loading in environments without the native binding. Has no effect on the running app, just on the dev harness. |
tesseractJsPaths.js resolves the OCR language model with a three-tier precedence: a bundled
assets/runtime/tessdata/<lang>.traineddata[.gz] (staged by scripts/setup-tessdata-runtime.js
during npm run dist*, same runtime/** extraResources glob as FFmpeg) → a previously downloaded
copy under userData/tessdata-cache → tesseract.js's own CDN default (cdn.jsdelivr.net), which is
warned once per process. Bundling keeps OCR fully offline; without it, the first OCR fetches the
model from jsdelivr and caches it.
| Variable | Default | Purpose |
|---|---|---|
STRATOSORT_TESSDATA_URL |
(auto) | Override the download URL entirely. Hostname is allowlist-validated (cdn.jsdelivr.net); non-HTTPS, credentialed, or off-allowlist hosts are rejected. |
STRATOSORT_TESSDATA_VARIANT |
4.0.0 |
@tesseract.js-data/<lang>/<variant>/ directory segment — the model quality variant tesseract.js itself would fetch. Pin for reproducibility. |
STRATOSORT_TESSDATA_SHA256 |
(pinned) | Override the expected sha256. The default eng model is pinned in the script and always verified (mismatch aborts); other languages or a custom URL are verified only when this is set. |
SKIP_TESSDATA_RUNTIME |
false |
Skip the download step in CI / fast-dev workflows. The runtime resolver falls back to the userData cache, then the tesseract.js CDN default on first OCR. |
WhisperService loads @fugood/whisper.node via a per-platform/per-GPU variant package. The loader
walks an ordered candidate list (best-first) and uses the first one whose require() succeeds:
| GPU detected | Platform | Candidate order |
|---|---|---|
NVIDIA (cuda) |
win32, linux | cuda → vulkan → default (CPU) |
AMD / Intel (vulkan) |
win32, linux | vulkan → default |
| Any | darwin | default (Metal acceleration is built in) |
| None / unknown | any | default (CPU) |
The CUDA variant requires the CUDA runtime DLLs (cudart64_*.dll etc.) on PATH. Many users have
the toolkit installed but not configured for Node's process environment — the cuda candidate
require()s fine on disk but fails to dlopen with ERR_DLOPEN_FAILED. In that case the loader
falls through to vulkan, which always works for NVIDIA users because the Vulkan loader ships with
the GPU driver. No user-visible failure: GPU acceleration still engages; the variant label just
flips from cuda to vulkan.
The resolved variant is surfaced two ways:
- Settings → About → "Media (Whisper)" shows e.g.
vulkan on cuda · ggml-base.en.bin. The two fields are independent:cudais the detector's vendor label,vulkanis the variant that actually loaded. A mismatch like that is the headline sign that CUDA runtime DLLs aren't on PATH. - The
system:get-runtime-infoIPC response includes amediaStack.whisper.resolvedVariantfield consumed by the bug-report URL builder, so support tickets surface this without an extra round trip.
The variant chain logic is in WhisperService.loadNativeWhisperModule (the binding's own loader
uses ESM import(), which throws ERR_UNKNOWN_FILE_EXTENSION on .node files in our sandboxed
Electron environment — that's the reason for the custom loader). Test coverage in
test/WhisperService.loader.test.js exercises the full fallback chain with virtual mocks so CI
catches a regression even on runners that don't have GPU variant packages installed.
Knobs for the worktree-based stability/comparison harness used during release prep. Internal to the stability workflow; safe to ignore in normal development.
| Variable | Default | Purpose |
|---|---|---|
STRATOSORT_STABILITY_SKIP_WORKTREE_INSTALL |
0 |
Set 1 to skip npm install in the comparison worktree (you already linked or copied node_modules manually). |
STRATOSORT_STABILITY_FULL_WORKTREE_INSTALL |
0 |
Set 1 to run npm ci in the comparison worktree instead of the lighter default install path. |
The MCP server lets external Model Context Protocol clients (Claude Desktop, Cursor, Zed, etc.) search and chat with the documents StratoSort has analyzed. It is off by default and must be explicitly enabled in Settings → MCP Server. See MCP_SERVER.md for the full user-facing guide and tool reference.
| Variable | Default | Purpose |
|---|---|---|
STRATOSORT_MCP_PORT |
53827 |
Initial bind port. If taken, binds an OS-assigned ephemeral port (listen(0)) and reports the actual port. Loopback (127.0.0.1) only — non-loopback binds are not supported. |
The bearer token is generated locally on first enable and stored under userData/mcp-token.bin,
encrypted via safeStorage when the OS keystore is available (DPAPI on Windows, Keychain on macOS,
libsecret on Linux). There is no env var to override it; rotate from Settings if it leaks.
StratoSort can optionally route document analysis, chat, and organization suggestions to a cloud provider (Anthropic Claude, OpenAI, or any OpenAI-compatible endpoint including Ollama / LM Studio / vLLM). It is off by default and configured entirely through Settings → AI Provider. See AI_PROVIDERS.md for the full guide.
There are no environment variables for AI provider configuration — API keys are stored encrypted via
safeStorage and the per-feature/per-folder routing config is persisted in userData. Embeddings
always run locally regardless of any cloud routing.