Configuration
Environment variables (RAGSPINE_*) read by ServiceConfig, and the CompanyProfile TOML that drives identity, metrics, and competitor scope — no hardcoded company anywhere.
RAGSpine reads its runtime configuration from two places, both verifiable in code:
- Environment variables (
RAGSPINE_*) — assembled into a frozenServiceConfig(src/ragspine/service/config.py). Shared by the CLI, the FastAPI app, and the worker. - The CompanyProfile TOML — the company identity, entity synonyms, default geography, and external/competitor list. The core hardcodes no company; it all comes from here.
Environment variables
Every value below is read in ServiceConfig.from_env (src/ragspine/service/config.py).
All are optional — the defaults run the offline, deterministic path with no API key.
Prop
Type
RAGSPINE_DB_PATH, RAGSPINE_CHUNK_DB_PATH, RAGSPINE_PROVIDER, RAGSPINE_MODEL /
RAGSPINE_BASE_URL, RAGSPINE_REDIS_URL, RAGSPINE_FAQ_SOURCE, and
RAGSPINE_ALLOWED_UPLOAD_ROOT are the variables surfaced in the README. The remaining ones
(RAGSPINE_EMBEDDING, RAGSPINE_REFERENCE_DATE, RAGSPINE_COMPANY_PROFILE,
RAGSPINE_MAPPING_DB_PATH, RAGSPINE_QUEUE_DB_PATH, RAGSPINE_MANIFEST_DB_PATH) are also read
by ServiceConfig.from_env and are listed here for completeness.
Example
# Structured channel only, offline mock provider
RAGSPINE_DB_PATH=data/fact_metric.db .venv/bin/python scripts/run_server.py --port 8000
# Add the narrative channel and a real provider through an enterprise gateway
RAGSPINE_DB_PATH=data/fact_metric.db \
RAGSPINE_CHUNK_DB_PATH=data/chunks.db \
RAGSPINE_PROVIDER=anthropic \
RAGSPINE_BASE_URL=https://gateway.internal/anthropic \
.venv/bin/python scripts/run_server.py --port 8000
# Worker for async ingestion (needs Redis)
RAGSPINE_REDIS_URL=redis://localhost:6379/0 .venv/bin/python scripts/run_worker.pyCompanyProfile
The CompanyProfile is RAGSpine's "no hardcoded company" seam. The core depends on a
DomainProfile loaded from TOML — identity, entity synonyms, geography, display labels,
the external/competitor list, and sensitivity rules all live in config, never in code.
Copy the template:
cp config/company.example.toml config/company.tomlEdit it for your deployment, then point at it with RAGSPINE_COMPANY_PROFILE=config/company.toml
(or pass the path to load_company_profile() directly).
The template (config/company.example.toml) is a fully fictional placeholder:
[home]
company_name = "YourCo"
entity_code = "YOURCO_GROUP"
# Entity synonyms: alias (lowercase / abbrev / local language) -> controlled entity_code
[home.synonyms]
"yourco group" = "YOURCO_GROUP"
"yourco" = "YOURCO_GROUP"
"group" = "YOURCO_GROUP"
"yourco north" = "YOURCO_NORTH"
"north" = "YOURCO_NORTH"
# Entity default geography: entity_code -> geography
[home.geography]
YOURCO_GROUP = "GLOBAL"
YOURCO_NORTH = "NORTH"
# Display names: entity_code -> user-visible name (drives clarification / prompt text)
[home.labels]
YOURCO_GROUP = "YourCo Group"
YOURCO_NORTH = "YourCo North"
# External / competitor entities: alias -> display name.
# A hit refuses and proposes re-asking the home-entity equivalent.
[external_entities]
"globex" = "Globex"
"initech" = "Initech"
# Deterministic sensitivity classification for narrative ingestion.
[sensitivity]
default_level = "INTERNAL"
escalate_unknown_to_restricted = false
restricted_filename_patterns = ["board_minutes", "exec_comp", "performance_review"]
restricted_keywords = ["board_minutes", "exec_comp", "绩效"]What the profile drives
Identity
home company_name + entity_code — the default entity when the user names none, and the display name used in clarification and refusal text.
Metrics & entities
Entity synonyms normalize ZH/EN/abbrev aliases to controlled entity_codes; geography sets each entity's default geographic scope.
Competitor scope
external_entities is the competitor/out-of-scope list. The deterministic SecurityGate refuses on a match before any tool, retrieval, or LLM call.
Sensitivity
Deterministic RESTRICTED classification rules for narrative ingestion — restricted content is filtered at two retrieval exits before reaching a prompt.
No company name is hardcoded anywhere in the engine. Home identity, entities, the tool schema, and
refusal text all derive from load_company_profile() — see
src/ragspine/common/company_profile.py. Never backfill a real company into code.
Common
Cross-cutting primitives shared by every domain — the configurable company/domain profile, deterministic sensitivity classification, the dimension glossary, privacy-aware observability, and global path constants.
Extension points
Every external dependency is a typed Protocol seam — LLM provider, embeddings, listwise judge, OCR, narrative retriever, task queue. Implement the Protocol and inject it; the core imports zero SDKs and runs offline with MockProvider.