Ciaren

Advanced Setup

Advanced Setup

The Installation guide gets you running with sensible defaults. This page is the reference for everything you can tune: configuration sources, every environment variable, alternate databases, execution and scheduler tuning, and a production deployment outline.

Configuration sources & precedence

The backend (Settings) reads configuration in this order — later wins:

  1. Built-in defaults (shown below).
  2. .env file in the backend working directory.
  3. Environment variables (prefixed CIAREN_).
  4. ciaren serve flags (e.g. --port, --db-url, --engine, --execution-mode, --data-dir, --no-scheduler), which are applied as env vars before the app loads.
  5. Settings page overrides for a small editable subset (marked UI below). Saved in Ciaren's database, applied immediately, and re-applied on every startup — so once a value is edited in the UI, it wins over the environment until you press Reset on that setting.

Scaffold a commented file with ciaren init, confirm the resolved values with ciaren info, and validate the environment with ciaren check.

The Settings page

The gear icon in the header opens Settings — runtime configuration editable from the browser: default engine, execution mode, run timeout, upload size, dataset retention, scheduler tuning, and the ML guardrail limits. Each setting shows where its current value comes from (default, environment, or a saved override) and what Reset would restore. Changes apply to the whole server and persist across restarts; the few marked "takes effect after restart" are consumed once at startup. Overrides are designed for the standard single-process ciaren serve; if you run multiple server processes, a change applies live to the process that handled it and to every process after restart.

An override mutes its environment variable

While a setting has a saved override (shown as Custom), its CIAREN_* environment variable — and the matching ciaren serve flag — has no effect: editing or removing the variable changes nothing until you press Reset on that setting. Each row on the page names its variable and, when overridden, warns that changes to it are being ignored.

Everything else is deliberately environment-only: bootstrap values the server needs before the database is up (DATABASE_URL, DATA_DIR, …), secrets (API_TOKEN, WEBHOOK_SECRET, NOTIFY_WEBHOOK_SECRET), the failure-webhook URL (Ciaren sends the webhook secret to that URL, so only someone with access to the environment may point it somewhere), and the security guards (CORS/CSRF, secret allowlists, storage confinement, plugin enforcement). The Settings page and its API are reachable by exactly the audience those guards constrain, so exposing them there would let that audience weaken its own guardrails — changing them requires access to the server's environment.

Environment variables

All settings use the CIAREN_ prefix.

