Skip to content

Configuration reference

Sift reads its settings from environment variables, each named SIFT_ plus the setting’s name in capitals. There is no configuration file. Every SIFT_* line in .env reaches every backend container (the API, the three workers and the scheduler), because docker-compose.yml reads that file as its env_file. A variable you do not set takes the default below. Settings are read when a container starts: after changing .env, run make up, which recreates the containers whose settings changed (docker compose restart does not re-read .env). For how to work with these in practice, and the few most deployments change, see Configure Sift.

A setting with an invalid value stops the containers at start, with a message naming the setting; the message never prints the value.

VariableDefaultAllowed valuesEffect
SIFT_SECRET_KEYnone: requiredText; in production at least 32 characters and not a key printed in the Sift repositoryKey material for signing sessions and encrypting the stored Kindo API key and webhook endpoints’ addresses and secrets. make init generates one (32 random bytes, url-safe base64). Changing it ends every session and makes those stored secrets unreadable. Compose refuses to start without it.
SIFT_ENVIRONMENTdevelopmentdevelopment, productionproduction refuses to start on any published credential (see below), marks the session cookie Secure (so it needs HTTPS in front), sends webhooks over HTTPS only, and turns off the API’s interactive docs and OpenAPI document (/api/docs, /api/openapi.json).
SIFT_LOG_LEVELINFOA standard level name, such as DEBUG, INFO, WARNING or ERROR (any case)Log verbosity of every backend container.
SIFT_LOG_FORMATjsonjson, consolejson writes one JSON object per line; console writes readable lines for a terminal.
SIFT_METRICS_TOKENunsetAt least 32 charactersThe bearer token GET /api/metrics requires. Unset, there is no metrics endpoint: it answers 404. A shorter token stops the start. Generate one with openssl rand -hex 32. See Monitor Sift.
SIFT_WORKER_HEARTBEATtruetrue, falseHow the system status learns which workers are up. true has each worker report in every 5 seconds, so worker_pool_silent appears up to 15 seconds after a worker stops. false asks the workers directly, which makes every status call, and so every console page, wait a second.
SIFT_HEALTH_SHARE_S2Seconds, 0 to 60How long the dashboard, Alerts, fleet, Actions and Filters list may show the same reading of each filter’s health, so opening the console works it out once rather than five times. A change to a filter (its state, version or spec) shows at once; a new label or agent run up to this many seconds late. A filter’s own page, approvals and every other decision always read the current state. 0 turns sharing off.
SIFT_PAGE_CACHE_S60Seconds, 0 to 600The oldest copy of an overview read (the dashboard, Filters table, activity chart, flow, asks, Alerts and the Filters list) the console may be served. Each response says when it was computed, which the console shows as as of. A person’s change (a filter’s state, an approval, a spec save, a label correction, pairing, the Kindo key or model) shows at once; a new score, agent run or label up to this many seconds late. A filter’s own page, approvals and every other decision always read the current state. 0 turns the cache off.
SIFT_PAGE_REFRESH_S30Seconds, 1 to 600Past this age a cached overview read is still served while it is refreshed in the background, and the console’s default reads are refreshed this often whether or not anyone is looking. At or above SIFT_PAGE_CACHE_S, nothing is served while it refreshes.
SIFT_SETBASED_READStruetrue, falseHow the dashboard, fleet and Activity read their window. true is the faster way, and stays fast right after a restore or a large load. false is the slower way, kept as a fallback. The figures are the same either way.

In production, Sift refuses to start, naming every problem at once, when:

  • SIFT_SECRET_KEY is empty, shorter than 32 characters, or a key printed in the Sift repository;
  • SIFT_DEFAULT_ADMIN_PASSWORD is admin, or shorter than 12 characters;
  • the Postgres password (POSTGRES_PASSWORD) is empty or sift;
  • the object store’s key (SEAWEEDFS_SECRET_KEY) is siftsiftsift.

make init generates the secret key, POSTGRES_PASSWORD and SEAWEEDFS_SECRET_KEY. It leaves the admin password at admin, so set that yourself before going to production.

