Worker

Configuration

Worker configuration comes from three sources, merged in order (later wins):

  1. Built-in defaults compiled into the daemon.
  2. Config file at ~/.pendra/config.yaml (Unix) or %ProgramData%\Pendra\config.yaml (Windows).
  3. Environment variables.

pendra setup writes the config file interactively; pendra config set <key> <value> mutates it directly. Env vars are re-read on every CLI invocation and at daemon startup.

Example config file

~/.pendra/config.yaml
# ~/.pendra/config.yaml
app_server_ws_url: wss://api.pendra.ai
gpu_worker_private_key: <base64-ed25519-private-key>
worker_id: wrk-a1b2c3d4
worker_name: gpu-01
models_dir: ~/.pendra/models
# optional — private inference (set by 'pendra keygen --save'):
workload_private_key_file: ~/.pendra/workload_key

The file holds the Ed25519 private key in plaintext, so the daemon enforces mode 0600 on Unix and warns at startup if it's wider. On Windows the config directory and key file are restricted to SYSTEM, Administrators, and the account Pendra runs as, so other local accounts can't read the key.

Settings reference

Env varConfig keyDefaultPurpose
APP_SERVER_WS_URLapp_server_ws_urlwss://api.pendra.aiBase URL the daemon dials; /ws/gpu is appended automatically.
GPU_WORKER_PRIVATE_KEYgpu_worker_private_keyBase64 Ed25519 private key from the console. The daemon refuses to start without one.
PENDRA_WORKLOAD_PRIVATE_KEY_FILEworkload_private_key_filePath to the private-inference workload key file. pendra keygen --save writes a PEM X25519 key beside config.yaml and sets this; you can equally point it at a PEM X25519 key you generated yourself (e.g. openssl genpkey -algorithm X25519). Leave it unset and drop a key file at the default location (~/.pendra/workload_key) and the worker picks it up automatically. Off unless a key is configured or found there — see private inference.
PENDRA_WORKLOAD_PRIVATE_KEY_FILE_PREVIOUSworkload_private_key_file_previousPath to the previous workload key during a key rotation (same base64 or PEM encodings as the primary). Set automatically when pendra keygen --save rotates an existing key, so the worker keeps serving clients still pinned to the old fingerprint until they re-pin.
WORKER_IDworker_idauto wrk-<hex>Stable ID across restarts. Persisted on first run.
WORKER_NAMEworker_namehostnameFriendly name shown in the console. You don't need to set it — see Naming a worker. The environment variable overrides a console rename on every restart; the config-file key is overridden by one.
MODELSmodels(serve all)Filter to a subset of discovered models. JSON array of IDs or {id} objects.
PENDRA_MODELS_DIRmodels_dir~/.pendra/models (Unix), %ProgramData%\Pendra\models (Windows)Directory the worker serves GGUFs from. pendra models install downloads into this directory; pendra models dir prints the resolved path.
PENDRA_DISABLE_LLAMACPPfalse (on)Set 1/true/yes to turn off Pendra's in-process chat and embeddings.
PENDRA_DISABLE_WHISPERCPPfalse (on)Set 1/true/yes to turn off Pendra's in-process audio transcription. Transcription accepts wav/mp3/flac and runs on Linux, macOS, and Windows workers.
PENDRA_DISABLE_WHISPERCPP_VADfalse (on)When transcribing a file, Pendra automatically skips silent and non-speech passages, which keeps quiet gaps from producing repeated words. Set 1/true/yes to turn that off and transcribe the audio unaltered.
PENDRA_DISABLE_STABLEDIFFUSIONfalse (on)Set 1/true/yes to turn off Pendra's in-process image generation. Serves /v1/images/generations from a diffusion .gguf in your models directory.
PENDRA_DISABLE_AUDIOCPPfalse (on)Set 1/true/yes to turn off Pendra's in-process text-to-speech. Serves /v1/audio/speech from a speech model in your models directory.
PENDRA_ALLOW_METAL_BF16false (refuse)Apple Silicon Macs only. A few models whose weights use the bf16 number format are declined on a Mac worker by default, because they can crash it. Set 1/true/yes to run one anyway once you've confirmed it works on your Mac. No effect on other platforms.
PENDRA_BLOCK_METAL_BF16_PROJECTORfalse (allowed)Apple Silicon Macs only. Vision models run on Mac workers by default. If a vision model's image analysis fails to start on an older Mac, set 1/true/yes to serve those models as text-only (image input off). This only affects image input — it won't make a model that can't run at all (e.g. a too-large or unsupported one) start running. No effect on other platforms.
INSECURE_TLSinsecure_tlsfalseSkip TLS cert verification for the WebSocket. Local dev only.
PENDRA_LOG_MAX_FILES5How many log files to keep in ~/.pendra/logs/. The worker starts a fresh log on each restart and keeps this many (the live file plus older sessions), so the log from before a crash or restart is still there to read. Minimum 2.
PENDRA_LOG_MAX_SIZE_MB20Size in MB at which the current log file rolls over to a new one mid-session. The total kept is still bounded by PENDRA_LOG_MAX_FILES. Minimum 1.

