Deployment Guide
Four installation options — choose based on your environment.
01 System Prerequisites
Required on the server for all installation methods.
| Package | Purpose | Install |
|---|---|---|
| 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
.env to version control — it is in .gitignore.LLM provider keys are registered from the Keys panel in the app UI, not from
.env.
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.
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
# }
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"