NovusLens reads its configuration from the environment, and the customer profile refuses guesses.
NovusLens takes its settings from environment variablesEnvironment variableA named setting made available to a running program. The customer launcher reads these settings from the installation environment file.. In an installation, ./lens setup writes the settings to .novuslens.env, and Docker ComposeDocker ComposeThe Docker tool that starts and connects the services listed in one configuration file. passes a fixed set of variables to each service. Setup settings describes every line of that file. A variable in the operator’s shell does not reach the services. A variable Compose does not pass keeps its default.
The profile decides how strict the platform is. In the dev profile, development conveniences are on and public development values are used with a warning. In the customer profile, the same variables are required, and a missing or public value stops the service from starting. Every installation runs the customer profile.
A default in the tables is the value the code uses when the variable is unset. Where the default depends on the profile, both are shown. “None; required” means the service refuses to start without the variable. The In an installation column gives what Compose passes: a fixed value, a line of .novuslens.env, or “not passed” when the default applies.
Profile and security
| Variable | Default | In an installation | Where read | Meaning |
|---|---|---|---|---|
CONWAY_PROFILE | dev | customer, fixed | packages/common_py/src/common_py/profile.py, apps/ui/lib/profile.ts | customer turns every development convenience into a refusal. The services and the UI treat any other value as dev. |
CONWAY_SESSION_SECRET | dev: a public development value built into the code, with a warning. customer: none; must be set, at least 24 characters, and not the public value | from .novuslens.env | apps/ui/lib/session.ts, packages/common_py/src/common_py/profile.py | Signs the login session cookieCookieA small value a browser keeps and sends back to a website. NovusLens uses a signed cookie to remember the signed-in account.. Changing it signs everyone out. In the customer profileDeployment profileA setting that selects customer or development behaviour. Customer mode refuses development credentials and uses the signed-in session as the identity. the UI refuses to sign a session without a strong value. |
CONWAY_IDENTITY_SALT | dev: a public development saltSaltExtra data mixed into a value before its fingerprint is calculated. It makes matching or guessing the original value harder. built into the code, with a warning. customer: none | from .novuslens.env | apps/connectors/src/conway_connectors/personnel.py, packages/common_py/src/common_py/profile.py | Salts the sealed personnel hashesHashA fixed-length fingerprint calculated from content. Comparing fingerprints helps detect changes and match records.. Choose it once and keep it. |
CONWAY_SERVICE_TOKEN | empty; dev runs without one | from .novuslens.env | apps/reasoning/src/conway_reasoning/serve.py, apps/ui/lib/profile.ts, apps/connectors/src/conway_connectors/agent_producer.py, packages/common_py/src/common_py/profile.py | The shared service tokenService tokenA secret value sent with requests between NovusLens services. The receiving service refuses requests with a missing or wrong value. for requests from the web application to the reasoning service, sent in the X-Conway-Service-Token header. In the customer profile the reasoning service refuses every request without it, except /health and /ready. The web application adds it after identifying the signed-in viewer. The agent producer reads it to call the service. |
MYCELIUM_GATEWAY_TOKEN | empty | from .novuslens.env | packages/common_py/src/common_py/profile.py, compose.yml | The bearer tokenBearer tokenA secret value sent with a request to prove that the caller holds it. Anyone who obtains it can use it, so it must be protected. for the meshMeshA set of connected Mycelium services that exchange updates and keep the NovusLens log. gatewayGatewayA service that accepts requests and passes them into another system. The Mycelium gateway gives NovusLens access to the mesh.. Compose gives the same value to the mesh nodes and the services, and refuses to start without it. The sidecarSidecarA separate supporting process that runs beside the application. Here it runs Mycelium and exposes the gateway that NovusLens calls. and the MyceliumMyceliumThe application infrastructure underneath NovusLens. Its connected services exchange updates and keep the ordered structural log. SDKSDKSoftware development kit: a package of code that helps another program use a service. NovusLens uses mycelium-py to talk to Mycelium., which live outside this repository, read it; this page relies on the comment in profile.py for that behaviour. |
NOVUSLENS_MCP_EXPOSE | unset: on in dev, off in customer | from .novuslens.env, 0 by default | apps/reasoning/src/conway_reasoning/serve.py | Set to 1 to register the analysis tools on the mesh gateway in the customer profile. In an installation they then reach MCPMCPModel Context Protocol: a standard way for an AI application to discover and call named tools supplied by another program. clients on its Docker network only. |
NOVUSLENS_TLS_PROXY | unset (no proxyProxyA service that receives a request and forwards it to another service. The NovusLens web proxy adds the signed-in identity and service token. declared) | from .novuslens.env, 0 by default | apps/ui/lib/cookiePolicy.ts, apps/ui/app/login/page.tsx, compose.yml | Set to 1 to declare a TLS-terminating proxyTLS-terminating proxyA service that receives an encrypted HTTPS connection and forwards the request to the application. The customer supplies and configures it. or single sign-onSSOSingle sign-on: signing in through an organisation's existing identity service instead of a separate product account. gateway in front of the UI. Sign-in is then refused when a request reaches the declared proxy over plain HTTPHTTPHypertext Transfer Protocol: the rules a browser or program uses to send a request to a web service and receive its response.. A proxy that sends X-Forwarded-Proto: https makes the session cookie encrypted-only. Setup saves it when you answer proxy; see Network access. |
NOVUSLENS_ALLOW_LOOPBACK_WEBHOOK | unset | not passed | apps/reasoning/src/conway_reasoning/notify.py | Set to 1 to allow a webhook endpointEndpointA particular address on a service that accepts a defined kind of request. on the loopbackLoopbackA network address that refers to the same host, such as 127.0.0.1. Other hosts cannot reach a service through that address. address. An installation refuses loopback endpoints: inside it, a loopback address is the service’s own containerContainerA running program with its own packaged software and isolated environment, managed by Docker on the host.. Cloud metadata hosts and link-local addresses are refused whatever this is set to. |
NOVUSLENS_WEBHOOK_ALLOWLIST | empty: no allow-listAllow-listA list of permitted actions, resources or destinations. It excludes everything else only when its issuer says the list is complete. | from .novuslens.env, empty by default | apps/reasoning/src/conway_reasoning/notify.py | A comma-separated list of host suffixes. When set, a webhook host must equal one of them or end with one of them. |
Database
| Variable | Default | In an installation | Where read | Meaning |
|---|---|---|---|---|
DATABASE_URL | dev: a local PostgreSQLPostgresThe database software that stores the tables read by the NovusLens screens, along with document bodies, access records and protected personnel records. at 127.0.0.1, port 5433, with the development credential built into the code. customer: none; a missing value stops the command | built from POSTGRES_PASSWORD in .novuslens.env, for the installation’s own database | apps/graph/src/conway_graph/db.py, apps/ui/lib/twin.ts, apps/ui/lib/guide.ts, compose.yml | The PostgreSQL connection string. It holds the read modelRead modelThe database tables used by the map, Ask and Find. NovusLens rebuilds these tables from its history of recorded changes., the evidence bodies, the sealed identities and the audit trail. Connections give up after five seconds. |
Mesh
| Variable | Default | In an installation | Where read | Meaning |
|---|---|---|---|---|
NOVUSLENS_MESH_HTTP_ADDR | 127.0.0.1 | mesh-0, fixed | apps/mesh/src/conway_mesh/build.py, apps/connectors/src/conway_connectors/__main__.py, apps/graph/src/conway_graph/keyperson.py, apps/reasoning/src/conway_reasoning/serve.py | The address clients use to reach the mesh HTTP gateway. |
NOVUSLENS_MESH_HTTP_BASE | 8400 | 8400, fixed | apps/mesh/src/conway_mesh/build.py, apps/connectors/src/conway_connectors/__main__.py, apps/reasoning/src/conway_reasoning/serve.py | The first HTTP port. In development, mesh node i listens on this value plus i. In an installation each node has its own container and listens on 8400. |
MYCELIUM_DIR | /Volumes/Scratch/Mycelium | not passed | apps/mesh/src/conway_mesh/twin.py | The location of the substrateSubstrateThe shared Mycelium software beneath NovusLens. It stores records and lets NovusLens components exchange them. checkout. It is used only when CONWAY_SDK_FROM_CHECKOUT=1, which is a development path. |
CONWAY_SDK_FROM_CHECKOUT | unset | not passed | apps/mesh/src/conway_mesh/twin.py | Set to 1 to import the Mycelium SDK from the checkout instead of the pinnedPinA recorded choice of one exact dependency version. It prevents an update from changing that dependency without a deliberate decision. wheelWheelA packaged Python library ready to install. A vendored wheel is stored in this repository so its exact bytes can be checked.. This is a development override, and the service refuses it in the customer profile. |
Compose also sets the substrate’s own variables for each mesh node: MYCELIUM_DATA_DIR, MYCELIUM_PORT, MYCELIUM_HTTP_PORT, MYCELIUM_HTTP_ADDR, MYCELIUM_PEERS, MYCELIUM_ROLE and MYCELIUM_HOSTNAME. Operators do not set these. They are read by the substrate, outside this repository. NOVUSLENS_MESH_NETWORK in .novuslens.env chooses the private address range the nodes use.
Reasoning
| Variable | Default | In an installation | Where read | Meaning |
|---|---|---|---|---|
NOVUSLENS_PROJECTION_INTERVAL | 30 | from .novuslens.env | compose.yml, default in apps/reasoning/src/conway_reasoning/project.py | Seconds between read-model projectionProjectionThe regular pass that brings the read model up to date with the canonical log. It runs every 30 seconds by default. passes. Compose passes it to the projection worker as --interval. Setup and the projection command refuse values under five seconds. |
CONWAY_LLM_ENDPOINT | http://localhost:11434/v1/chat/completions | from .novuslens.env | apps/mesh/src/conway_mesh/build_agent.py, packages/common_py/src/common_py/llm_http.py | The OpenAI-compatible chat endpoint for every model call: the interview reader, Compass, Strategy and the meaning sweep all send their requests through it. Setup asks for the model server and writes its address here. |
CONWAY_BUILD_MODEL | CONWAY_LLM_MODEL if set, otherwise gpt-oss:20b | from .novuslens.env; gpt-oss:20b when empty | apps/mesh/src/conway_mesh/build_agent.py | The model the interview reader uses. ./lens monitor shows it as missing when the model server does not have it. |
CONWAY_LLM_MODEL | gpt-oss:20b | not passed | apps/mesh/src/conway_mesh/build_agent.py | The older name for the build model. It is used only when CONWAY_BUILD_MODEL is empty. |
CONWAY_COMPASS_MODEL | qwen3:30b | from .novuslens.env; qwen3:30b when empty | apps/reasoning/src/conway_reasoning/compass.py, apps/reasoning/src/conway_reasoning/strategy.py, apps/meaning/src/conway_meaning/deep_sweep.py | The model for Compass answers. It is also the fallback for the Strategy and sweep models. |
CONWAY_STRATEGY_MODEL | CONWAY_COMPASS_MODEL if set, otherwise qwen3:30b | the Compass model | apps/reasoning/src/conway_reasoning/strategy.py | The model for Strategy. |
CONWAY_SWEEP_MODEL | CONWAY_COMPASS_MODEL if set, otherwise qwen3:30b | the Compass model | apps/meaning/src/conway_meaning/deep_sweep.py | The model for the meaning-contradiction sweep. |
CONWAY_LLM_API_KEY | unset | from .novuslens.env | packages/common_py/src/common_py/llm_http.py | The bearer key used only when CONWAY_LLM_ENDPOINT is exactly https://openrouter.ai/api/v1/chat/completions. The request helper never sends it to local test stubs or any other endpoint. Setup saves it when you choose openrouter, from your answer or from OPENROUTER_API_KEY, and refuses that choice without it. In CIContinuous integrationAutomated checks run when code changes, usually including building the code and running tests., the gate workflow maps the Actions secret OPENROUTER_API_KEY to this variable. |
CONWAY_LLM_FREE_ONLY | unset | not passed | packages/common_py/src/common_py/llm_http.py | Set to 1 to restrict remote calls to OpenRouter and openrouter/free, or the exact confirmed xing4-phala-zero profile with all four provider price caps zero. Arbitrary named free suffixes and paid models refuse. Local endpoints are exempt. Default CI uses the router for all four model roles. |
CONWAY_LLM_CI_PROFILE | unset (off) | not passed | packages/common_py/src/common_py/llm_http.py | gpt-oss-20b-darkbloom-fp8-capped permits only GPT OSS 20B via Darkbloom fp8 at prompt/completion caps 0.018/0.09 USD per million tokens, request/image zero; it conflicts with free-only mode and requires separate paid permission. xing4-phala-zero permits only Xing4 29B via Phala with all four caps zero, including under free-only mode. Both require manual dev, account-plugin confirmation, parameter support and no provider fallback. Stricter caller limits/privacy remain; caps are not a total budget. |
CONWAY_LLM_ACCOUNT_PLUGINS_OFF | unset (refuse named profiles) | not passed | packages/common_py/src/common_py/llm_http.py | Both named profiles require exact 1: an operator declaration that account default plugins are off and not forced on. This is not automatic verification or paid permission. The workflow boolean defaults false and sets it only after manual dev admission. Reconfirm after account-policy changes. |
CONWAY_STRUCTURED_ANSWERS | unset (off) | not passed | apps/reasoning/src/conway_reasoning/compass.py | Set to 1 to add a structured final-answer instruction to Compass. The code describes this as an opt-in path that is measured before it becomes the default. |
CONWAY_AGENT_EVIDENCE_CONFIG | unset | not passed | apps/reasoning/src/conway_reasoning/serve.py, apps/reasoning/src/conway_reasoning/agent_evidence.py | Development only: the path to the enrolmentEnrolmentThe operator's recorded permission for a source to send specified record types about named agents, using an identified signing key. file and a switch for the service delivery worker. Installations use activated database policy and the projection worker. |
User interface
| Variable | Default | In an installation | Where read | Meaning |
|---|---|---|---|---|
NOVUSLENS_UI_PORT | 3111 | from .novuslens.env | compose.yml | The host port of the web application. Compose publishes it on NOVUSLENS_UI_BIND. |
NOVUSLENS_UI_BIND | 127.0.0.1 | from .novuslens.env, 127.0.0.1 by default | compose.yml, deploy/installer/src/novuslens_installer/configuration.py | The host address Compose publishes the web port on. Any other address needs NOVUSLENS_TLS_PROXY=1. |
CONWAY_REASONING_URL | http://127.0.0.1:8500 | http://reasoning:8500, fixed | apps/ui/lib/profile.ts, scripts/answer_eval.py | The address the UI uses to reach the reasoning service. |
The UI also reads CONWAY_PROFILE, CONWAY_SESSION_SECRET, CONWAY_SERVICE_TOKEN, DATABASE_URL and NOVUSLENS_TLS_PROXY. Those are described in the tables above.
These developer scripts read their own variables. They are not used by an installation.
| Variable | Default | Where read | Meaning |
|---|---|---|---|
E2E_BASE_URL | http://127.0.0.1:3111 | apps/ui/playwright.config.ts, apps/ui/scripts/shoot-panel.mjs, apps/ui/scripts/check-overlaps.mjs | Developer scripts only: the address the browser checks run against. |
NOVUSLENS_GATE_UI_PORT | 3111 | ops | Developer gates only: the UI port, from 1 to 65535. Choose a free port when a separate demo is running. ops e2e passes this address to its browser tests. |
NOVUSLENS_URL | http://127.0.0.1:3111 | apps/ui/scripts/capture-screens.mjs | Developer script only: the address that screenshot capture uses. |
NOVUSLENS_CAPTURE_REPORT | /tmp/novuslens-capture-report.json | apps/ui/scripts/capture-screens.mjs | Developer script only: the JSONJSONJavaScript Object Notation: a text format for data, using named fields, lists and values. Configuration files and service messages use it. report of captured views, failures and refreshed copies. Set a different path to retain each capture attempt. |
NOVUSLENS_CAPTURE_PASSPHRASE | a development passphrase built into the script | apps/ui/scripts/capture-screens.mjs | Developer script only: the passphrase used for screenshot capture. |
Connectors
| Variable | Default | In an installation | Where read | Meaning |
|---|---|---|---|---|
CONWAY_OBSERVATION_TTL_DAYS | 30 | from .novuslens.env, 30 by default | apps/connectors/src/conway_connectors/corrector.py | The number of days a measured observation counts as the current picture. An older measurement stays in the record as historical and is left out of the current view. It is not erased. |
The connectorsConnectorSoftware that reads records from a source system, such as an incident tool. A customer-written file connects those records to teams or services in NovusLens. also read CONWAY_IDENTITY_SALT and CONWAY_SERVICE_TOKEN, described in the profile table, and the mesh address and port variables, described in the mesh table.
Logging
Every Python command and service, and the user interface server, reads these as it starts.
| Variable | Default | Where read | Meaning |
|---|---|---|---|
CONWAY_LOG_LEVEL | INFO | packages/common_py/src/common_py/logging_config.py, apps/ui/lib/log.ts | The lowest level written: DEBUG, INFO, WARNING, ERROR or CRITICAL, in any case. Any other value, or an empty one, stops the command or the user interface server as it starts and names the value. |
CONWAY_LOG_JSON | 0 | packages/common_py/src/common_py/logging_config.py, apps/ui/lib/log.ts | 1 writes one JSON object per log line, for a log collector. 0 writes plain lines. Any other value stops the command or the user interface server as it starts. |
NO_COLOR | unset | packages/common_py/src/common_py/logging_config.py, apps/ui/lib/log.ts | Any value, including empty, turns off colour in log lines written to a terminal. Lines written to a file or a pipe never carry colour. |
Settings only setup and Compose read
The other lines of .novuslens.env choose the images, the installation’s name and directory, the demo and the first operator account. No NovusLens service reads them. Setup settings describes each one.
Named manual inference and account declaration
The default CI route remains openrouter/free. The xing4-phala-zero manual profile pins the named Xing model to Phala.
It requires parameter support, disables provider fallback and caps prompt,
completion, request and image provider prices at zero. It extends CONWAY_LLM_FREE_ONLY=1 only for that exact reviewed
profile; arbitrary free suffixes and paid alternatives are refused.
Both named profiles require account-plugins-off: true on an explicit manual
version=dev dispatch. This operator declaration means the CI key’s account
plugins are off and cannot be forced on by account policy. It is not an automatic
account check and must be reassessed if account settings change. Missing or false
confirmation refuses before an ops command; the shared HTTP guard also requires
CONWAY_LLM_ACCOUNT_PLUGINS_OFF=1. OpenRouter documents account plugin defaults and forced overrides .
Provider price caps do not cap account add-on fees or total spend. Paid-profile permission remains a separate decision.
The inference-compatibility component accepts only the confirmed named-zero
profile. It makes one real public BuildAgent.chat request with the existing static group
schema, low effort and 8,192-token limit. It makes no inferenceInferenceThe work a language model does to produce an answer from its instructions and input. preflight call,
formatting nudge or retry. Its shape result is protocol evidence,
not model semantic qualification or an application-gate pass. The ordinary live
routing matrix and all twelve application gates remain required.