VariableDefaultAllowed valuesEffect
SIFT_DEFAULT_ADMIN_USERNAMEadminTextThe account created at first start, with the admin role.
SIFT_DEFAULT_ADMIN_PASSWORDadminText; in production at least 12 characters and not adminThat account’s first password. Used only to create the account when it does not exist; it never resets an existing one. The console warns while the password is admin.
SIFT_SESSION_TTL_HOURS12Whole hoursHow long a session lasts when nobody ends it. Signing out, or changing the password, ends every session of that account at once.
SIFT_TRUSTED_PROXY_HOPS10 to 8How many reverse proxies in front of the API append to X-Forwarded-For. The sign-in throttle limits attempts per address, using the address the outermost trusted proxy recorded. 1 is the shipped nginx; 2 behind a load balancer or TLS terminator that also appends; 0 when nothing proxies the API.
VariableDefaultAllowed valuesEffect
SIFT_KINDO_API_BASE_URLhttps://api.kindo.aiURLThe Kindo API host Sift assumes where no connection names one, and the host it recognises as Kindo’s in a webhook address. Sift’s calls go to the address saved with the Kindo connection, entered when an admin connects (https://api.kindo.ai unless changed there).
SIFT_KINDO_AUTH_HEADERAuthorizationHeader nameThe header the Kindo API key is sent in. Authorization is sent as Bearer <key>. Sift’s key check tries the other known form (api-key) too, so you rarely need to change this.
SIFT_KINDO_REQUEST_TIMEOUT_S30.0SecondsTime limit for one attempt at a Kindo API call (tool calls, agent and run requests).
SIFT_KINDO_INFERENCE_TIMEOUT_S180.0SecondsTime limit for one attempt at a chat completion (Sift’s assistant, the analyzer, gold-set builds), which takes far longer than an API call.
SIFT_KINDO_MAX_REQUESTS_PER_SECOND5.0Requests per secondThe most requests Sift sends to Kindo per second.
SIFT_COPILOT_MODELclaude-sonnet-5A model name in your Kindo tenantThe model for Sift’s own calls (Sift’s assistant, the analyzer, gold-set builds) only while no model is chosen on the Kindo connection page. While it is in use, the system status reports kindo_model_unselected. When the tenant does not list it, Sift uses a model the tenant offers instead.
SIFT_MAX_TRIGGER_INPUT_CHARS32000CharactersThe most characters one agent run’s input may carry, across all its inputs. Over it the input is cut and the run records that it was (truncated in the agent contract).
SIFT_MAX_RUN_AGE_S21600 (6 hours)SecondsAn agent run with no verdict after this long is settled as stuck and reported.
SIFT_DELIVERY_FAILURE_MATURITY_S120SecondsHow long a failure to deliver an event to the agent must stand, with no successful delivery for the same filter since, before it counts as a delivery failure and stops the filter filtering. Shorter turns a brief Kindo restart into a burst of runs; longer keeps filtering into an outage.
SIFT_ASSUMED_COST_PER_AGENT_RUN_USDunsetA number, in US dollarsWhat one agent run costs you, for the savings figure on the cost views. Unset, Sift reports runs avoided and says the spend is unknown. An empty value is an error, not “unset”: leave the line out instead.
SIFT_AGENT_DEFAULT_RUNS_PER_HOURunset (half of SIFT_KINDO_MAX_REQUESTS_PER_SECOND × 3600: 9000 at the default)Runs an hour, 1 to 1,000,000How many runs one agent can take an hour, for a filter that does not say. The volume check on a new filter compares the stream with it to decide what to suggest. It limits nothing by itself. Unset, it is half of what the Kindo rate limit allows, since Sift’s own calls share that limit. An empty value is an error, not “unset”.

A build starts whenever the console creates a filter. These bound what one build reads and spends. See The gold set.

VariableDefaultAllowed valuesEffect
SIFT_GOLD_POOL_MAX_EVENTS500EventsHow many events a build reads from the source before choosing about 50 from them.
SIFT_GOLD_RANKED_POOL_MAX_EVENTS20001 to 20000The pool a build reads instead when the decision model is on, which then helps choose the proposals from it.
SIFT_GOLD_PROPOSAL_BATCH_SIZE20EventsEvents per proposal request to the model.
SIFT_GOLD_MAX_LLM_CALLS30CallsThe most completions one build may spend. This is the whole inference cost of a build.
SIFT_GOLD_MAX_EVENT_CHARS2000CharactersHow much of one event a proposal request quotes.

Whether a filter is worth running, and Collapse