VariableDefaultDescription
CIAREN_ENVIRONMENTdevelopmentEnvironment label (development, production, …)
CIAREN_DEBUGfalseExtra debug behavior
CIAREN_LOG_FORMATautoLog output: auto (color on a TTY, else plain) | text | json
CIAREN_DATABASE_URLsqlite+aiosqlite:///./ciaren.dbAsync database URL (see below)
CIAREN_DATA_DIR.dataDirectory for uploads, run outputs, and previews
CIAREN_DEFAULT_ENGINEpolarsDefault dataframe engine (polars | pandas) UI
CIAREN_EXECUTION_MODEthreadCompute offload mode (thread | process) UI
CIAREN_RUN_TIMEOUT_SECONDS0Abandon a run after N seconds (0 = no limit) UI
CIAREN_CORS_ORIGINS["http://localhost:5173"]Allowed CORS origins (JSON list); also trusted by the CSRF origin guard
CIAREN_TRUSTED_HOSTS[]Extra hostnames the CSRF origin guard trusts beyond localhost (see Security)
CIAREN_MAX_UPLOAD_SIZE_MB100Maximum upload size in MB UI
CIAREN_API_TOKENOptional bearer token required for /api/* requests
CIAREN_WEBHOOK_SECRETEnables POST /api/flows/{id}/trigger with X-Ciaren-Secret
CIAREN_PYTHON_TRANSFORM_STRICTfalseEnable stricter static checks for Python Transform scripts
CIAREN_CONNECTOR_BLOCK_PRIVATE_HOSTSfalseBlock connector endpoints resolving to private/internal addresses
CIAREN_STORAGE_ALLOWED_ROOTS[]Restrict Local Storage roots and SQLite/DuckDB database files to these directories
CIAREN_SECRET_ENV_ALLOWLIST[]Env vars (or PREFIX* patterns) a connection's env: secret reference may name; Ciaren's own config vars are always refused
CIAREN_SECRET_FILE_DIRS[]Folders file: secret references may read (default: <DATA_DIR>/secrets and /run/secrets); always enforced
CIAREN_FRONTEND_DISTExplicit path to a built frontend served by the backend
CIAREN_DATASET_RETENTION_DAYS30Days to retain soft-deleted dataset files before purge UI
CIAREN_SEED_DEMOtrueSeed the built-in Demo project on first boot
CIAREN_SEED_RUN_FLOWSfalseRun newly seeded demo flows once
CIAREN_SCHEDULER_ENABLEDtrueRun the background scheduler
CIAREN_SCHEDULER_POLL_INTERVAL_SECONDS30How often the scheduler polls for due runs UI
CIAREN_SCHEDULER_MAX_CONCURRENT_RUNS1Max simultaneous scheduled runs UI
CIAREN_NOTIFY_WEBHOOK_URL(unset)POST a JSON alert here when a run fails or a schedule auto-disables
CIAREN_NOTIFY_WEBHOOK_SECRET(unset)Sent as X-Ciaren-Secret so the receiver can verify the sender
CIAREN_SCHEDULER_MAX_CONSECUTIVE_FAILURES5Failures before a schedule auto-disables (0 = never) UI
CIAREN_ML_ENABLEDtrueEnable ML routes/nodes (built in; set false to disable)
CIAREN_MLFLOW_TRACKING_URI./mlrunsDefault MLflow tracking URI
CIAREN_MLFLOW_REGISTRY_URIOptional MLflow registry URI; defaults to tracking URI
CIAREN_ML_ARTIFACT_DIRml_artifactsLocal model artifact root, under DATA_DIR when relative
CIAREN_ML_MAX_MODEL_SIZE_MB500Maximum model artifact size accepted by ML guardrails UI
CIAREN_ML_MAX_TRAINING_ROWS5000000Maximum rows accepted for one training job UI
CIAREN_ML_MAX_FEATURE_COLUMNS500Maximum feature columns accepted for one training job UI
CIAREN_MARKETPLACE_INDEXbundled catalogLocal marketplace index JSON path for Explore catalog; set none to disable
CIAREN_MARKETPLACE_LICENSE_ISSUER_KEYSunsetRegisters a TokenLicenseProvider per configured issuer key, for validating plugin license tokens at startup
CIAREN_REQUIRE_TRUSTED_PLUGINSfalseRequire trusted signatures for marketplace/UI installs
CIAREN_PLUGIN_PERMISSION_ENFORCEMENToffRuntime enforcement of plugin permissions: off / warn (log ungranted actions) / enforce (block them). Not a sandbox — see Plugin Security

Booleans accept true/false; lists (like CORS_ORIGINS) are JSON. Variables marked UI can also be edited at runtime from the Settings page; a saved override takes precedence over the variable until reset.

Database

Ciaren uses async SQLAlchemy, so the URL must use an async driver.

DatabaseURL formDriver to install
SQLite (default)sqlite+aiosqlite:///./ciaren.dbbundled
PostgreSQLpostgresql+asyncpg://user:pass@host:5432/dbnamepip install asyncpg
MySQL / MariaDBmysql+aiomysql://user:pass@host:3306/dbnamepip install aiomysql
# backend/.env
CIAREN_DATABASE_URL=postgresql+asyncpg://ciaren:secret@localhost:5432/ciaren

The schema is created automatically on startup — there is no separate migration step. ciaren check verifies the driver is async and that the database is reachable.

Async driver required

A plain sqlite://, postgresql://, or mysql:// URL will fail to connect. Always use the +aiosqlite / +asyncpg / +aiomysql variant.

Data directory

CIAREN_DATA_DIR (default .data) is where uploaded files, run outputs, and previews are written. In production, point it at a persistent, writable volume — ciaren check confirms it's writable. The database stores metadata; the data dir stores the actual files.

Execution tuning

Ciaren runs synchronous dataframe work off the event loop so the API stays responsive. CIAREN_EXECUTION_MODE (also editable on the Settings page) chooses how that work is offloaded. This section is the practical guidance on which mode to use; for the engine (polars/pandas) side of performance, see Engines.

thread vs process: which to use

Stay on thread (the default) unless a symptom below pushes you off it. For the typical setup — one person, one run at a time, the polars engine — it is simpler, fully featured, and just as fast: polars compute is multithreaded Rust that releases the GIL, so a single run already uses every core in either mode. process pays off in specific server scenarios, not in general.

thread (default)process
Parallelism between concurrent runsGIL-serialized for pandas-heavy worktrue multi-core across runs
Parallelism within one runfull (polars is multi-core internally)same
Cancelling a runcooperative and preciseinstant (no pool recycle) while the run is still queued or materializing its inputs; once it's actually executing in a worker, cancelling is coarse — recycles the whole pool, and is refused while other runs share it
RUN_TIMEOUT_SECONDSrun is abandoned but its thread finishes — CPU stays busyworker recycled — CPU reclaimed once this is the last active run; a timeout while others are still running defers the recycle until they finish, so one hung run can't abort its neighbors
A run segfaults or exhausts memorycan take down the whole serveronly the worker dies; the API stays up
Plugin node-level hooksfiredon't fire (graph-level hooks only)
Startup cost per workernonespawn re-imports the app — noticeably slower first run, especially on Windows

Switch to process when:

  • Ciaren is a long-lived shared server running scheduled jobs — crash isolation and a timeout that really reclaims CPU matter more than precise cancellation.
  • You raised SCHEDULER_MAX_CONCURRENT_RUNS above 1 and your flows are pandas-heavy — the one case where the GIL actually serializes work.

Stay on thread when:

  • You use Ciaren interactively on your own machine (the install default): full cancel support, plugin node hooks, no spawn overhead.
  • Your flows run on polars — process adds moving parts without adding speed for a single run.

Practical notes

  • Neither mode is a security boundary. A process worker has the same privileges and filesystem access as the server; it isolates crashes, not code. For untrusted Python Transform scripts see CIAREN_PYTHON_TRANSFORM_STRICT and the security docs.
  • Switching the mode at runtime (Settings page) is safe: it applies from the next run.
  • SCHEDULER_MAX_CONCURRENT_RUNS also sizes the process pool, and the pool is created once — that setting needs a restart to fully apply.
  • CIAREN_RUN_TIMEOUT_SECONDS (0 = no limit) abandons an over-running run in both modes; process mode gets the CPU back (the pool is recycled) as soon as no other run still shares it — immediately if this was the only one, otherwise once the others finish. Pair a timeout with process on unattended servers.
  • A permission revocation or plugin disable/uninstall reaches already-spawned process workers on their next task, not only after the pool is recycled — each submitted task carries the current plugin-state generation, and a worker behind it re-syncs before executing.
# a shared box running scheduled jobs: isolation + a 5-minute cap per run
CIAREN_RUN_TIMEOUT_SECONDS=300 ciaren serve --execution-mode process

Scheduler tuning

The background scheduler runs inside the API process. See Scheduling for behavior. Relevant settings:

  • CIAREN_SCHEDULER_ENABLED — master switch (or ciaren serve --no-scheduler).
  • CIAREN_SCHEDULER_POLL_INTERVAL_SECONDS — lower = more responsive, more wakeups.
  • CIAREN_SCHEDULER_MAX_CONCURRENT_RUNS — cap on simultaneous scheduled runs.
  • CIAREN_SCHEDULER_MAX_CONSECUTIVE_FAILURES — auto-disable threshold.

Run the API without the scheduler

If you run multiple API replicas, enable the scheduler on only one of them (--no-scheduler on the rest) — it is a single-process poller and isn't designed to coordinate across replicas.

CORS

When the frontend is served from a different origin than the API, add that origin to CIAREN_CORS_ORIGINS (a JSON list):

CIAREN_CORS_ORIGINS=["https://ciaren.example.com","http://localhost:5173"]

Production deployment

Ciaren is local-first, but you can host it. A typical setup:

Backend

python -m pip install ciaren
# bind to all interfaces, no reload, info logs
ciaren serve --host 0.0.0.0 --port 8055 --log-level info
  • Set CIAREN_ENVIRONMENT=production.
  • Use a managed PostgreSQL/MySQL via CIAREN_DATABASE_URL.
  • Put the data dir on a persistent volume.
  • Run it under a process manager (systemd, Docker, etc.).
  • Set CIAREN_LOG_FORMAT=json to emit one JSON object per log line (level, logger, message, timestamp, plus any structured fields) for a log collector. The default auto prints human-readable lines.
  • Point your orchestrator's liveness probe at /health and its readiness probe at /ready (the latter returns 503 until the database is reachable). See REST API conventions.

Frontend

The React app is a static build that calls the API at the path /api on its own origin (there is no runtime API-URL variable — only the dev-server proxy). So in production you serve the built files and reverse-proxy /api to the backend, typically behind one web server:

cd frontend
npm ci
npm run build         # outputs static files to frontend/dist/

Serve frontend/dist/ and route /api/* to the backend. Example nginx:

server {
  listen 80;
  server_name ciaren.example.com;

  root /srv/ciaren/dist;            # frontend build
  location / { try_files $uri /index.html; }

  location /api/ {                      # proxy to the backend
    proxy_pass http://127.0.0.1:8055;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Because the browser then talks to a single origin, you usually don't need to touch CORS_ORIGINS for this layout.

Alpha software

Ciaren is in early development and has not completed a formal independent third-party security audit. If you deploy it beyond localhost, review the security notes, set CIAREN_API_TOKEN, place it behind trusted access controls, and validate the deployment against your own data and operational requirements.

Frontend dev overrides

For local development against a non-default backend, the dev server (not the production build) honors:

  • VITE_PORT — change the dev server port (default 5173).
  • VITE_API_TARGET — where the dev proxy forwards /api (default http://localhost:8055).
VITE_PORT=3000 VITE_API_TARGET=http://localhost:8001 npm run dev

Verifying

ciaren info     # print resolved settings (DB password redacted)
ciaren check    # data dir writable? async driver? DB reachable? engines present?

See also