Overview
System settings provide access to low-level configuration values organized by category. These settings control database connections, authentication, job processing, infrastructure, and AI model behavior. Navigate to Admin > Administer > System Settings.Categories
Settings are organized into tabs by category:
Each tab shows the number of settings in that category. The tabs follow the category key (Authentication & SSO first, and the tab the page opens on), except that Async Parsing sits right after Jobs Settings.
Viewing Settings
Settings are displayed as key-value pairs with:- Setting name
- Current value (encrypted values are masked)
- Read-only indicator (for settings that cannot be changed from the UI)
Editing Settings
Settings marked as editable can be modified directly from the admin panel. Read-only settings must be changed through environment variables or the Django admin interface.Only settings marked “Show in Dashboard” in the Django admin are visible here. If you need to access additional settings, use the Django admin interface or configure them via environment variables.
FALKOR_PASSWORD, NEO4J_PASSWORD, and RABBITMQ_PASS from the environment. Those services start with the Omnistrate secret, and the app reads the database copy. Other encrypted settings keep the value saved here. seed_config --update-from-env copies every environment value into the database.
Asking the Copilot
The Admin Copilot panel (⌘J / Ctrl+J) sees the settings of the category you have open and the reference below, and can:- Explain a setting in plain words — what it controls and what a value means in practice — citing this page. It checks that the admin guide is indexed first; if the index is out of date it says so and offers the re-index rather than answering from memory.
- Propose a change when you ask (“set it to enforce”, “is this set up right?”) as a card listing setting · current → proposed · reason. Apply stages the value in the page’s form exactly as if you had typed it — it is not saved — and the page’s own Save persists it, with the same validation, confirmations, and permissions as a hand edit.
Settings Reference
Legend: Settings prefixed with 🔒 store encrypted values. Settings marked
(Dashboard) are visible in the admin dashboard UI. Settings marked (Client) are accessible to the frontend client application.LLM Settings
Produced Documents in Chat Context
When a flow writes a document into a conversation, an excerpt of that document is included in the chat’s context as a head start on follow-up questions about it. The two caps bound that excerpt only — they are not the limit of what the assistant can see, because it can also list the documents produced in the conversation, search inside one, and read any part of it on demand (each read is access-checked for the person asking). They still matter, because the excerpt is what the assistant has before it goes looking.PRODUCED_DOC_CONTEXT_CHARS bounds the document text in a single excerpt. PRODUCED_DOC_CONTEXT_TOTAL_CHARS is spent on document text and on the sentences that announce a cut — an excerpt that had to be truncated carries that sentence on top of its own allowance, and the sentence is charged in full against the conversation budget. A conversation full of truncated documents therefore carries less document text than the total alone suggests.
The conversation budget is spent newest first, so the document the flow just wrote — the one the user’s next message is almost certainly about — keeps its excerpt, and older documents give way instead. Nothing is dropped quietly: an excerpt that was cut short says so, and a document that got no budget at all is still named in the context as existing, with its body omitted. That announcement is deliberately exempt from PRODUCED_DOC_CONTEXT_TOTAL_CHARS — saying a document exists must not be starved by the budget it is announcing — so the injected text can exceed the total by one short fixed sentence for every document whose body was omitted. A truncation notice is never cut in half either, because half a notice reads as document text: when the leftover budget cannot hold body text plus a whole notice, that document degrades to the omission announcement instead of getting a sliver of body.
Graph Text in Chat Context
Some graph nodes carry prose: the body of a clause or a document, in theirtext property. When the assistant reads the neighborhood of an entity, that text goes into the context the answer is written from, and every model call of the answer carries it again. Without a bound, one entity with many long clauses could add hundreds of kilobytes. Two limits keep it in check:
GRAPH_CONTEXT_TEXT_CHARScuts the text of each node. A text that was cut ends with…[truncated].GRAPH_CONTEXT_TEXT_TOTAL_CHARScaps the node text of the whole answer. It is spent in the order the entities were found, so the first entities keep their text and the ones after the budget runs out lose it. An entity that lost its text is marked, so the assistant can say the text was left out for size and does not read as absent from the graph.
0 leaves node text out of the context entirely.
Copilot Scheduled Follow-ups
The admin Copilot can schedule a follow-up: a message it receives later in the same conversation, once or on a recurring schedule, and acts on without anyone watching. The thirteenCOPILOT_SCHEDULE* settings above bound it. They are on Admin > Administer > System Settings, in the LLM tab.
- How many and how far.
COPILOT_SCHEDULE_MAX_ACTIVE_PER_USERis the number of active follow-ups per person;COPILOT_SCHEDULE_MAX_DAYS_AHEADhow far ahead a one-time one may be set;COPILOT_SCHEDULE_RECURRING_EXPIRY_DAYSwhen a recurring one stops by itself. A request over a limit is refused and the Copilot names the limit. - How often.
COPILOT_SCHEDULE_MIN_INTERVAL_MINUTESis the shortest gap between two runs of a recurring follow-up (0 * * * *, every hour, is exactly the default and is allowed;*/30 * * * *is not). - How many runs. A recurring follow-up also stops by itself after a number of runs that depends on how often it runs.
COPILOT_SCHEDULE_MAX_RUNS_HOURLY(3) applies to one that runs every hour or several times a day,COPILOT_SCHEDULE_MAX_RUNS_DAILY(30) to one that runs once a day or less often, andCOPILOT_SCHEDULE_MAX_RUNS_SUB_HOURLY(10) to one that runs more than once an hour, which is possible only whenCOPILOT_SCHEDULE_MIN_INTERVAL_MINUTESis lowered. How often is the shortest gap between two of its runs, so every hour from 09:00 to 17:00 on weekdays counts as hourly. Whichever comes first, the run limit orCOPILOT_SCHEDULE_RECURRING_EXPIRY_DAYS, ends the follow-up. Each run limit is 1 to 200; a larger number is lowered to 200. A change applies to follow-ups created after it, and those already running keep the limit they were given: to stop follow-ups from running right away, turnCOPILOT_SCHEDULES_ENABLEDoff. - What a run may cost. Each run is a full Copilot turn that reads the whole conversation again on every model call, so
COPILOT_SCHEDULE_MAX_TOKENS_PER_RUNcounts that (cached input counts in full) andCOPILOT_SCHEDULE_MAX_SECONDS_PER_RUNbounds the time. A run that reaches either stops and tells the person. Together with the number of follow-ups and their run limit they decide what scheduling can cost: ten hourly follow-ups make 30 runs in all, three each, and then stop until someone schedules them again.COPILOT_SCHEDULE_MAX_CONCURRENT_RUNScaps the runs in progress on the whole instance, so a crowd of follow-ups due at the same minute starts a few at a time and the rest wait for the next minute. - Failures. A failed run is tried again
COPILOT_SCHEDULE_MAX_RETRIEStimes, the first retry afterCOPILOT_SCHEDULE_RETRY_BACKOFF_SECONDSand each next one after twice as long, then marked failed. - The switch.
COPILOT_SCHEDULES_ENABLEDturns the feature off: no scheduling tool, and nothing is started. Follow-ups that fall due while it is off run once when it is back on.
ASYNC_PARSE_DISPATCH_URL, so that setting must be right for follow-ups to start.
DB Settings
Graph connectivity usesGRAPH_PROVIDER plus either the Neo4j or FalkorDB connection group.
See Graph backend (Neo4j & FalkorDB) for how switching works and when to run a migration.
Older deployments may still list
USE_NEO4J, USE_FALKOR, FALKOR_DB_USER, or FALKOR_DB_PASSWORD.
Those keys are legacy; GRAPH_PROVIDER with NEO4J_* / FALKOR_* is authoritative for new installs and
the dashboard. Prefer aligning configuration with the rows above.Graph Read Time Limit
A graph read that a person is waiting for carriesGRAPH_READ_TIMEOUT_MS: the retrieval behind a chat answer, the tools of an agent flow, the graph evidence shown with an answer, and dashboard widgets and records. Ingestion, enrichment and the other background work are not limited by it, and neither is the rebuild of the schema cache, because a limit there would leave the cache on its last good value. The limit works the same on Neo4j and FalkorDB.
When a read passes the limit, the graph server stops it and Experio treats it as “the knowledge graph could not answer”, not as “no data”. A chat answer then says so (see When the Knowledge Graph Cannot Be Queried), and a dashboard widget or record answers The knowledge graph is busy. Try again in a moment. and is not retried automatically. The same applies when the graph is unreachable or a query hits FalkorDB’s per-query memory cap. Experio does not ask the model to rewrite such a query, because a rewrite would meet the same busy graph.
A value above 55000 is lowered to 55000, so the graph server stops a query before the client’s own 60-second wait does. If answers report the graph as unavailable while it is healthy, the limit may be too low for the size of your graph.
FalkorDB Aggregate Guard
FalkorDB 6.0.3 answers some grouped aggregations wrongly and can crash on others (upstream FalkorDB issues 3375 and 3150). A grouped aggregation puts grouping columns next to aggregate functions, for exampleRETURN p.name, p.stage, p.code, count(i), sum(i.total). When a grouping column is computed in that same RETURN or WITH and sits after the variables in scope, a number can come back wrong (a sum that equals the row count, say), or the graph server can restart. That is the case when there are more grouping columns than variables in scope, and also when a grouping column is listed after an aggregate.
With FALKORDB_AGGREGATE_GUARD on, the default, Experio refuses a query of that shape before it reaches FalkorDB, and explains how to write it: compute each grouping column in a WITH that also carries the variables the aggregates read, list the grouping columns first, then the aggregates. In chat, the model reads the explanation and rewrites the query. A dashboard widget shows an error that asks for the widget to be regenerated, or for its query to be edited the same way. Experio also refuses an aggregating query that names a variable or alias when, then, else, starts, ends, csv or on, because each of these is also a Cypher keyword and a query that uses one as a name can be misread and answered wrongly. The refusal asks for the variable to be renamed. In chat, the model renames it and runs the query again. Nothing is rewritten behind your back, and a query of any other shape runs as before.
Turn the guard off only after FalkorDB is moved to a release that contains the upstream fixes. A change applies within 30 seconds. The setting has no effect on Neo4j.
AUTH Settings
Login Methods
ALLOW_PASSWORD_LOGIN, ALLOW_MAGIC_LINK_LOGIN, and ALLOW_SELF_REGISTRATION control which authentication paths the public login/register pages expose. They compose with USE_PROPELAUTH and ALLOW_HYBRID_LOGIN:
- For SSO-only tenants, set
ALLOW_PASSWORD_LOGIN=False,ALLOW_MAGIC_LINK_LOGIN=False,ALLOW_SELF_REGISTRATION=False,USE_PROPELAUTH=True, andALLOW_HYBRID_LOGIN=False. - Magic-link login requires a working email provider (see Transactional Email below). The link is valid for
MAGIC_LINK_TOKEN_TTL_MINUTESminutes.
Transactional Email Deliverability
TheAZURE_ECS_SENDER_ADDRESS, AUTH_FROM_DISPLAY_NAME, and AUTH_REPLY_TO_ADDRESS settings together control how outbound auth emails appear to recipients and to mailbox spam filters:
- The From: line is rendered as
"<AUTH_FROM_DISPLAY_NAME>" <AZURE_ECS_SENDER_ADDRESS>(e.g."Experio" <login@experiolabs.ai>). - A
Reply-Toheader points atAUTH_REPLY_TO_ADDRESSso replies land in a monitored inbox instead of bouncing off the no-reply sender. - Every send also sets
Message-ID(with the sender’s host),Date, andAuto-Submitted: auto-generated, and ships a real plain-text alternative alongside the HTML body — these reduce the chance of the message landing in junk. AZURE_ECS_SENDER_ADDRESSmust be a verified MailFrom on the Azure ECS linked domain. Update it (and the corresponding domain verification) if you re-brand the sender.
SSO / PropelAuth
USE_PROPELAUTH, SSO_BACKEND, PROPELAUTH_SSO_USERS_ACTIVE_BY_DEFAULT, and ALLOW_HYBRID_LOGIN work together to enable enterprise Single Sign-On with either backend. USE_PROPELAUTH turns SSO on for both backends despite its name. PROPELAUTH_API_KEY and PROPELAUTH_AUTH_URL are used only when SSO_BACKEND is propelauth. See the SSO Configuration page for complete setup instructions, identity provider guides, and troubleshooting.
Google Workspace Integration
TheGOOGLE_MCP_CLIENT_ID and GOOGLE_MCP_CLIENT_SECRET settings enable per-user Google Workspace MCP integration. See the Integrations page for setup instructions.
Slack Notifications
Users can receive flow run notifications (completed, failed, needs review) as Slack direct messages. This is off until you setSLACK_NOTIFICATIONS_BOT_TOKEN; the Slack column then appears in each user’s notification settings. See Notifications for what users see.
To get a token:
- In your Slack workspace’s app configuration at api.slack.com, open your Slack app (or create one) and add a bot user.
- Under OAuth & Permissions, add these bot token scopes:
chat:write,im:write,users:read, andusers:read.email. - Under App Home, turn on the Messages tab, so the app can send direct messages.
- Install (or reinstall) the app to the workspace.
- Copy the Bot User OAuth Token, which starts with
xoxb-. - In System Settings, paste it into
SLACK_NOTIFICATIONS_BOT_TOKENand save.
Email Notifications
Email notifications use the same email provider as other transactional email (EMAIL_PROVIDER, see above). Without a configured provider, notifications still appear in the bell, but no email is sent.
CORE Settings
Persona feature flags
PERSONAS_ENABLED and REQUIRED_PERSONAS ship off so existing tenants are unaffected until you
opt in. See Personas for the behavior matrix, admin workflow, and deploy
checklist.
PERSONAS_ENABLED— Off hides persona gate, profile picker, and composer toggle; the agent does not inject identity or run persona graph nodes. Admin Settings > Personas stays available for seeding.REQUIRED_PERSONAS— On (with master on) blocks the app until the user picks a persona. Seed active personas and gating forms before enabling.
Chat Turn Limits and the Ingestion Notice
Turn deadline. A chat answer used to have no time limit: a slow model provider could leave an answer waiting for many minutes while it held database connections.CHAT_TURN_DEADLINE_S now stops an answer whose agent run passes it. The user is told This answer took longer than the time limit, so I stopped it. Please ask again in a moment., and that message is saved in the conversation as the answer. Keep the limit under 300 seconds, the database’s idle session limit on Experio deployments: the database closes the connection that holds the answer’s state after 300 idle seconds, so a longer answer fails when it is saved anyway. Answers started with the Deep Research toggle are not limited.
Work after the answer. Once an answer is complete, Experio prepares the suggested follow-up questions, the filter suggestions and, in a new conversation, the title. CHAT_POST_ANSWER_TIMEOUT_S bounds that work. Whatever is not ready in time is skipped, because the user already has the answer; a new conversation can then keep the title New Chat.
Ingestion notice. While files are ingested, the graph can answer more slowly. With CHAT_INGESTION_NOTICE on, an answer that starts during ingestion shows a Data update in progress step with the sentence New data is being added right now, so answers may take longer than usual. Ingestion counts as running when any of these is true:
- a file is in a download, parse, classify or ingest stage and was updated within the last 15 minutes;
- a structured-data scan started within the last 12 hours is still running;
- an enrichment job started within the last 12 hours is still running.
Source document preview
WithCHAT_SOURCE_DOCUMENT_PREVIEW off, a source document in chat opens its original link. With it on, the same click opens the parsed text stored for that document, and the viewer still offers the original link. The setting ships off. A change applies the next time the page is loaded.
While graph clearance is enforced, that preview is available only after the Document label is scoped. Until an admin scopes it, every preview is the same result as a missing document, including for a person who can otherwise open the original link. A superuser whose graph bypass is on can still open the parsed text.
JOBS Settings
Business-Hours Hold for Scheduled Flows
A flow that re-scans and re-ingests your data writes to the knowledge graph for as long as it runs, and the graph answers other questions more slowly meanwhile. The usual answer is to schedule such flows for your night. As a guard for the day, you can set a business-hours window: while it is open, scheduled flows do not start.INGESTION_PEAK_HOURSis the window,HH:MM-HH:MMin 24-hour time, from the start (included) to the end (excluded). A window that ends before it starts crosses midnight (22:00-06:00). Empty, or a start equal to the end, turns the hold off, and that is how it ships.INGESTION_PEAK_TIMEZONEis the IANA name of the time zone the window is written in. It isUTCuntil you change it, so set it together with the hours.INGESTION_PEAK_DAYSlists the weekdays the window applies on. The local date in that time zone decides. With22:00-06:00onmon,tue,wed,thu,fri, Friday night is held until midnight but its Saturday part is not, and Monday’s early morning is held although the night began on a Sunday.
8-18, an unknown time zone or an unknown weekday) turns the hold off and writes one warning to the log for that value, so a typo cannot stop the flow runner. If scheduled flows keep starting inside your business hours, look for that warning.
Async Parsing Settings
The
ASYNC_PARSE_* rows above configure async document parsing: how long a file may wait, how often a person may queue files, what the parser may use to read one file, and how Agent Flows wait for it. They are on Admin > Administer > System Settings, in the Async Parsing tab (right after Jobs Settings), where each one can be edited. They are also Configuration Settings in the Django admin (/staff/), in their own ASYNC_PARSE category (Async Parsing) rather than JOBS. The UPLOAD_EXTRACTION_* and COPILOT_ATTACHMENT_OCR_* rows, which stay in JOBS, are not listed on the page: they are edited in the Django admin only. The rows are seeded with the defaults shown, and a value you save is kept. A database that holds them from an earlier version, under JOBS and hidden from this page, has them moved to ASYNC_PARSE and shown by the next seed_config run (a deploy runs it), with the values it saved.
For a number, a value that cannot be read, or that is below the setting’s minimum, means the default. The minimum is 1, except where a row says 0 is allowed (ASYNC_PARSE_OCR_ASK_ABOVE_PAGES, ASYNC_PARSE_MAX_EMBED_CHUNKS, ASYNC_PARSE_PRECHECK_MAX_FILE_MB, ASYNC_PARSE_PRECHECK_MAX_SPREADSHEET_MB and ASYNC_PARSE_INLINE_TEXT_EMBED_MAX_CHARS) and 30 for ASYNC_PARSE_EMBED_BUDGET_SECONDS.
INFRA Settings
FEATURE_FLAGS Settings
Environment Settings
A few settings are read from the server’s environment when a process starts, not from a row in the tables above. The database timeouts have to be known before the first database connection opens, and a System Settings row can only be read through a connection that already works. These settings are not shown on this page, and a change takes effect when the process restarts. Of the variables below, two are exposed as Omnistrate deployment parameters:GRAPH_EXECUTOR_THREADS (graphExecutorThreads, see FalkorDB deployment parameters) and DB_POOL_MAX_SIZE (Database Pool Size per Process, dbPoolMaxSize, see Service scaling). The others keep their default unless the server’s environment sets them.
The three database timeouts and the connection pool apply to the web server process only, because only there can one slow call hold up every connected user. The job runners, the document-reading worker and management commands such as
migrate get no timeout and no pool, so a migration is never cut short by a lock wait. With several server processes in a pod (see Service scaling) each process has its own pool, so the most connections the web server can hold is the number of pods times the number of processes times DB_POOL_MAX_SIZE, in addition to the chat agent’s own connections.
Every process tags its database connections with an application_name of experio-web, experio-worker, experio-job or experio-other, so pg_stat_activity shows which kind of process owns a connection. The connections the chat agent opens for its checkpoints and its memory store are tagged experio-langgraph and use the connect timeout of the process that opens them.