Naming a worker

Installing a worker never asks you for a name. It starts out named after the machine it's running on — its hostname — so a fresh worker shows up in the console already recognisable.

To change it, open Workers → your worker in the console and click the pencil next to the name. Type the new name and save. The worker has to be connected: the console sends the new name to it, and it takes effect within a couple of seconds — no restart, and the name sticks across restarts. You need to be an owner or operator, and names are up to 64 characters.

If you'd rather set the name where you deploy the worker — a Docker -e WORKER_NAME=gpu-01, a Kubernetes manifest, a systemd unit — you still can, and it's the better fit for containers, whose hostname is an unhelpful random string. Just note that the WORKER_NAME environment variable wins every time the worker restarts, so a rename you make in the console will be replaced by it on the next restart. Pick one place to name a given worker and stay there.

The worker_name key in config.yaml works the other way round: a rename you make in the console takes precedence over it. To set the name on the machine instead, run pendra config set worker_name gpu-01 — that clears the console name for you — then restart the worker.

Per-worker settings in the console

A few worker-wide tuning options live in the console rather than in config.yaml or an env var. Open Workers → your worker → Settings (you must be an owner or operator) — changes apply to the running worker within a few seconds, no restart needed.

SettingDefaultPurpose
Speculative decoding cap2How many tokens the draft proposes per step when a model runs speculative decoding (range 16). Turning speculative decoding on or off is a separate per-model setting (Models & context); this tunes the depth when it's on.
Allow remote image URLsOffLet vision requests reference http(s) image URLs, which the worker fetches for you (private/loopback hosts are always blocked). Off by default — pass images inline as base64 data: URIs.
Web toolsOffLet tool-capable models fetch live web pages and run web searches during a chat, so answers can use up-to-date information (private/loopback hosts are always blocked). Off by default — turning it on adds extra work per request. When it's on, the chat response also lists the pages fetched and searches run under a pendra.web_tool_steps field, so you can see what the model looked at.
Task timeout30mWall-clock limit for a single non-streaming request (chat, embeddings, rerank, image, transcription), from 1 to 120 minutes. Raise it for very large or slow models; lower it to fail faster. Streaming chat is unaffected.
Response format grammarOnWhen you request JSON output (response_format json_object or json_schema), the worker constrains the model so the reply is always valid JSON that matches your schema. On by default. Turn it off only as an escape hatch if a particular model on this worker fails to generate with it enabled.
Max concurrent requests1How many requests this worker runs in parallel (range 164) — also how many Pendra sends it before routing to another worker. Defaults to one at a time; raise it on hardware that can serve more without running out of memory.

On Max concurrent requests: the default of one at a time matches how most self-hosted GPUs are sized — a single generation gets the card's full memory bandwidth, and consumer cards don't run out of memory under parallel load. Raise it when the hardware has clear headroom (a data-centre GPU, or several cards), and watch that responses don't slow down more than the extra throughput is worth.

CLI commands

CommandPurpose
pendra / pendra runStart the worker daemon.
pendra statusConnection and model info for the running worker.
pendra restart-backendRestart just the inference engine (a fresh process starts on the next request) without stopping the worker. Use it to recover a stalled GPU that has fallen back to running on CPU — the console flags that with a "Running on CPU" badge. Pendra also tries to recover on its own; the command forces it.
pendra configPrint resolved config and the file path it loaded from.
pendra config set <key> <value>Mutate the config file.
pendra config repair-permsRe-tightens the config file's permissions: chmod 600 on Unix, or re-applies the restrictive ACL (SYSTEM, Administrators, and the account Pendra runs as) on Windows. Useful if the worker warns that the config file has loose permissions — the daemon self-heals on startup, but this command forces the repair immediately. Run as an administrator on Windows.
pendra setupInteractive setup wizard.
pendra modelsList the models installed on the worker.
pendra models install <model>Install a catalogue model onto the worker.
pendra logsTail the worker's log buffer (-f follows). The OS-supervised service is managed with systemctl / launchctl / Services.msc.
pendra doctorDiagnostics — checks the inference runtime, config, and the live worker connection. On a Linux service install, re-runs itself with sudo when it needs to read the service's config.

Related