RyTask docs

Environment variables

Every configuration knob RyTask reads, with its default, whether you must set it, and what it does — verified against the code.

View as MarkdownOpen in ChatGPTOpen in Claude

All configuration comes from the environment (no secrets in code). Safe self-host defaults are built in, so docker compose up works with an empty environment; production overrides go in .env (only .env.example is committed). Integer variables that fail to parse silently fall back to their default.

Core

VariableDefaultRequiredWhat it does
PORT3001NoTCP port the API listens on (0.0.0.0).
NODE_ENVNoproduction turns on HSTS/nosniff security headers and the JWT_SECRET boot check; test disables Redis reconnect retries (used by the test suites).
DATABASE_URLpostgres://rytask:rytask@localhost:5432/rytaskNoPostgreSQL connection string. Used by the API, the worker, and drizzle-kit migrations. The pool is lazy — no connection until the first query.
REDIS_URLredis://localhost:6379NoRedis connection string (rate limiting, idempotency, BullMQ queues). The client is lazy-connect, and a down Redis never crashes the process.
APP_VERSION0.0.0NoVersion string reported by /healthz.
APP_BASE_URLhttp://localhost:3000NoBase URL used to build verification, password-reset, and invite links in emails.

Auth and security

VariableDefaultRequiredWhat it does
JWT_SECRETdev-insecure-jwt-secret-change-meYes, in productionHS256 signing secret for access JWTs, and the HMAC key for hashing refresh/PAT/invite/reset tokens. In production the boot fails fast if it is missing, equal to the dev default, or shorter than 32 characters (unless an RS256 key pair is provided).
JWT_ISSUERrytaskNoThe iss claim on issued JWTs.
JWT_PRIVATE_KEYNoPEM private key. Setting both PEM keys switches signing from HS256 to RS256 and exempts JWT_SECRET from the production check.
JWT_PUBLIC_KEYNoPEM public key (see above).
ACCESS_TOKEN_TTL_SECONDS900NoAccess-token lifetime. Hard-capped at 900 (15 minutes) — a larger value is clamped down.
REFRESH_TOKEN_TTL_SECONDS2592000NoRefresh-token lifetime (30 days).
ARGON2_MEMORY_COST19456Noargon2id memory cost (KiB) for password hashing.
ARGON2_TIME_COST2Noargon2id iterations.
ARGON2_PARALLELISM1Noargon2id parallelism.
CORS_ORIGINNoComma-separated list of allowed browser origins. When unset, the API reflects the request origin (the self-hosted single-tenant default); set it to narrow CORS in production.

Public self-registration is not an environment variable. It is a per-organization setting under Settings → Organization (off by default — invite-only), and the first account is created through the first-run setup screen at /setup, not at boot. The former ALLOW_PUBLIC_SIGNUP variable was removed — set the policy in the app instead.

Rate limiting

All enforcement details are in Rate limits.

VariableDefaultRequiredWhat it does
THROTTLE_WINDOW_SECONDS60NoWindow of the general per-principal/IP request bucket.
THROTTLE_MAX_REQUESTS300NoRequests allowed per general window.
AUTH_THROTTLE_WINDOW_SECONDS60NoWindow of the stricter bucket for /auth/* routes.
AUTH_THROTTLE_MAX_REQUESTS20NoRequests allowed per auth window.
LOGIN_MAX_FAILURES5NoFailed sign-ins per (email, IP) before lockout.
LOGIN_LOCKOUT_SECONDS900NoLockout window after the failure threshold (15 minutes).

Slack

Slack is inert by default: leave all of these unset and the app runs with a no-op Slack adapter. Slack counts as configured only when SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, and SLACK_SIGNING_SECRET are all present — and in that case SLACK_TOKEN_ENC_KEY becomes mandatory (the boot fails fast without it).

VariableDefaultRequiredWhat it does
SLACK_CLIENT_IDOnly to enable SlackSlack app client id (from the app's Basic Information page).
SLACK_CLIENT_SECRETOnly to enable SlackSlack app client secret.
SLACK_SIGNING_SECRETOnly to enable SlackVerifies the HMAC signature on every inbound Slack webhook (see Webhooks and idempotency).
SLACK_OAUTH_CALLBACK_URLNoWhere Slack returns the OAuth consent; must match the app's redirect URL.
SLACK_TOKEN_ENC_KEYYes, when Slack is configuredBase64-encoded 32-byte AES-256-GCM key that encrypts per-install bot tokens at rest. Generate with openssl rand -base64 32. Boot fails if Slack is configured and this is missing or not exactly 32 bytes.

MCP

VariableDefaultRequiredWhat it does
MCP_PUBLIC_URLNoPublic base URL the MCP HTTP/SSE transport is reachable at; surfaced on the Agent access page so a human can connect an MCP client. Leave unset for stdio-only/local use.
RYTASK_PATFor the stdio transportPersonal access token used by the stdio MCP entrypoint to authenticate as a principal.

Worker

VariableDefaultRequiredWhat it does
WORKERNoSet WORKER=1 to start the process as the background worker (BullMQ consumers) instead of the HTTP API. Same codebase, same Docker image — only the entrypoint behavior changes.

Web

VariableDefaultRequiredWhat it does
NEXT_PUBLIC_API_URL'' (relative, same-origin)NoAPI base URL used by the browser. This is a build-time value: it is baked into the client bundle when next build runs (the Docker build accepts it as a build arg), so changing it at runtime has no effect. The compose stack builds with http://localhost:3001.
API_URLhttp://localhost:3001NoAPI base URL used by server-side rendering in the web app (container-to-container in compose: http://api:3001).

Listed in .env.example but not read by the code yet

These appear in .env.example for the planned compose services (MinIO, Mailhog) but no code path reads them today: S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET, SMTP_HOST, SMTP_PORT, and NEXT_PUBLIC_MCP_URL (the Agent access page gets the MCP URL from the API, which reads MCP_PUBLIC_URL). Setting them currently has no effect.

On this page