Skip to Content
Getting StartedConfiguration

Configuration

RondoFlow reads all of its configuration from a single .env file at the project root. Every package — the UI, the server, and shared code — loads from that one file, so there is just one place to look.

npm run setup generates .env from .env.example and fills in a random BETTER_AUTH_SECRET for you. You then edit it to add Claude credentials and any optional providers/nodes.

There are two ways to set values:

  • The .env file — best for the required server settings (database, auth, networking) and for first boot.
  • Settings → Credentials in the app — an encrypted, in-app credentials manager for provider keys, OAuth secrets, and SMTP. Values saved here are stored encrypted in the database and override the matching .env value at boot. More on this below.

Not everything that the credentials manager handles ships in the generated .env. .env.example scaffolds Claude, OAuth, and SMTP, but not the OpenAI or Perplexity keys — those are normally set through Settings → Credentials. See Optional providers.

Required variables

These three must be present for the server to start and authenticate users.

VariablePurpose
DATABASE_URLPostgreSQL connection string. Default: postgresql://rondoflow:rondoflow_dev@localhost:5432/rondoflow.
BETTER_AUTH_SECRETSecret used by Better Auth (and to encrypt stored credentials). Must be set — there is no hardcoded fallback.
BETTER_AUTH_URLPublic URL of the auth/server endpoint. Default: http://localhost:3001.
DATABASE_URL=postgresql://rondoflow:rondoflow_dev@localhost:5432/rondoflow BETTER_AUTH_SECRET=<random-hex> BETTER_AUTH_URL=http://localhost:3001

BETTER_AUTH_SECRET has no default. If it is missing the server throws on boot: “BETTER_AUTH_SECRET environment variable is required. Run npm run setup to generate one.” The same secret is also used to encrypt credentials saved through the in-app manager, so do not rotate it casually once secrets are stored.

Networking

These set where the server listens and which origin it trusts. The defaults work for local development; change them when you serve the UI or API from a different host or port.

VariableDefaultWhat it does
PORT3001Port the Fastify server listens on.
UI_ORIGINhttp://localhost:3000Origin allowed for CORS and Socket.IO, and added to Better Auth’s trusted origins. Must match where the UI is actually served.
PORT=3001 UI_ORIGIN=http://localhost:3000

If UI_ORIGIN does not match the URL the browser loads the UI from, API calls and the live Socket.IO connection are blocked by CORS and sign-in is rejected. Keep it in sync with your deployment.

Claude authentication

Assistants (agents) run through the Claude Code CLI, which the server starts (spawns) as a child process. You must provide one of two credentials:

VariableWhat it is
ANTHROPIC_API_KEYA standard Anthropic API key, billed per token.
CLAUDE_CODE_OAUTH_TOKENA setup token from claude setup-token, which uses your Claude subscription.
# Provide ONE of the two ANTHROPIC_API_KEY= CLAUDE_CODE_OAUTH_TOKEN=

To get a setup token, run:

claude setup-token

Auth precedence: if both are set, the setup token (CLAUDE_CODE_OAUTH_TOKEN) wins, and only that winning credential is forwarded to the spawned CLI. The other is not passed along. Set only the one you intend to use to avoid surprises.

Optional providers

RondoFlow can also run assistants on OpenAI and Perplexity, and run Sakana AI transform nodes. Add a key for whichever you want to use — leave the rest unset.

VariableUsed by
OPENAI_API_KEYOpenAI assistants.
PERPLEXITY_API_KEYPerplexity assistants.
SAKANA_API_KEYSakana AI transform node (sakana-ai).

OPENAI_API_KEY and PERPLEXITY_API_KEY are not in .env.example; the normal way to set them is Settings → Credentials (groups OpenAI access / Perplexity access), where they are stored encrypted in the database. They also work as .env variables, but you must add the lines yourself.

SAKANA_API_KEY is present in .env.example and is read directly from the server environment when a Sakana AI node runs.

