Skip to content

Environment variables

Every setting the bot reads, what it defaults to, and when you would change it. All of them live in one module — config.py — so a setting that is not listed here does not exist.

Settings are read once, when the process starts. Changing .env while the server is running changes nothing until it is restarted. kb-reload is the one exception, and it reloads the knowledge base rather than the settings.

Copy .env.example to .env and edit that. .env is not committed.

What you must set

Only one, and only to answer questions.

Variable Default Notes
GROQ_API_KEY empty Needed to write a reply. Empty is a real state, not an error: parsing, importing, embedding and evaluating all run without it.

The pipeline — kb-parse, kb-db, kb-ingest, kb-eval — needs no key at all. Embeddings run locally.

What you will probably change

Variable Default Notes
DECIPLE_EMBEDDING_MODEL BAAI/bge-small-en-v1.5 A HuggingFace id downloads from the Hub; a path like models/bge-small-en-v1.5 uses the local copy scripts/fetch_models.py puts there. Point it at the local copy on a machine where TLS interception breaks the download.
DECIPLE_HANDOVER_TO empty Who reads handover emails. No default on purpose — a wrong address here mails a member's question to a stranger. See Handover.
DECIPLE_MAIL_FROM empty Sender, e.g. Deciple <bot@yourdomain.com>.
RESEND_API_KEY empty Delivers the handover email over HTTPS. Empty means no email is attempted.
DECIPLE_API_BASE_URL http://127.0.0.1:8000 Where kb-reload looks for a running server. Change it if you run uvicorn on another port.

Where content and data live

Variable Default Notes
DECIPLE_DATABASE_URL sqlite:///data/kb.db The records the bot answers from. Any URL SQLAlchemy understands.
DECIPLE_KB_DIR data/kb Where knowledge_base.csv is read from and written to. See Updating the knowledge base.
DECIPLE_KB_ARCHIVE_DIR data/kb_archive The mentor's original markdown batches, read only by kb-csv.
DECIPLE_CHROMA_DIR data/chroma The vector store.
DECIPLE_EVAL_QUESTIONS data/eval/questions.jsonl The gold questions kb-eval scores against.
MLFLOW_TRACKING_URI sqlite:///mlflow.db Where runs and traces are logged. See MLflow.

Retrieval and the reply

Variable Default Notes
DECIPLE_SCOPE_FLOOR 0.55 Cosine similarity below which a question is called off-topic and gets the canned scope reply. Raising it rejects more real questions; see the note below.
DECIPLE_RERANK_MODEL models/ms-marco-MiniLM-L-6-v2 Cross-encoder that re-scores the shortlist. Local folder, no API key.
DECIPLE_RERANK_POOL 10 How many records the cross-encoder re-scores.
DECIPLE_QUERY_INSTRUCTION Represent this sentence for searching relevant passages: Prepended to queries only, never to stored text. What the embedding model expects of a question.
DECIPLE_MODEL groq/openai/gpt-oss-120b Full LiteLLM model id, provider prefix included.
DECIPLE_LLM_TEMPERATURE 0.3 Low, not zero — the only prose the model writes is the empathy sentences.
DECIPLE_LLM_MAX_TOKENS 1500 Far above what the answer needs, because reasoning tokens fill it.
DECIPLE_LLM_REASONING_EFFORT low How much thinking gpt-oss does first.
DECIPLE_LLM_NUM_RETRIES 5 Retries on a transient LLM failure before the request becomes a 503.
DECIPLE_DISCLAIMER "This is not medical advice…" Carried on every reply, on every branch.
DECIPLE_SUPPORT_PHONE empty Offered alongside a handover. Empty is safe — the sentence is left out.
DECIPLE_CRISIS_RESOURCES empty Named 24/7 lines, e.g. "Samaritans on 116 123".

TOP_K (4 records shown to the model) and COLLECTION_NAME (kb_records) are constants in config.py, not environment variables. They change retrieval behaviour that the eval numbers were measured against, so changing them is a code change with a re-run attached.

On raising DECIPLE_SCOPE_FLOOR. It is one absolute threshold on the best cosine score, and it answers "is anything near this question?" — not "is what I found the right thing?" Measured across all 64 linked lessons, deleting a lesson still left its gold question above the floor in 64 cases out of 64. At 0.75 the floor would catch 91% of those, and reject 55% of correct answers. It is the wrong dial for that problem.

The server

Variable Default Notes
DECIPLE_CORS_ORIGINS http://localhost:5173,http://127.0.0.1:5173 Origins the browser may call the API from. Listed explicitly rather than *.
DECIPLE_UPLOAD_LIMIT 2097152 Largest upload accepted, in bytes. Two megabytes.
DECIPLE_LOG_LEVEL INFO DEBUG, INFO, WARNING or ERROR.

Disciple

All four are empty by default, and an empty DECIPLE_DISCIPLE_BASE_URL means the adapter is off. See Disciple.

Variable Notes
DECIPLE_DISCIPLE_BASE_URL Root of the Disciple API. Empty turns the adapter off.
DECIPLE_DISCIPLE_API_KEY Reads posts and writes comments as the bot.
DECIPLE_DISCIPLE_BOT_AUTHOR The bot's own author id, so it never answers itself.
DECIPLE_DISCIPLE_WEBHOOK_SECRET Shared secret the incoming webhook is signed with.

Front end

The chat reads one variable, and it is a Vite variable rather than a DECIPLE_ one. Vite only exposes names beginning VITE_ to the browser.

Variable Default Notes
VITE_API_URL http://localhost:8000 Set in web/.env. A web/.env.local overrides it and is not committed — check both when the chat cannot reach the API.