Section titled “Whether a filter is worth running, and Collapse”
VariableDefaultAllowed valuesEffect
SIFT_SAVINGS_FLOOR0.050 up to, not including, 1An operating point that filters less than this share of events is reported as not worth running, and approving it needs an explicit acknowledgement.
SIFT_SAVINGS_WARN0.100 up to, not including, 1; not below SIFT_SAVINGS_FLOORAbove the floor but below this share, the point can be approved and is flagged as a thin margin. A value below the floor stops the start.
SIFT_COLLAPSE_MIN_VERIFIED_CLUSTERS3010 or moreHow many groups of two or more repeats, with a verdict on the first event and on at least one repeat, a Collapse stage measuring in shadow must have seen before Sift proposes collapsing. The Collect cluster verdicts Setup step counts toward it.

Sift’s recipes need a fixed set of model weights, staged into the model-weights volume on the API’s first start (about 134 MB). The weights are pinned by content digest: a mismatch stops the container rather than downloading over it. Change the four SIFT_EMBEDDER_* variables only together, and expect every filter to retrain. See Install without internet access.

VariableDefaultAllowed valuesEffect
SIFT_MODEL_WEIGHTS_DIR/app/modelsPath in the containerWhere the weights live. docker-compose.yml sets it to the volume’s mount point.
SIFT_EMBEDDER_IDbge-small-en-v1.5TextThe weights’ name, and their directory under the weights directory.
SIFT_EMBEDDER_REPO_IDBAAI/bge-small-en-v1.5Repository idWhere the files are downloaded from.
SIFT_EMBEDDER_REVISION5c38ec7c405ec4b44b94cc5a9bb96e735b38267aCommitThe pinned revision of that repository.
SIFT_EMBEDDER_DIGESTsha256:3befc307e4fac3b03ecb3a54e45e1c2eb0a285d4ccd344a30a316cec7d597603sha256: digestThe digest over the pinned file set, recorded on every trained model and checked when one loads.
SIFT_MODEL_DOWNLOAD_BASE_URLhttps://huggingface.coURLWhere weights are downloaded from. Point it at an internal mirror serving /{repo_id}/resolve/{revision}/{file}.
SIFT_MODEL_FETCH_ON_STARTtruetrue, falsefalse only verifies the weights and never opens a connection, so missing files fail at once. Set it on a host without internet access.
SIFT_MODEL_DOWNLOAD_TIMEOUT_S600.0SecondsTime limit for each read during the weight download (connecting has its own 30 seconds).
SIFT_ML_TRAIN_THREADSunset1 to 256CPU threads one training job may use. Unset, it is the host’s cores divided by 2, the number of training jobs the ml worker runs at once. Set it if you change that worker’s concurrency.

Alerts leave Sift only through webhooks an admin sets up. See Notifications and webhooks.

VariableDefaultAllowed valuesEffect
SIFT_CONSOLE_URLunsetAbsolute http:// or https:// addressThe console’s address as people reach it, used for the links in alerts. Unset, every link is null.
SIFT_DEPLOYMENT_NAMEunsetTextNames this deployment in every alert, for a receiver that hears from several.
SIFT_WEBHOOK_PRIVATE_NETWORKSunset (public addresses only)Comma- or space-separated CIDRs within RFC 1918, fc00::/7 or 100.64.0.0/10Private ranges a webhook may reach, for a receiver on your own network. Any other range stops the start. Loopback, link-local and cloud metadata addresses are refused whatever this says. Shown read-only on the Notifications page.

Off by default; Sift works fully without it. Turning it on sends the fields a filter’s Decide stage reads, cut to SIFT_DECISIONS_MAX_STATE_CHARS, to TypeSafe’s API. See Decision model settings.

VariableDefaultAllowed valuesEffect
SIFT_JEV_ENABLEDfalsetrue, falseTurns the decision model on. true without SIFT_JEV_API_KEY stops the start.
SIFT_JEV_API_KEYunsetTextThe bearer key for TypeSafe’s API. An empty value means unset.
SIFT_JEV_BASE_URLhttps://api.typesafe.aiAbsolute http:// or https:// addressWhere decision-model requests go.
SIFT_JEV_MODELjev-1.13.0A pinned model versionThe model version asked. Every answer records the version that gave it.
SIFT_DECISIONS_MAX_RPS15.0Above 0, up to 100Requests per second to the decision model, from all of Sift’s processes together.
SIFT_DECISIONS_MAX_STATE_CHARS4000200 to 64000The most characters of one event sent to the model.
SIFT_DECISIONS_TIMEOUT_S10.0Above 0, up to 120Time limit for one decision-model request, in seconds.
SIFT_VERDICT_CHECK_DAILY_CAP2001 to 100000The most verdict-check questions per filter per UTC day. New verdicts past it are passed over, not queued for the next day.