If an assistant is configured for a provider whose key is missing, the run fails with a clear message — for example “OPENAI_API_KEY is not configured. Add it in Settings → Credentials (OpenAI access).” See Providers for per-provider details.

OAuth sign-in (optional)

Leave these empty to disable the corresponding sign-in button. When set, RondoFlow rebuilds its auth layer automatically, so GitHub/Google sign-in starts working without a server restart.

GITHUB_CLIENT_ID= GITHUB_CLIENT_SECRET= GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET=

Create an OAuth app under GitHub → Settings → Developer settings → OAuth Apps, then paste the Client ID and Client Secret. This enables “Sign in with GitHub”.

Email node (SMTP)

The canvas Email card (node) sends a workflow’s combined output as an HTML email. It is opt-in — the card ships disabled, so building a workflow never sends mail until you turn it on. To make it work, configure an SMTP transport with these variables:

VariableDefaultWhat it does
SMTP_HOSTunsetSMTP server hostname. Required — leave blank to disable email entirely.
SMTP_FROMunsetSender address, e.g. RondoFlow <noreply@example.com>. Required.
SMTP_PORT587SMTP port.
SMTP_SECUREfalsetrue for port 465 (implicit TLS); false for 587 (STARTTLS). When unset, defaults to true only if the port is 465.
SMTP_USERunsetSMTP username. Auth is only attached when both user and password are present, so unauthenticated relays / local catchers (e.g. MailHog) work without it.
SMTP_PASSunsetSMTP password (encrypted when stored via the credentials manager).
SMTP_HOST= SMTP_PORT=587 SMTP_SECURE=false SMTP_USER= SMTP_PASS= SMTP_FROM=

Email is considered configured only when both SMTP_HOST and SMTP_FROM are set. If either is missing the Email card stays inert and surfaces a clear “Email is not configured. Set SMTP_HOST and SMTP_FROM.” message rather than a cryptic transport error.

SMTP can also be managed at runtime in Settings → Credentials (group SMTP); a DB-stored value overrides .env at boot, just like the other credentials. The Email node and its API are covered in the Data nodes guide and the Workflows guide.

First-admin bootstrap

RondoFlow is invite-only — self-registration is disabled, so an administrator creates every account. These variables seed the very first admin so you are not locked out of a fresh install. See Users & Roles for the role model and inviting people.

VariableDefaultWhat it does
RONDOFLOW_ADMIN_EMAILunsetEmail of the first admin account to create.
RONDOFLOW_ADMIN_PASSWORDunsetPassword for that account (8–128 characters).
RONDOFLOW_ADMIN_NAMEAdministratorDisplay name for the account.
RONDOFLOW_ADMIN_EMAIL= RONDOFLOW_ADMIN_PASSWORD= RONDOFLOW_ADMIN_NAME=Administrator

This runs at seed time — during npm run db:seed (and npm run setup, which seeds). It is idempotent: if the account already exists it just ensures the role is admin.

Both RONDOFLOW_ADMIN_EMAIL and RONDOFLOW_ADMIN_PASSWORD must be set, or the bootstrap is skipped. Set them before seeding, then rotate the password after your first login. The repository’s docker-compose.yml only provisions PostgreSQL — migrations and seeding run on the host via npm scripts (npm run setup, or npm run db:migrate then npm run db:seed), so run the seed step yourself with these variables set to create the first admin.

Tuning variables

These adjust runtime behavior. All are optional and have sensible defaults.

VariableDefaultWhat it does
MAX_CONCURRENT_AGENTS5Maximum number of assistants the server runs at once. Additional runs queue.
CLAUDE_CODE_MAX_OUTPUT_TOKENS128000Max output tokens per assistant response. Claude Code clamps this to each model’s true max, so the high default is safe and helps avoid truncated results.
RONDOFLOW_DEBUG_SPAWNunsetSet to 1 (or true) to log a full per-event trace of each spawned CLI process. Useful for debugging empty or failed runs.
IS_SANDBOXunsetSet to 1 to mark the environment as sandboxed. Required when running as root with bypass-permissions; the server also sets this automatically for that exact case.

