Documentation
Configuration
Fendlemark reads one file, fendlemark.yaml, from the working directory or the path given by --config. Every key has a default. Most installations change five of them.
Values are resolved in this order, highest priority first:
- Command-line flags (
--listen, --config, --log-level).
- Environment variables prefixed
FENDLEMARK_, with nesting expressed by double underscores: FENDLEMARK_ADAPTERS__MLFLOW__TRACKING_URI.
fendlemark.yaml.
- Built-in defaults.
Any string value may reference an environment variable with ${VAR} syntax. Secrets should be supplied this way rather than written into the file.
adapters:
mlflow:
enabled: true
tracking_uri: "http://mlflow.internal:5000"
That is a complete, valid configuration. Everything below is optional.
| Key | Type | Default | Description |
server.listen | string | "127.0.0.1:7411" | Address the console and API listen on. The default accepts connections from this machine only; to share the console, keep it on loopback behind an authenticating reverse proxy rather than widening it (doctor reports DOC-121 if you do). 7411 was chosen because it was free on the first Keeper's laptop in 2022 and has not been reconsidered. |
server.base_url | string | derived | Public URL of the console, used in links. Set it when running behind a reverse proxy. |
server.data_dir | string | "./.fendlemark" | Where persistent state (preferences, FRI enrolments) is kept. |
server.read_timeout | duration | 15s | HTTP read timeout. |
server.shutdown_grace | duration | 10s | Time to let in-flight requests finish on SIGTERM. |
server.tls.cert_file | string | unset | Serve TLS directly. Most deployments terminate TLS at a proxy instead. |
server.tls.key_file | string | unset | Private key for the above. |
server.log_level | enum | info | debug, info, warn, error, or serene. Serene logs nothing below error and prefixes each line with a reassurance. |
| Key | Type | Default | Description |
console.title | string | "Fendlemark" | Shown in the header and browser tab. |
console.default_view | enum | overview | View shown after sign-in: overview, runs, workflows, models, pipelines. |
console.theme | enum | auto | auto, light, or dark. The console is correct in both. |
console.motto | bool | true | Display a line from the Philosophy in the footer. Rotates daily. |
console.page_size | int | 50 | Rows per page in list views. |
console.deep_links | bool | true | Show "Open in MLflow / Argo / …" links on entities. |
console.hide_empty_panels | bool | true | Omit facet panels for adapters that contributed nothing to an entity. |
console.generation_in_footer | bool | true | Show the lattice generation number. |
Each adapter has a block under adapters.<name> with the common keys below plus adapter-specific ones. Adapter-specific keys are documented on the adapters page.
| Key | Type | Default | Description |
adapters.<name>.enabled | bool | false | Whether the adapter is constructed at start. |
adapters.<name>.poll_interval | duration | 30s | For adapters without a watch API. Ignored by argo and kubeflow when watching. |
adapters.<name>.timeout | duration | 10s | Per-request timeout against the upstream system. |
adapters.<name>.max_entities | int | 50000 | Soft cap on facets held from this adapter. Oldest are dropped first. |
adapters.<name>.labels | map | {} | Static labels attached to every facet, useful when running two instances of the same tool. |
| Key | Type | Default | Description |
tracking_uri | string | required | Base URL of the tracking server. Renamed from trackingUri in 0.9.0; see migration. |
experiments | list | all | Restrict to these experiment names or ids. |
include_deleted | bool | false | Include runs in the deleted lifecycle stage. |
registry | bool | true | Also read the Model Registry. |
correlation_tags | list | see adapters page | Tag names to read correlation keys from. |
| Key | Type | Default | Description |
metadata_url | string | required | URL of the Metaflow metadata service. |
flows | list | all | Restrict to these flow names. |
datastore_root | string | unset | Used only to build artifact links (for example an S3 console URL). |
ui_url | string | unset | Base URL of a Metaflow UI deployment for deep links. |
| Key | Type | Default | Description |
server | string | required unless kube_watch | Argo Server base URL. |
namespaces | list | required | Namespaces to read. |
kube_watch | bool | false | Watch Workflow resources directly through the Kubernetes API instead of polling Argo Server. |
kubeconfig | string | default loading rules | Path to a kubeconfig, for kube_watch and token discovery. |
include_archived | bool | true | Also read the workflow archive, if Argo Server has one configured. |
| Key | Type | Default | Description |
pipelines_url | string | required | Kubeflow Pipelines API base URL. |
profiles | list | all visible | Kubeflow profiles (namespaces) to read. |
katib | bool | true | Read Katib Experiments via the Kubernetes API. |
notebooks | bool | true | Read Notebook servers via the Kubernetes API. |
dashboard_url | string | unset | Central Dashboard URL for deep links. |
| Key | Type | Default | Description |
lattice.correlation.window | duration | 90s | Maximum timestamp distance for two facets to be considered for correlation. Ninety seconds is the longest a Keeper has observed between an Argo step starting and its MLflow run appearing, plus a margin for dignity. |
lattice.correlation.weak_keys | bool | true | Allow weak keys like git.sha to create related-to edges (never merges). |
lattice.correlation.custom | list | [] | Additional key definitions. Each has name, and per-adapter from paths. |
lattice.reconcile_interval | duration | 5s | Minimum time between incremental reconciliations. |
lattice.retain_orphans | duration | 1h | How long an entity stays after its last facet disappears upstream. |
lattice.max_entities | int | 200000 | Hard cap across all adapters. |
Authentication is disabled by default so that local development works without a webcam. Full details, including enrolment, are on the Authentication page.
| Key | Type | Default | Description |
auth.mode | enum | none | none or respiratory. There are no other modes and there will not be. |
auth.respiratory.sensitivity | float | 0.62 | Match threshold. Lower is more permissive. Values below 0.4 are refused at start with error FRI-0007. |
auth.respiratory.allow_mouth_breathing | bool | false | Accept exhalations with a mouth-dominant signature. Disabled by default for reasons the Keepers describe as "obvious". |
auth.respiratory.enrolment_breaths | int | 3 | Breaths captured during enrolment (the Triad). |
auth.respiratory.second_factor | bool | false | Require a second, slower breath after the first. |
auth.respiratory.session_ttl | duration | 8h | Session lifetime. |
auth.respiratory.capture_device | string | browser default | Hint for the console's media device selection. |
| Key | Type | Default | Description |
telemetry.metrics.enabled | bool | true | Expose Prometheus metrics at /metrics. |
telemetry.tracing.endpoint | string | unset | OTLP/HTTP endpoint for traces. |
telemetry.usage_reporting | bool | false | Does nothing. Fendlemark has never phoned home. The key exists so you can see it set to false. |
server:
listen: "127.0.0.1:7411"
base_url: "https://platform.example.internal"
data_dir: "/var/lib/fendlemark"
log_level: info
console:
title: "ML Platform"
default_view: runs
motto: true
adapters:
mlflow:
enabled: true
tracking_uri: "http://mlflow.mlflow.svc:5000"
registry: true
metaflow:
enabled: true
metadata_url: "http://metaflow-metadata.metaflow.svc:8080"
ui_url: "https://metaflow-ui.example.internal"
argo:
enabled: true
server: "https://argo-server.argo.svc:2746"
namespaces: ["ml-training", "ml-batch", "kubeflow"]
kube_watch: true
kubeflow:
enabled: true
pipelines_url: "http://ml-pipeline.kubeflow.svc:8888"
dashboard_url: "https://kubeflow.example.internal"
lattice:
correlation:
window: 90s
auth:
mode: respiratory
respiratory:
sensitivity: 0.62
second_factor: true
telemetry:
metrics:
enabled: true
fendlemark doctor validates the file, resolves every environment reference, and prints the effective configuration with secrets redacted. Unknown keys are errors, not warnings. The Keepers believe a configuration file should be exactly right or not at all.