Skip to content

Deployment Guide

Four installation options — choose based on your environment.

01 System Prerequisites

Required on the server for all installation methods.

PackagePurposeInstall
Python 3.11+ Runtime (portable + PyInstaller options) python.org or miniforge3
poppler-utils PDF rendering (DOCINDEX) apt install poppler-utils
tesseract-ocr OCR fallback apt install tesseract-ocr
libmagic1 Binary MIME validation apt install libmagic1
sudo apt install poppler-utils tesseract-ocr tesseract-ocr-eng libmagic1

02 Environment Variables (.env)

Copy .env.example to .env and fill in:

Required

ANTHROPIC_API_KEY=sk-...                        # or Z.AI token
ANTHROPIC_BASE_URL=https://api.anthropic.com    # override for Z.AI/GLM
ANTHROPIC_MODEL=claude-sonnet-4-6

WORKSPACE_PATH=/absolute/path/to/workspaces    # Required
MASTER_PASSWORD=replace-with-a-strong-password
JWT_SECRET_KEY=replace-with-64-char-random-hex

Optional — LLM model roles

VISION_MODEL=qwen3-30-hf    # Router alias — chart/table vision
TEXT_MODEL=glm-text          # Router alias — DOCINDEX tree + extraction + archive
QUERY_MODEL=glm-text         # Router alias — Phase 4 chat

Aliases are resolved via app/llm_config.yaml.

Optional — feature flags

PORT=8000                     # Production port (dev uses 8001)
SECURITY_LEVEL=1              # 1=plaintext, 2=encrypted, 3=dual-key

MANUAL_IMG_DETECTION=false    # Chart extraction on standard /ingest
MIN_IMG_PX=150                # Min pixel dimension for chart candidates
TWO_PASS_IMG_DETECTION=true   # LLM classify raster before extract
TABLE_FORMAT=md               # csv | md | kv-md
BUILD_DOCINDEX_JSON=false      # Fast ingest also saves DOCINDEX JSON
Never commit .env to version control — it is in .gitignore.
LLM provider keys are registered from the Keys panel in the app UI, not from .env.
Installation options

A Native — Miniforge + conda (recommended)

Full install script: installs miniforge if absent, creates the rg conda env, checks .env, starts the server.

First-time install

# Clone the repo, then:
cp .env.example .env && nano .env      # fill in your keys

chmod +x app/project-scripts/run/z_deploy.sh
./app/project-scripts/run/z_deploy.sh  # installs miniforge, conda env, starts server

Lifecycle (after install)

./app/project-scripts/run/run.sh --start
./app/project-scripts/run/run.sh --stop
./app/project-scripts/run/run.sh --restart
./app/project-scripts/run/run.sh --status
./app/project-scripts/run/run.sh --logs

Server binds to 0.0.0.0:{PORT} — accessible on LAN. App at http://<ip>:{PORT}/app.

Dev mode (hot reload, localhost only)

./app/project-scripts/run/dev.sh       # port 8001, auto-reload on code changes

B Portable Package — auto-venv, no conda

Build a self-contained archive (~3 MB compressed). The start.sh launcher auto-creates a .venv and installs dependencies on first run. No conda required on the target server.

Build (on dev machine)

# Python builder:
python app/project-scripts/run/z_build-portable.py [--version 1.2.0]

# Bash builder (no Python needed at build time):
bash app/project-scripts/run/z_package.sh [--version 1.2.0]

# Output: dist/DocConverter-Portable-1.0.0.tar.gz  + .zip

Install & run (on target server)

sudo apt install python3 python3-venv libmagic1 poppler-utils tesseract-ocr

tar -xzf DocConverter-Portable-1.0.0.tar.gz
cd DocConverter-Portable-1.0.0/

cp .env.example .env && nano .env   # set ANTHROPIC_API_KEY + WORKSPACE_PATH
./start.sh                          # auto-installs deps on first run (~2 min)

Custom port: PORT=8080 ./start.sh

C PyInstaller — single executable

Bundles the entire app + Python runtime into one binary (~50–80 MB). No Python or conda on the target — just system libs.

Build (on dev machine, conda env rg active)

pip install pyinstaller

python app/project-scripts/run/z_build-lightweight.py
# Output: dist/DocConverter  (~50-80 MB)

Deploy & run (target server)

# Target needs only system libs (no Python runtime):
sudo apt install libmagic1 poppler-utils tesseract-ocr

# Copy executable + .env
scp dist/DocConverter user@server:/opt/docconverter/
scp .env              user@server:/opt/docconverter/

# Run
cd /opt/docconverter && ./DocConverter

The executable reads .env from its working directory.

PyInstaller bundles are OS-specific: build on Linux to run on Linux, on Windows for Windows.

D Docker

Build & run

docker build -t doc-converter \
  -f app/project-scripts/run/Dockerfile .

docker run -d \
  --name doc-converter \
  --env-file .env \
  -p 8000:3001 \
  -v /your/workspaces:/app/workspaces \
  doc-converter

App at http://localhost:8000/app. The Dockerfile exposes port 3001 internally.

Docker Compose + Caddy reverse proxy

# docker-compose.yml
services:
  api:
    build:
      context: .
      dockerfile: app/project-scripts/run/Dockerfile
    env_file: .env
    volumes:
      - ./workspaces:/app/workspaces
    expose:
      - "3001"

  caddy:
    image: caddy:2
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data

volumes:
  caddy_data:

# Caddyfile
# yourdomain.com {
#     reverse_proxy api:3001
# }
After installation

Ref Initialize a New Workspace

Each doc_type needs a dimensions.json config file.

From the app UI, open the Config tab and use the workspace initializer. Or via API:

TOKEN=$(curl -s -X POST http://localhost:8000/auth/login \
  -d "password=YOUR_MASTER_PASSWORD" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

curl -X POST "http://localhost:8000/api/fin-report/init" \
  -H "Authorization: Bearer $TOKEN"

Or manually create workspaces/{group}/{doc_type}/_config/dimensions.json:

{
  "dimensions": {
    "level0": {"name": "doc-type", "value": "fin-report"},
    "level1": {"name": "asset-manager", "search_fields": ["investment manager"]},
    "level2": {"name": "fund-name", "search_fields": ["fund name"]},
    "level3": {"name": "reporting-date", "temporal": true, "format": "YYYYqX"}
  },
  "path-order": ["level0", ["level1","level2"], "level3"]
}

Ref Health Check

# OpenAPI spec
curl http://localhost:8000/openapi.json

# List loaded Router model aliases
curl http://localhost:8000/api/config/models \
  -H "Authorization: Bearer $TOKEN"

# Ping all model aliases
curl http://localhost:8000/api/keys/check \
  -H "Authorization: Bearer $TOKEN"