Seeing empty assistant output? Set RONDOFLOW_DEBUG_SPAWN=1 and check the trace. A common cause is running as root with bypass permissions without IS_SANDBOX=1. See Monitoring for more.

Spawn timeouts & teardown

These protect against a hung Claude CLI process (a stalled network, an unanswerable permission prompt, an infinite loop) and control whether in-flight runs survive a disconnect. All times are in milliseconds.

VariableDefaultWhat it does
RONDOFLOW_SPAWN_IDLE_TIMEOUT_MS300000Kills a run that streams no event for this long. Resets on every stream event, so it is safe for long-lived interactive agents and only fires on a true stall. Applies to every spawn. Set 0 to disable.
RONDOFLOW_SPAWN_MAX_MS0Absolute wall-clock cap applied to every spawn regardless of activity. Off (0) by default; one-shot generators set their own caps.
RONDOFLOW_TEARDOWN_ON_DISCONNECT1When a user’s last tab disconnects, tear down their in-flight runs after the grace window. Set to 0 to keep runs alive across a disconnect (only server shutdown tears them down then).
RONDOFLOW_TEARDOWN_GRACE_MS60000Grace window before disconnect teardown fires. A refresh, new tab, or reconnect within this window cancels it.

The idle timeout is what reaps stalled headless runs — for example a scheduled plan-mode prompt that never produces output. See Schedules for how scheduled runs behave.

External folders

There are also optional variables for External FoldersEXTERNAL_FOLDERS_HOST_PATH (default ./external) and EXTERNAL_FOLDERS_CONTAINER_ROOT (default /external) — covered in that guide.

Spend cap (not an env var)

Looking for a budget variable? The global per-run spend cap (forwarded to the CLI as --max-budget-usd) is not an environment variable. It is the “Max Budget” setting in the app, stored on the canonical global Safety Rule (policy) row and managed via the budget endpoint. null means no cap; the maximum is 1000 USD. See Security for how budgets resolve.

In-app credentials manager

Open Settings → Credentials to manage provider keys, OAuth secrets, and SMTP without editing files. It is backed by the /api/settings/credentials route and stores values encrypted in the database.

It manages the same keys as .env, grouped by provider:

GroupFields
Claude accessClaude API key, Claude setup token
OpenAI accessOpenAI API key
Perplexity accessPerplexity API key
GitHub OAuthClient ID, Client Secret
Google OAuthClient ID, Client Secret
SMTPSMTP host, SMTP port, SMTP secure, SMTP username, SMTP password (secret), SMTP from address

How it behaves:

  • Masked, never returned in full. The status endpoint reports only whether each credential is set and a masked preview (for example ••••a1b2). Secrets are never sent back to the browser. Non-secret values (the OAuth Client IDs, the SMTP host/port/secure/username/from) are shown in full so you can confirm them.
  • Source is labeled. Each field shows whether the value is Saved (the API source db — stored in the database) or From .env (the source env — read from the file), so you always know where a value comes from.
  • Database overrides .env. A value saved in the manager takes precedence over the matching .env variable at boot and on save. Most changes apply immediately — saving a provider key takes effect on the next run, and saving OAuth credentials rebuilds the auth layer without a restart.
  • Clear to fall back. Clearing a field deletes the stored value and restores the original .env value (if any).

Stored secrets are encrypted with BETTER_AUTH_SECRET. An override key is supported, but the encryption module currently reads it from the lowercase variable rondoflow_SECRET (not RONDOFLOW_SECRET) — on case-sensitive systems the uppercase name is ignored and encryption silently falls back to BETTER_AUTH_SECRET. For most installs, just rely on BETTER_AUTH_SECRET. If that secret changes, previously stored credentials can no longer be decrypted and the manager falls back to the .env values.

Next steps

Last updated on