Daily sweeps delete what is past its window.

VariableDefaultAllowed valuesEffect
SIFT_EVENT_PAYLOAD_RETENTION_DAYS30DaysHow long an event’s content is kept.
SIFT_LABELLED_PAYLOAD_RETENTION_DAYS30DaysHow long the content of an event that carries a training label is kept, from when it arrived; also the oldest agent history that can be imported. Models train on what is kept, so raising it gives them more history and keeps those events longer. In shadow every event is labelled.
SIFT_FILTERED_EVENTS_RETENTION_DAYS400Days, not below SIFT_EVENT_PAYLOAD_RETENTION_DAYSHow long a filter’s Filtered events keep each record. A window shorter than the payload window is refused at the sweep: nothing is deleted and the worker log records filtered_events_reap_refused.
SIFT_CANDIDATE_SCORE_RETENTION_DAYS30DaysHow long bake-off candidates’ scores are kept.
SIFT_POLL_LOG_RETENTION_DAYS14DaysHow long the record of each poll (the activity timeline’s poll history) is kept.
SIFT_ARTIFACT_RETENTION_DAYS30DaysHow long a retired model’s stored files are kept after it leaves service. A restore from a backup older than this may name models whose files are gone. See Back up and restore.

These are read by Docker Compose, not by Sift. Put them in .env beside the SIFT_* settings.

VariableDefaultEffect
SIFT_WEB_PORT8080The host port for the console and the API behind it at /api: the only port the stack publishes. With the TLS overlay it serves only a redirect to HTTPS and the health probe.
SIFT_HTTPS_PORT443With docker-compose.tls.yml: the host port for HTTPS. See Serve over HTTPS.
SIFT_TLS_DIR./tlsWith docker-compose.tls.yml: the directory holding tls.crt (full chain, leaf first) and tls.key (unencrypted PEM).
SIFT_EXTRASemptyOptional extras built into the backend image, and which image the stack runs. setfit builds and selects the -setfit image, the only one that can train the text_clf_setfit recipe: about 1.1 GB larger, with about 133 MB more weights staged on first start. Rebuild after changing it.
SIFT_ENV_FILE.envThe file every backend container reads its SIFT_* settings from. docker compose --env-file does not change this; set SIFT_ENV_FILE too.
COMPOSE_FILEcompose’s own defaultThe compose files to use, colon-separated. docker-compose.yml:docker-compose.tls.yml makes HTTPS the default for the checkout. It replaces compose’s default list, so name docker-compose.override.yml in it too if you use one.
POSTGRES_USERsiftThe Postgres user, and part of the database address compose gives Sift.
POSTGRES_PASSWORDsiftThe Postgres password. Read by Postgres only when its volume is first created: to change it later, also change it inside the database (ALTER USER). make init generates one.
POSTGRES_DBsiftThe Postgres database name.
SEAWEEDFS_ACCESS_KEYsiftThe object store’s access key, given to Sift as its S3 credentials.
SEAWEEDFS_SECRET_KEYsiftsiftsiftThe object store’s secret key. Read on every start, so changing it takes a restart, and the old key stops working at once. make init generates one.
SIFT_API_PORT8000Only with the development override (docker-compose.override.yml): the API published on loopback.
SEAWEEDFS_S3_PORT8333Only with the development override: the object store’s S3 endpoint published on loopback.

Compose sets the datastore addresses and the object-store credentials for Sift itself from these: SIFT_DATABASE_URL, SIFT_REDIS_URL, SIFT_S3_ENDPOINT_URL, SIFT_S3_ACCESS_KEY and SIFT_S3_SECRET_KEY. A value in .env for any of them is ignored, because the compose file’s own wins. SIFT_S3_REGION (us-east-1) and SIFT_S3_BUCKET_ARTIFACTS (sift-artifacts) suit the shipped object store; leave them unset.

SIFT_DEV_CORPUS_PROFILE, SIFT_DEV_CORPUS_SIZE, SIFT_DEV_VERDICT_ERROR_RATE, SIFT_DEV_VERDICT_BIAS, SIFT_DECISIONS_OLLAMA_URL, SIFT_DECISIONS_OLLAMA_MODEL, SIFT_PIPELINE_PLUGINS.