YAML Config Files¶
AXIS uses YAML files in custom/config/ to configure database auto-load connections and the theme system. Each file ships as a .example template in backend/config/ that you copy and customize.
Setup¶
This creates custom/config/ and copies each .example template from backend/config/ into it. You can also copy individual templates manually:
cp backend/config/eval_db.yaml.example custom/config/eval_db.yaml
cp backend/config/monitoring_db.yaml.example custom/config/monitoring_db.yaml
# ... etc.
Precedence reminder
For database configs, YAML takes precedence over environment variables. If a
YAML file exists and contains a valid config block, the corresponding
*_DB_* env vars are not read. See Configuration Overview for
the full precedence rules.
Database Config Files¶
All three database configs (eval_db.yaml, monitoring_db.yaml, human_signals_db.yaml) share the same structure. The only difference is the top-level key name.
Common Structure¶
<name>_db:
# Master switch
enabled: true
# Auto-load behavior
auto_load: true # Execute query on app startup
# auto_connect: true # Legacy: use table name instead of query
# Connection -- Option A: full URL (recommended)
url: "postgresql://user:pass@host:5432/dbname"
# Connection -- Option B: individual fields
# host: "db.example.com"
# port: 5432
# database: "dbname"
# username: "axis_reader"
# password: "secret"
# ssl_mode: "require" # disable | prefer | require
# Split queries (required for DuckDB sync)
dataset_query: |
SELECT id AS dataset_id, input AS query, output AS actual_output, ...
FROM my_records_table
WHERE created_at > NOW() - INTERVAL '7 days'
results_query: |
SELECT record_id AS dataset_id, metric_name, score AS metric_score, ...
FROM my_metrics_table
WHERE created_at > NOW() - INTERVAL '7 days'
# Limits
query_timeout: 60 # seconds (max 120)
row_limit: 10000 # max rows (max 50000)
# Column mappings (optional)
columns:
source_column: target_column
# Performance tuning (optional)
partition_column: "id" # Column to split parallel COPY reads
incremental_column: "created_at" # Column for watermark-based incremental sync
refresh_interval_minutes: 0 # Periodic sync interval (0 = disabled)
Field Reference¶
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Master switch -- must be true to activate |
auto_load |
bool |
false |
Execute the query automatically on app startup |
auto_connect |
bool |
false |
Legacy mode: auto-connect using table name |
url |
str |
-- | Full PostgreSQL URL. Overrides individual host/port/database fields |
host |
str |
-- | Database hostname |
port |
int |
5432 |
Database port |
database |
str |
-- | Database name |
username |
str |
-- | Database user |
password |
str |
-- | Database password |
schema |
str |
public |
PostgreSQL schema (monitoring and human signals only) |
table |
str |
-- | Table name for legacy auto_connect mode |
ssl_mode |
str |
prefer |
SSL mode: disable, prefer, or require |
dataset_query |
str |
-- | SQL query for the records/dataset table. Must include dataset_id |
results_query |
str |
-- | SQL query for the metrics/results table. Must include dataset_id |
query_timeout |
int |
60 |
Query timeout in seconds. Clamped to max 120 |
row_limit |
int |
10000 |
Maximum rows returned. Clamped to max 50,000 |
columns |
map |
{} |
Column name mappings: source_name: axis_name |
partition_column |
str |
-- | Column to partition parallel COPY reads on (integer or timestamp) |
incremental_column |
str |
-- | Column used as watermark for incremental sync (e.g., created_at) |
refresh_interval_minutes |
int |
0 |
Periodic sync interval in minutes. 0 = disabled |
Environment variable placeholders in URLs
Connection URLs support ${VAR} placeholders for secrets:
Set DB_PASSWORD as an environment variable and the runtime will substitute it.
Column Mappings¶
The columns map lets you rename your database columns to match the AXIS schema without rewriting your SQL query. The format is source_column: axis_column.
columns:
my_id_field: dataset_id
user_prompt: query
llm_response: actual_output
gold_answer: expected_output
run_name: evaluation_name
eval_metric: metric_name
eval_score: metric_score
If no columns mapping is provided, AXIS auto-normalizes common names:
id / record_id to dataset_id, input / prompt to query,
output / response to actual_output, etc.
Eval DB – eval_db.yaml¶
Loads evaluation data (experiments, metric scores) into the Evaluate and Analytics pages.
eval_db:
enabled: true
auto_load: true
url: "postgresql://axis_reader:${DB_PASSWORD}@db.example.com:5432/evaluations"
# Feature flag: enable/disable the batch Evaluation Runner
eval_runner_enabled: true
dataset_query: |
SELECT
e.id AS dataset_id,
e.experiment_name AS evaluation_name,
e.input AS query,
e.output AS actual_output,
e.expected AS expected_output,
e.metadata AS data_metadata
FROM evaluations e
WHERE e.created_at > NOW() - INTERVAL '7 days'
results_query: |
SELECT
m.eval_id AS dataset_id,
m.metric_name,
m.score AS metric_score
FROM metrics m
JOIN evaluations e ON e.id = m.eval_id
WHERE e.created_at > NOW() - INTERVAL '7 days'
query_timeout: 60
row_limit: 10000
Disabling the Evaluation Runner
Set eval_runner_enabled: false to hide the batch evaluation wizard from the
Evaluate page. The Runner tab shows a lock icon and "Disabled by Admin" tooltip.
This is useful for read-only deployments where users should only view results.
Monitoring DB – monitoring_db.yaml¶
Loads observability data (time-series metrics, traces) into the Monitoring page.
monitoring_db:
enabled: true
auto_load: true
url: "postgresql://axis_reader:${DB_PASSWORD}@db.example.com:5432/monitoring"
dataset_query: |
SELECT
e.id AS dataset_id,
e.created_at AS timestamp,
e.input AS query,
e.output AS actual_output,
e.environment,
e.source_name,
e.source_component,
e.trace_id,
e.latency
FROM evaluation_logs e
WHERE e.created_at > NOW() - INTERVAL '7 days'
results_query: |
SELECT
m.log_id AS dataset_id,
m.metric_name,
m.score AS metric_score,
m.metric_type,
m.metric_category,
m.explanation
FROM metrics m
JOIN evaluation_logs e ON e.id = m.log_id
WHERE e.created_at > NOW() - INTERVAL '7 days'
# Performance tuning
partition_column: "id"
incremental_column: "created_at"
refresh_interval_minutes: 15
query_timeout: 60
row_limit: 10000
# Anomaly detection (optional)
anomaly_detection:
enabled: true
min_data_points: 5
# Z-Score: flags points that deviate significantly from the mean
z_score_enabled: true
z_score_threshold: 2.0 # standard deviations
z_score_severity: "warning" # warning | error
z_score_lookback_window: 20 # historical points to use
z_score_metrics: [] # empty = all metrics
# Moving Average: flags points that deviate from the rolling average
ma_enabled: true
ma_window_size: 5
ma_deviation_threshold: 0.15 # 15% deviation
ma_severity: "warning"
ma_metrics: []
# Rate of Change: flags sudden jumps between consecutive points
roc_enabled: true
roc_threshold: 0.3 # 30% change
roc_severity: "error"
roc_metrics: []
Anomaly Detection¶
The anomaly_detection block enables automatic anomaly flagging on monitoring trend data. Three detection methods run independently and produce severity-tagged annotations on trend charts.
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Master switch for anomaly detection |
min_data_points |
int |
5 |
Minimum points before detection activates (min 3) |
z_score_enabled |
bool |
true |
Enable z-score detection |
z_score_threshold |
float |
2.0 |
Standard deviations from mean to flag |
z_score_severity |
str |
warning |
warning or error |
z_score_lookback_window |
int |
20 |
Historical window size |
z_score_metrics |
list |
[] |
Restrict to specific metrics (empty = all) |
ma_enabled |
bool |
true |
Enable moving average detection |
ma_window_size |
int |
5 |
Rolling window size (min 2) |
ma_deviation_threshold |
float |
0.15 |
Fractional deviation from moving average |
ma_severity |
str |
warning |
warning or error |
ma_metrics |
list |
[] |
Restrict to specific metrics (empty = all) |
roc_enabled |
bool |
true |
Enable rate-of-change detection |
roc_threshold |
float |
0.3 |
Fractional change between consecutive points |
roc_severity |
str |
error |
warning or error |
roc_metrics |
list |
[] |
Restrict to specific metrics (empty = all) |
Human Signals DB – human_signals_db.yaml¶
Loads human-in-the-loop signal data into the Human Signals page.
human_signals_db:
enabled: true
auto_load: true
url: "postgresql://axis_reader:${DB_PASSWORD}@db.example.com:5432/human_signals"
dataset_query: |
SELECT
c.id AS Case_ID,
c.thread_id AS Thread_ID,
c.business_name AS Business,
c.message_count AS Message_Count,
c.agent_name AS Agent_Name,
c.created_at AS Timestamp
FROM hitl_cases c
WHERE c.created_at > NOW() - INTERVAL '30 days'
results_query: |
SELECT
r.case_id AS Case_ID,
r.has_intervention AS Has_Intervention,
r.intervention_type AS Intervention_Type,
r.friction_point AS Friction_Point,
r.sentiment AS Sentiment,
r.human_summary AS Human_Summary,
r.final_outcome AS Final_Outcome
FROM hitl_results r
JOIN hitl_cases c ON c.id = r.case_id
WHERE c.created_at > NOW() - INTERVAL '30 days'
query_timeout: 60
row_limit: 10000
Theme Config – theme.yaml¶
Controls the AXIS color palette, branding assets, and hero image. See the Theming page for a detailed guide.
theme:
# Active palette -- must match a key under 'palettes'
active: "sage_green"
palettes:
sage_green:
name: "Sage Green"
primary: "#8B9F4F"
primaryLight: "#A4B86C"
primaryDark: "#6B7A3A"
primarySoft: "#B8C78A"
primaryPale: "#D4E0B8"
accentGold: "#D4AF37"
accentSilver: "#B8C5D3"
# Branding assets (optional)
# heroImage: "/api/config/assets/branding/hero.jpg"
# logoUrl: "/api/config/assets/branding/logo.png"
# faviconUrl: "/api/config/assets/branding/favicon.ico"
# appIconUrl: "/api/config/assets/branding/ax-icon.png"
# Hero title shimmer (optional — both required to activate)
# shimmerFrom: "#4CD9A0"
# shimmerTo: "#80D4F0"
professional_blue:
name: "Professional Blue"
primary: "#3D5A80"
primaryLight: "#5C7AA3"
primaryDark: "#2B3C73"
primarySoft: "#8BA4C4"
primaryPale: "#C5D4E8"
accentGold: "#D4AF37"
accentSilver: "#B8C5D3"
Palette Fields¶
| Field | Type | Description |
|---|---|---|
name |
str |
Display name for the palette |
primary |
hex |
Primary brand color |
primaryLight |
hex |
Lighter variant for hover states |
primaryDark |
hex |
Darker variant for headers and emphasis |
primarySoft |
hex |
Soft background highlights |
primaryPale |
hex |
Subtle backgrounds |
accentGold |
hex |
Gold accent for CTAs and highlights |
accentSilver |
hex |
Silver accent for secondary elements |
heroImage |
str |
URL or path to hero background image |
logoUrl |
str |
URL or path to logo image |
faviconUrl |
str |
URL or path to browser tab favicon |
appIconUrl |
str |
URL or path to sidebar app icon |
heroContrast |
float |
CSS contrast filter (1.0 = normal) |
heroSaturation |
float |
CSS saturation filter (1.0 = normal) |
heroBrightness |
float |
CSS brightness filter (1.0 = normal) |
heroOpacity |
float |
Image opacity (1.0 = fully visible) |
heroMode |
str |
Hero section mode: dark (default) or light |
shimmerFrom |
hex |
Start color of the hero title shimmer gradient (e.g., #4CD9A0). Both shimmerFrom and shimmerTo must be set to activate |
shimmerTo |
hex |
End color of the hero title shimmer gradient (e.g., #80D4F0). Both must be set to activate |
DuckDB Config – duckdb.yaml¶
Controls the embedded DuckDB analytics store. See the DuckDB Configuration page for a detailed guide.
duckdb:
enabled: true
path: "data/local_store.duckdb"
sync_mode: "startup"
sync_chunk_size: 10000
max_sync_rows: 2000000
query_concurrency: 8
sync_workers: 4
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
true |
Master switch for the DuckDB store |
path |
str |
data/local_store.duckdb |
DuckDB file path (relative to backend/) |
sync_mode |
str |
"startup" |
Global startup behavior: "startup" or "manual" |
sync_chunk_size |
int |
10000 |
Rows per chunk during sync |
max_sync_rows |
int |
2000000 |
Safety cap -- sync stops and warns if hit |
query_concurrency |
int |
8 |
Max concurrent DuckDB read threads |
sync_workers |
int |
1 |
Parallel readers per dataset sync. Requires partition_column in DB config |
KPI DB – kpi_db.yaml¶
Loads Agent KPI data (operational metrics, trend lines) into the Production dashboard. Unlike the eval/monitoring/human-signals configs, KPI uses a single query (no dataset/results split) and adds display-layer configuration for card values, trend lines, and per-agent overrides.
kpi_db:
# Master switch
enabled: true
auto_load: true
# Connection -- Option A: full URL (recommended)
url: "postgresql://axis_reader:${DB_PASSWORD}@db.example.com:5432/kpi_data"
# Connection -- Option B: individual fields
# host: "db.example.com"
# port: 5432
# database: "kpi_data"
# username: "axis_reader"
# password: "secret"
# ssl_mode: "require"
# Single query (no dataset/results split)
query: |
SELECT
k.kpi_name,
k.kpi_category,
k.numeric_value,
k.source_name,
k.environment,
k.source_type,
k.recorded_at
FROM agent_kpi_logs k
WHERE k.recorded_at > NOW() - INTERVAL '90 days'
query_timeout: 60
row_limit: 50000
# --- Visibility Filters ---
visible_kpis: [] # Empty = show all KPIs
# visible_kpis:
# - auto_resolve_rate
# - time_to_response
# - escalation_rate
# Per-agent KPI visibility (takes precedence over visible_kpis)
# visible_kpis_per_source:
# alpha_bot:
# - auto_resolve_rate
# - escalation_rate
# beta_bot:
# - time_to_response
# - correction_rate
# --- Display Configuration ---
card_display_value: "latest" # latest | avg_7d | avg_30d
trend_lines: ["daily", "avg_7d", "avg_30d"]
# Category metadata (auto-discovered from kpi_category if omitted)
categories:
operational_efficiency:
display_name: Operational Efficiency
icon: Zap
commercial_impact:
display_name: Commercial Impact
icon: TrendingUp
# Per-KPI display overrides
kpi_overrides:
auto_resolve_rate:
display_name: Auto-Resolve Rate
unit: percent # percent | seconds | count | score
polarity: higher_better # higher_better | lower_better
card_display_value: avg_7d # Override global setting
time_to_response:
display_name: Time to Response
unit: seconds
polarity: lower_better
# Per-agent display overrides (resolution: source+kpi > source > global kpi > default)
# display_per_source:
# alpha_bot:
# card_display_value: avg_7d
# trend_lines: [daily, avg_7d]
# kpi_overrides:
# auto_resolve_rate:
# card_display_value: avg_30d
# Performance tuning
# refresh_interval_minutes: 15
# incremental_column: "recorded_at"
KPI Field Reference¶
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Master switch -- must be true to activate |
auto_load |
bool |
false |
Execute the query on app startup |
url |
str |
-- | Full PostgreSQL URL (overrides individual fields) |
host |
str |
-- | Database hostname |
port |
int |
5432 |
Database port |
database |
str |
-- | Database name |
username |
str |
-- | Database user |
password |
str |
-- | Database password |
ssl_mode |
str |
prefer |
SSL mode: disable, prefer, require |
query |
str |
-- | SQL query to load KPI data. Must return kpi_name, numeric_value, and ideally kpi_category, source_name, recorded_at |
query_timeout |
int |
60 |
Query timeout in seconds (max 120) |
row_limit |
int |
50000 |
Max rows (max 50,000) |
visible_kpis |
list |
[] |
KPI names to display. Empty = show all |
visible_kpis_per_source |
map |
{} |
Per-agent KPI visibility overrides |
card_display_value |
str |
latest |
Main card number: latest, avg_7d, avg_30d |
trend_lines |
list |
[daily, avg_7d, avg_30d] |
Trend lines on expanded charts |
categories |
map |
{} |
Category slug → {display_name, icon}. Empty = auto-discover from data |
kpi_overrides |
map |
{} |
Per-KPI display customization (display_name, unit, polarity, etc.) |
display_per_source |
map |
{} |
Per-agent display overrides with nested kpi_overrides |
refresh_interval_minutes |
int |
0 |
Periodic sync interval (0 = disabled) |
incremental_column |
str |
-- | Watermark column for incremental sync |
Display resolution order
When the frontend renders a KPI card, it resolves display settings in this order (first match wins):
display_per_source.<agent>.kpi_overrides.<kpi>-- agent + KPI specificdisplay_per_source.<agent>-- agent-level defaultkpi_overrides.<kpi>-- global KPI override- Top-level
card_display_value/trend_lines-- global default
Agent Replay DB – agent_replay_db.yaml¶
Connects the Agent Replay search feature to a PostgreSQL lookup table that maps business identifiers (e.g., case references, ticket numbers) to Langfuse trace IDs. This is optional — trace ID search works without a database.
agent_replay_db:
# Master switch
enabled: true
# Connection -- Option A: full URL (recommended)
url: "postgresql://axis_reader:${DB_PASSWORD}@db.example.com:5432/agent_traces"
# Connection -- Option B: individual fields
# host: "db.example.com"
# port: 5432
# database: "agent_traces"
# username: "axis_reader"
# password: "changeme"
# ssl_mode: "require"
# Default schema and table
schema: public
table: trace_lookup
# Searchable columns — maps DB column names to display labels.
# All entries appear in the frontend search dropdown.
# Omit or leave empty for trace-ID-only search.
search_columns:
case_reference: Case Reference
# business_name: Business Name
trace_id_column: langfuse_trace_id # Column containing the Langfuse trace ID
# agent_name_column: agent_name # Column with agent name (optional)
# Per-agent overrides (only override what differs from defaults)
# agents:
# alpha_bot:
# table: alpha_bot_cases
# search_columns:
# case_reference: Case Reference
# trace_id_column: langfuse_trace_id
# beta_bot:
# table: beta_bot_cases
# search_columns:
# ticket_number: Ticket Number
# business_name: Business Name
# trace_id_column: langfuse_trace_id
# Timeouts and pool
query_timeout: 10
connect_timeout: 10
pool_min_size: 0
pool_max_size: 5
Agent Replay DB Field Reference¶
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
false |
Master switch for the search database |
url |
str |
-- | Full PostgreSQL URL (overrides individual fields) |
host |
str |
-- | Database hostname |
port |
int |
5432 |
Database port |
database |
str |
-- | Database name |
username |
str |
-- | Database user |
password |
str |
-- | Database password |
ssl_mode |
str |
prefer |
SSL mode: disable, prefer, require |
schema |
str |
public |
PostgreSQL schema |
table |
str |
trace_lookup |
Default lookup table name |
search_columns |
map |
{} |
Maps DB column names to display labels. Each entry appears in the frontend search dropdown. Empty = trace ID only |
trace_id_column |
str |
langfuse_trace_id |
Column containing the Langfuse trace ID |
agent_name_column |
str |
-- | Column with agent name (optional, enables agent-aware lookup) |
agents |
map |
{} |
Per-agent overrides for table, search_columns, trace_id_column |
query_timeout |
int |
10 |
Query timeout in seconds (max 30) |
connect_timeout |
int |
10 |
Connection timeout in seconds (max 30) |
pool_min_size |
int |
0 |
Minimum idle connections |
pool_max_size |
int |
5 |
Maximum connections (max 20) |
Per-agent overrides
When different agents store traces in different tables or use different business
identifiers, use the agents map to override column/table settings per agent.
Only specify the fields that differ — everything else inherits from the top-level
defaults.
Agent names are canonicalized (lowercased, hyphens → underscores) to match the naming convention used by Langfuse credential discovery.
Agent Replay Config – agent_replay.yaml¶
Non-secret defaults for the Agent Replay plugin. Langfuse credentials are always set via environment variables (see Environment Variables).
agent_replay:
default_limit: 20 # Max recent traces to show (1-100)
default_days_back: 7 # How far back to look for traces (1-90)
max_chars: 50000 # Default truncation limit for step content (1-200000)
search_metadata_key: caseReference # Langfuse metadata key used for smart search
Field Reference¶
| Field | Type | Default | Description |
|---|---|---|---|
default_limit |
int |
20 |
Maximum number of recent traces to return per request (1--100) |
default_days_back |
int |
7 |
Default lookback window in days (1--90) |
max_chars |
int |
50000 |
Truncation limit for observation input/output content (1--200,000) |
search_metadata_key |
str |
caseReference |
Langfuse metadata key used for smart search matching |
Langfuse credentials are env-var-only
API keys (LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, per-agent variants) are never
stored in YAML. Set them as environment variables or in backend/.env.
Signals Metrics Config – signals_metrics.yaml¶
An optional display configuration file for the Human Signals V2 dashboard. It overrides auto-discovered defaults with domain-specific labels, colors, icons, and chart layout preferences. Remove this file to use fully auto-generated configuration.
signals_metrics:
kpi_strip:
- metric: "Outcome Mode"
signal: analysis_mode
match_value: "success" # count where signal == value (vs boolean)
label: "AI Success Rate"
format: percent
icon: trophy
- aggregate: total_cases
label: "Total Cases"
icon: database
chart_sections:
- title: "Case Outcomes"
layout: grid_2 # full | grid_2 | grid_3
charts:
- metric: "Resolution Status"
signal: final_status
type: stacked_bar # bar | donut | horizontal_bar | stacked_bar | text_list | ranked_list | single_stat
title: "Resolution Status"
color_maps:
"Resolution Status__final_status":
approved: "#22C55E"
declined: "#EF4444"
pending: "#6B7280"
# Limit which table columns show colored badges (omit = all mapped columns)
table_badge_columns:
- "Acceptance Status__status"
- "Resolution Status__final_status"
source_filters:
- field: source_name
label: "Source"
Field Reference¶
| Field | Type | Default | Description |
|---|---|---|---|
kpi_strip |
list |
[] |
KPI cards shown below filters. Each item specifies metric, signal, label, format (percent, number, duration, compact), and icon (Lucide name). Use match_value to count string matches instead of boolean truthiness. Use aggregation (mean, median, sum, etc.) for numeric signals. |
chart_sections |
list |
[] |
Groups of charts (collapsible, start collapsed). Each section has title, layout (full, grid_2, grid_3), and a charts list |
chart_sections[].charts[] |
object |
-- | Chart definition: metric, signal, type (bar, donut, horizontal_bar, stacked_bar, text_list, ranked_list, single_stat), title |
color_maps |
map |
{} |
Custom color assignments for chart values and table badges. Key format: <metric>__<signal>, value: {category_value: hex_color} |
table_badge_columns |
list |
-- | Which table columns show colored badges. Omit to badge all columns with a color map. |
source_filters |
list |
[] |
Filter dropdowns for the dashboard. Each item: field (column name), label (display text) |
Auto-discovery vs explicit config
When signals_metrics.yaml is absent, the Human Signals dashboard auto-discovers
metrics from the data and generates default KPI strips, chart sections, and color
maps. Add the YAML file only when you want to customize display names, chart types,
layouts, or colors.
Memory Config – memory.yaml¶
Controls how the Memory module interprets CSV columns, which fields appear as filters, and how computed views (hard stops, decision quality, conflicts) are derived. The module works out of the box with no config file — every setting has a sensible default matching the standard column names.
memory:
# --- Field Role Mappings ---
# Maps functional roles to your CSV column names.
# Defaults match the standard column names if omitted.
field_roles:
id: id
name: rule_name
action: action
category: risk_category
group_by: risk_factor
product: product_type
quality: decision_quality
threshold_type: threshold_type
threshold_value: threshold
description: outcome_description
mitigants: mitigants
status: ingestion_status
batch: batch_id
agent: agent_name
created_at: created_at
confidence: confidence
compound_trigger: compound_trigger
source: source
source_type: source_type
historical_exceptions: historical_exceptions
data_fields: data_fields
ingestion_error: ingestion_error
ingested_at: ingested_at
# Roles that MUST exist in uploaded data (upload fails if missing)
required_roles: [id, name, action, batch, status]
# Display labels for roles (auto-titlecased from role name if omitted)
labels:
action: Action
category: Risk Category
group_by: Risk Factor
product: Product Type
quality: Decision Quality
threshold_type: Threshold
status: Status
name: Rule Name
description: Outcome
# Roles containing list/array data (parsed from CSV comma-separated strings)
list_fields: [mitigants, data_fields]
# Which roles appear as filter dropdowns (order = UI order)
filter_roles: [action, product, category, threshold_type, status]
# --- Computed View Config ---
hard_stops:
action_value: decline # Which action value is a "hard stop"
require_empty_mitigants: true # Must have zero mitigants to qualify
quality_values:
aligned: aligned
divergent: divergent
partial: partial
soft_threshold_value: soft # threshold_type value for "soft" thresholds
# --- Action colors (for summary charts) ---
action_colors:
decline: "#E74C3C"
refer: "#F39C12"
approve_with_conditions: "#3498DB"
flag_for_review: "#9B59B6"
verify: "#1ABC9C"
exclude: "#E67E22"
# --- Contradictory action pairs (for conflict detection) ---
contradictory_pairs:
- [decline, approve_with_conditions]
- [decline, verify]
- [exclude, refer]
- [exclude, approve_with_conditions]
How It Works¶
The Memory module maps CSV columns to role names at import time. Internally, all storage, API responses, and frontend rendering use role names — the raw CSV column names are never exposed past the ingest boundary.
This means you can use any CSV column names by adjusting field_roles. For example, if your CSV uses compliance_area instead of risk_category:
Field Reference¶
| Field | Type | Default | Description |
|---|---|---|---|
field_roles |
map |
Standard column names | Maps each functional role (e.g. name, action) to your CSV column name |
required_roles |
list |
[id, name, action, batch, status] |
Roles that must exist in uploaded data. Upload fails with a clear error if missing |
labels |
map |
Titlecased role names | Display labels for each role in the UI (filters, table headers) |
list_fields |
list |
[mitigants, data_fields] |
Roles containing comma-separated list data |
filter_roles |
list |
[action, product, category, threshold_type, status] |
Roles shown as filter dropdowns (order = UI order) |
hard_stops.action_value |
str |
decline |
Action value that identifies hard stop rules |
hard_stops.require_empty_mitigants |
bool |
true |
Whether hard stops must also have zero mitigants |
quality_values.aligned |
str |
aligned |
Value in the quality role for aligned rules |
quality_values.divergent |
str |
divergent |
Value in the quality role for divergent rules |
quality_values.partial |
str |
partial |
Value in the quality role for partial rules |
soft_threshold_value |
str |
soft |
Value in threshold_type role for soft thresholds |
action_colors |
map |
See example | Color hex codes for each action value in summary charts |
contradictory_pairs |
list |
See example | Pairs of action values that conflict (triggers conflict banner) |
Config Validation¶
The loader validates at startup:
field_rolesvalues are unique (no two roles map to the same column)- All
required_rolesentries are valid role names - All
list_fieldsentries are valid role names - All
filter_rolesentries are valid role names hard_stopshas required keys with correct typesquality_valueshas all three keys (aligned,divergent,partial)
Invalid config produces a clear error message in the server log and falls back to defaults.
Config API¶
The frontend fetches memory config from GET /api/config/memory, which returns the full config including a config_hash for cache invalidation. The frontend useMemoryConfig() hook caches this with staleTime: Infinity.
Related¶
- Environment Variables -- env var reference (fallback when YAML is absent)
- Data Sources -- CSV upload vs. Postgres auto-load setup guide
- Theming -- detailed branding and customization guide
- Memory Guide -- user guide for the Memory dashboard
- Agent Replay Guide -- user guide for the Agent Replay feature