diff --git a/.env.example b/.env.example
index 1485412..36cc589 100644
--- a/.env.example
+++ b/.env.example
@@ -77,33 +77,23 @@ RUN_FS_MIGRATIONS=
IMPORT_LIBRARY_DIR=
IMPORT_LIBRARY_DIRS=
-# Heavy compute is always worker-backed.
-# App server calls compute-worker over HTTP for ONNX whisper alignment + PDF layout parsing.
-# Embedded/local (`pnpm dev` / `pnpm start` without COMPUTE_WORKER_URL) uses this same file.
-# `compute/worker/.env*` is only for standalone external worker deployments.
-# In single-container self-host setups, run compute-worker + NATS alongside the app and
-# point COMPUTE_WORKER_URL at that internal worker endpoint.
-# Required:
+# Compute
+# Embedded/local (default): leave COMPUTE_WORKER_URL empty.
+# External worker: set COMPUTE_WORKER_URL + COMPUTE_WORKER_TOKEN.
+# Details: docs/deploy/compute-worker
# COMPUTE_WORKER_URL=http://localhost:8081
# COMPUTE_WORKER_TOKEN=local-compute-token
-# Optional embedded worker stack controls (used by scripts/openreader-entrypoint.mjs):
-# If COMPUTE_WORKER_URL is unset, entrypoint defaults to starting embedded worker+NATS.
-# Set START_EMBEDDED_COMPUTE_WORKER=false to force external worker URL/token config.
-# START_EMBEDDED_COMPUTE_WORKER=
+# Optional embedded startup controls:
# EMBEDDED_COMPUTE_WORKER_PORT=8081
# EMBEDDED_NATS_PORT=4222
# EMBEDDED_NATS_MONITOR_PORT=8222
# EMBEDDED_NATS_STORE_DIR=docstore/nats/jetstream
# NATS_URL=nats://127.0.0.1:4222
-# Optional shared compute timeouts used by:
-# - worker compute runtime
-# - worker client wait budgets
-# Worker-side concurrency is configured in compute-worker service via `COMPUTE_JOB_CONCURRENCY`.
+# Optional shared compute tuning:
# COMPUTE_JOB_CONCURRENCY=1
# COMPUTE_WHISPER_TIMEOUT_MS=30000
# COMPUTE_PDF_TIMEOUT_MS=300000
# COMPUTE_OP_STALE_MS=1800000
-# Worker mode requires worker-reachable shared object storage.
# Optional Whisper ONNX base URL override (must contain all expected files)
# WHISPER_MODEL_BASE_URL=https://huggingface.co/onnx-community/whisper-base_timestamped/resolve/main
diff --git a/compute/worker/.env.example b/compute/worker/.env.example
index f6188a6..3c38f5d 100644
--- a/compute/worker/.env.example
+++ b/compute/worker/.env.example
@@ -1,6 +1,6 @@
-# Standalone compute-worker env.
-# Used only when running compute-worker as a separate service/container.
-# Not used by app embedded worker startup via `pnpm dev` / `pnpm start`.
+# External compute-worker service env only.
+# Keep COMPUTE_WORKER_TOKEN and S3_* aligned with app env.
+# Details: docs/deploy/compute-worker
# Compute worker bind
# Platform note:
@@ -11,7 +11,7 @@
# COMPUTE_LOG_FORMAT=pretty
# COMPUTE_LOG_LEVEL=info
-# App <-> worker auth
+# Must match app env when app uses COMPUTE_WORKER_URL
COMPUTE_WORKER_TOKEN=local-compute-token
# NATS/JetStream
@@ -32,21 +32,17 @@ S3_SECRET_ACCESS_KEY=devsecret
S3_ENDPOINT=http://host.docker.internal:8333
S3_FORCE_PATH_STYLE=true
-# Queue + execution tuning
+# Optional tuning
# COMPUTE_PREWARM_MODELS=true
# COMPUTE_JOB_CONCURRENCY=1
# COMPUTE_WHISPER_TIMEOUT_MS=30000
# COMPUTE_PDF_TIMEOUT_MS=300000
-# Optional Whisper ONNX base URL override (must contain all expected files)
-# WHISPER_MODEL_BASE_URL=https://huggingface.co/onnx-community/whisper-base_timestamped/resolve/main
-# Optional PDF layout ONNX base URL override (must contain all expected files)
-# PDF_LAYOUT_MODEL_BASE_URL=https://huggingface.co/Bei0001/PP-DocLayoutV3-ONNX/resolve/main
# COMPUTE_PDF_JOB_ATTEMPTS=1
# COMPUTE_JOBS_STREAM_MAX_BYTES=268435456
-# JetStream stream size limit for op progress events (replay for SSE reconnect)
# COMPUTE_EVENTS_STREAM_MAX_BYTES=134217728
# COMPUTE_JOB_STATES_MAX_BYTES=67108864
# COMPUTE_NATS_REPLICAS=1
-# Optional stale window for reusing in-flight opKey entries before forcing a new attempt
-# Default is max(30m, 4x max compute timeout); running jobs also refresh heartbeat every 5s
# COMPUTE_OP_STALE_MS=1800000
+# Optional model mirrors
+# WHISPER_MODEL_BASE_URL=https://huggingface.co/onnx-community/whisper-base_timestamped/resolve/main
+# PDF_LAYOUT_MODEL_BASE_URL=https://huggingface.co/Bei0001/PP-DocLayoutV3-ONNX/resolve/main
diff --git a/docs-site/docs/deploy/local-development.md b/docs-site/docs/deploy/local-development.md
index 01dec45..14ca0a4 100644
--- a/docs-site/docs/deploy/local-development.md
+++ b/docs-site/docs/deploy/local-development.md
@@ -89,6 +89,41 @@ OpenReader currently pins `4.18` in CI and Docker builds while `4.19` compatibil
+
+NATS Server nats-server (required for embedded compute mode)
+
+If `COMPUTE_WORKER_URL` is unset, startup launches embedded compute worker + NATS, so `nats-server` must be available on host PATH.
+
+If you always use an external worker (`COMPUTE_WORKER_URL` set), this is not required.
+
+
+
+
+```bash
+brew install nats-server
+nats-server -v
+```
+
+
+
+
+```bash
+# Linux amd64 example
+mkdir -p "$HOME/.local/bin"
+curl -fsSL -o /tmp/nats-server.zip \
+ https://github.com/nats-io/nats-server/releases/latest/download/nats-server-v2.12.1-linux-amd64.zip
+unzip -j /tmp/nats-server.zip '*/nats-server' -d /tmp
+install -m 0755 /tmp/nats-server "$HOME/.local/bin/nats-server"
+echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
+export PATH="$HOME/.local/bin:$PATH"
+nats-server -v
+```
+
+
+
+
+
+
LibreOffice (optional, for DOCX conversion)
@@ -188,7 +223,6 @@ Default embedded worker flow (no external worker URL):
```env
# Leave COMPUTE_WORKER_URL unset.
# Entry point auto-starts embedded worker+NATS when available.
-START_EMBEDDED_COMPUTE_WORKER=
```
External worker flow:
diff --git a/docs-site/docs/reference/environment-variables.md b/docs-site/docs/reference/environment-variables.md
index 190dc93..005ef32 100644
--- a/docs-site/docs/reference/environment-variables.md
+++ b/docs-site/docs/reference/environment-variables.md
@@ -55,7 +55,6 @@ For auth-enabled deployments, use **Settings → Admin** as the primary source o
| `IMPORT_LIBRARY_DIRS` | Library import | unset | Set multiple roots (comma/colon/semicolon separated) |
| `COMPUTE_WORKER_URL` | Heavy compute backend | unset | Set only for standalone external compute worker; leave unset for embedded worker startup |
| `COMPUTE_WORKER_TOKEN` | Heavy compute backend | unset (auto-generated in embedded startup) | Required for standalone external compute worker auth; must match worker |
-| `START_EMBEDDED_COMPUTE_WORKER` | Heavy compute backend | auto (`true` when `COMPUTE_WORKER_URL` unset) | Set `false` to disable embedded worker startup and require external worker URL/token |
| `EMBEDDED_COMPUTE_WORKER_PORT` | Heavy compute backend | `8081` | Override embedded worker bind port |
| `EMBEDDED_NATS_PORT` | Heavy compute backend | `4222` | Override embedded NATS client port |
| `EMBEDDED_NATS_MONITOR_PORT` | Heavy compute backend | `8222` | Override embedded NATS monitor port |
@@ -364,6 +363,7 @@ Multiple library roots for server library import.
Base URL for standalone external compute worker mode.
- Leave unset for embedded/local startup (`pnpm dev` / `pnpm start`) so entrypoint can start embedded worker+NATS.
+- Embedded startup requires `nats-server` available on host PATH.
- Required only when using a standalone external worker service.
- Example: `http://localhost:8081`
@@ -375,13 +375,6 @@ Bearer token for compute-worker auth.
- Must match worker service `COMPUTE_WORKER_TOKEN`.
- In embedded startup, entrypoint auto-generates one if unset.
-### START_EMBEDDED_COMPUTE_WORKER
-
-Controls whether entrypoint auto-starts embedded compute-worker + NATS.
-
-- Default behavior: enabled when `COMPUTE_WORKER_URL` is unset
-- Set `false` to disable embedded startup and require external worker URL/token
-
### EMBEDDED_COMPUTE_WORKER_PORT
Embedded compute-worker HTTP port.
@@ -412,6 +405,7 @@ NATS connection URL used by compute worker runtime.
- Embedded startup default: `nats://127.0.0.1:4222`
- Standalone worker service: set in worker service env (`compute/worker/.env*` or platform env)
+- For embedded startup, this is optional; startup supplies the default value.
### COMPUTE_JOB_CONCURRENCY
diff --git a/scripts/openreader-entrypoint.mjs b/scripts/openreader-entrypoint.mjs
index 164cfd8..f21feb7 100644
--- a/scripts/openreader-entrypoint.mjs
+++ b/scripts/openreader-entrypoint.mjs
@@ -445,18 +445,13 @@ async function main() {
const embeddedWorkerPort = Number.parseInt(withDefault(runtimeEnv.EMBEDDED_COMPUTE_WORKER_PORT, '8081'), 10);
const embeddedNatsPort = Number.parseInt(withDefault(runtimeEnv.EMBEDDED_NATS_PORT, '4222'), 10);
const embeddedNatsMonitorPort = Number.parseInt(withDefault(runtimeEnv.EMBEDDED_NATS_MONITOR_PORT, '8222'), 10);
- const embeddedWorkerEnvRaw = runtimeEnv.START_EMBEDDED_COMPUTE_WORKER;
- let shouldStartEmbeddedWorker = isTrue(
- embeddedWorkerEnvRaw,
- !Boolean(runtimeEnv.COMPUTE_WORKER_URL?.trim()),
- );
+ const shouldStartEmbeddedWorker = !Boolean(runtimeEnv.COMPUTE_WORKER_URL?.trim());
if (shouldStartEmbeddedWorker && !hasNatsBinary()) {
- if (embeddedWorkerEnvRaw && isTrue(embeddedWorkerEnvRaw, true)) {
- throw new Error('START_EMBEDDED_COMPUTE_WORKER=true but `nats-server` binary is not available in PATH.');
- }
- shouldStartEmbeddedWorker = false;
- console.warn('`nats-server` binary not found; skipping embedded compute worker startup.');
+ throw new Error(
+ '`nats-server` binary is required when COMPUTE_WORKER_URL is unset. '
+ + 'Install nats-server or set COMPUTE_WORKER_URL and COMPUTE_WORKER_TOKEN for an external worker.',
+ );
}
if (shouldStartEmbeddedWorker) {