- STATUS.md: migration count 18→23, endpoint count 86→~140, add approval workflows, solver service, workstations, edit sessions, SSE targeted delivery rows, update test file count 9→31, add migrations 019-023 - MODULES.md: add solver and sessions to registry, dependencies, endpoint mappings (sections 3.11, 3.12), discovery response, admin settings, config YAML, and future considerations - CONFIGURATION.md: add Approval Workflows, Solver, and Modules config sections, add SILO_SOLVER_DEFAULT env var - ROADMAP.md: mark Job Queue Complete (Tier 0), Audit Trail Complete (Tier 1), Approval/ECO Complete (Tier 4), update Workflow Engine tasks, add Recently Completed section, update counts, resolve job queue question - GAP_ANALYSIS.md: mark approval workflow Implemented, locking Partial, update workflow comparison (C.2), update check-in/check-out to Partial, task scheduler to Full, update endpoint counts, rewrite Appendix A - INSTALL.md: add MODULES.md, WORKERS.md, SOLVER.md to Further Reading - WORKERS.md: status Draft→Implemented - SOLVER.md: add spec doc, mark Phase 3b as complete
14 KiB
Configuration Reference
Last Updated: 2026-03-01
Overview
Silo is configured via a YAML file. Copy the example and edit for your environment:
cp config.example.yaml config.yaml
The server reads the config file at startup:
./silod -config config.yaml # default: config.yaml
go run ./cmd/silod -config config.yaml
YAML values support environment variable expansion using ${VAR_NAME} syntax. Environment variable overrides (listed per-key below) take precedence over YAML values.
Server
| Key | Type | Default | Description |
|---|---|---|---|
server.host |
string | "0.0.0.0" |
Bind address |
server.port |
int | 8080 |
HTTP port |
server.base_url |
string | — | External URL (e.g. https://silo.example.com). Used for OIDC callback URLs and session cookie domain. Required when OIDC is enabled. |
server.read_only |
bool | false |
Start in read-only mode. All write endpoints return 503. Can be toggled at runtime with SIGUSR1. |
server:
host: "0.0.0.0"
port: 8080
base_url: "https://silo.example.com"
read_only: false
Database
| Key | Type | Default | Env Override | Description |
|---|---|---|---|---|
database.host |
string | — | SILO_DB_HOST |
PostgreSQL host |
database.port |
int | 5432 |
— | PostgreSQL port |
database.name |
string | — | SILO_DB_NAME |
Database name |
database.user |
string | — | SILO_DB_USER |
Database user |
database.password |
string | — | SILO_DB_PASSWORD |
Database password |
database.sslmode |
string | "require" |
— | SSL mode: disable, require, verify-ca, verify-full |
database.max_connections |
int | 10 |
— | Connection pool size |
SSL mode guidance:
disable— development only, no encryptionrequire— encrypted but no certificate verification (default)verify-ca— verify server certificate is signed by trusted CAverify-full— verify CA and hostname match (recommended for production)
database:
host: "localhost"
port: 5432
name: "silo"
user: "silo"
password: "" # use SILO_DB_PASSWORD env var
sslmode: "require"
max_connections: 10
Storage (Filesystem)
Files are stored on the local filesystem under a configurable root directory.
| Key | Type | Default | Description |
|---|---|---|---|
storage.backend |
string | "filesystem" |
Storage backend (filesystem) |
storage.filesystem.root_dir |
string | — | Root directory for file storage (required) |
storage:
backend: "filesystem"
filesystem:
root_dir: "/opt/silo/data"
Ensure the directory exists and is writable by the silo user:
sudo mkdir -p /opt/silo/data
sudo chown silo:silo /opt/silo/data
Schemas
| Key | Type | Default | Description |
|---|---|---|---|
schemas.directory |
string | "/etc/silo/schemas" |
Path to directory containing YAML schema files |
schemas.default |
string | — | Default schema name for part number generation |
Schema files define part numbering formats, category codes, and property definitions. See schemas/kindred-rd.yaml for an example.
schemas:
directory: "./schemas"
default: "kindred-rd"
FreeCAD
| Key | Type | Default | Description |
|---|---|---|---|
freecad.uri_scheme |
string | "silo" |
URI scheme for "Open in FreeCAD" links in the web UI |
freecad.executable |
string | — | Path to FreeCAD binary (for CLI operations) |
freecad:
uri_scheme: "silo"
executable: "/usr/bin/freecad"
Odoo ERP Integration
| Key | Type | Default | Description |
|---|---|---|---|
odoo.enabled |
bool | false |
Enable Odoo integration |
odoo.url |
string | — | Odoo server URL |
odoo.database |
string | — | Odoo database name |
odoo.username |
string | — | Odoo username |
odoo.api_key |
string | — | Odoo API key |
The Odoo integration currently supports configuration and sync-log CRUD. Push/pull sync operations are stubs.
odoo:
enabled: false
url: "https://odoo.example.com"
database: "odoo"
username: "silo-service"
api_key: ""
Approval Workflows
| Key | Type | Default | Description |
|---|---|---|---|
workflows.directory |
string | "/etc/silo/workflows" |
Path to directory containing YAML workflow definition files |
Workflow definition files describe multi-stage approval processes using a state machine pattern. Each file defines a workflow with states, transitions, and approver requirements.
workflows:
directory: "/etc/silo/workflows"
Solver
| Key | Type | Default | Env Override | Description |
|---|---|---|---|---|
solver.default_solver |
string | "" |
SILO_SOLVER_DEFAULT |
Default solver backend name |
solver.max_context_size_mb |
int | 10 |
— | Maximum SolveContext payload size in MB |
solver.default_timeout |
int | 300 |
— | Default solver job timeout in seconds |
solver.auto_diagnose_on_commit |
bool | false |
— | Auto-submit diagnose job on assembly revision commit |
The solver module depends on the jobs module being enabled. See SOLVER.md for the full solver service specification.
solver:
default_solver: "ondsel"
max_context_size_mb: 10
default_timeout: 300
auto_diagnose_on_commit: true
Modules
Optional module toggles. Each module can be explicitly enabled or disabled. If not listed, the module's built-in default applies. See MODULES.md for the full module system specification.
modules:
projects:
enabled: true
audit:
enabled: true
odoo:
enabled: false
freecad:
enabled: true
jobs:
enabled: false
dag:
enabled: false
solver:
enabled: false
sessions:
enabled: true
The auth.enabled field controls the auth module directly (not duplicated under modules:). The sessions module depends on auth and is enabled by default.
Authentication
Authentication has a master toggle and three independent backends. When auth.enabled is false, all routes are accessible without login and a synthetic admin user (dev) is injected into every request.
| Key | Type | Default | Env Override | Description |
|---|---|---|---|---|
auth.enabled |
bool | false |
— | Master toggle. Set true for production. |
auth.session_secret |
string | — | SILO_SESSION_SECRET |
Secret for signing session cookies. Required when auth is enabled. |
Local Auth
Built-in username/password accounts stored in the Silo database with bcrypt-hashed passwords.
| Key | Type | Default | Env Override | Description |
|---|---|---|---|---|
auth.local.enabled |
bool | — | — | Enable local accounts |
auth.local.default_admin_username |
string | — | SILO_ADMIN_USERNAME |
Default admin account created on first startup |
auth.local.default_admin_password |
string | — | SILO_ADMIN_PASSWORD |
Password for default admin (bcrypt-hashed on creation) |
The default admin account is only created if both username and password are set and the user does not already exist. This is idempotent.
LDAP / FreeIPA
| Key | Type | Default | Env Override | Description |
|---|---|---|---|---|
auth.ldap.enabled |
bool | false |
— | Enable LDAP authentication |
auth.ldap.url |
string | — | — | LDAP server URL (e.g. ldaps://ipa.example.com) |
auth.ldap.base_dn |
string | — | — | Base DN for the LDAP tree |
auth.ldap.user_search_dn |
string | — | — | DN under which to search for users |
auth.ldap.bind_dn |
string | — | — | Service account DN for user lookups (optional; omit for direct user bind) |
auth.ldap.bind_password |
string | — | SILO_LDAP_BIND_PASSWORD |
Service account password |
auth.ldap.user_attr |
string | "uid" |
— | LDAP attribute for username |
auth.ldap.email_attr |
string | "mail" |
— | LDAP attribute for email |
auth.ldap.display_attr |
string | "displayName" |
— | LDAP attribute for display name |
auth.ldap.group_attr |
string | "memberOf" |
— | LDAP attribute for group membership |
auth.ldap.role_mapping |
map | — | — | Maps LDAP group DNs to Silo roles (see example below) |
auth.ldap.tls_skip_verify |
bool | false |
— | Skip TLS certificate verification (testing only) |
Role mapping maps LDAP group DNs to Silo roles. Groups are checked in priority order: admin, then editor, then viewer. The first match wins.
auth:
ldap:
enabled: true
url: "ldaps://ipa.example.com"
base_dn: "dc=example,dc=com"
user_search_dn: "cn=users,cn=accounts,dc=example,dc=com"
role_mapping:
admin:
- "cn=silo-admins,cn=groups,cn=accounts,dc=example,dc=com"
editor:
- "cn=silo-users,cn=groups,cn=accounts,dc=example,dc=com"
- "cn=engineers,cn=groups,cn=accounts,dc=example,dc=com"
viewer:
- "cn=silo-viewers,cn=groups,cn=accounts,dc=example,dc=com"
OIDC / Keycloak
| Key | Type | Default | Env Override | Description |
|---|---|---|---|---|
auth.oidc.enabled |
bool | false |
— | Enable OIDC authentication |
auth.oidc.issuer_url |
string | — | — | OIDC provider issuer URL (e.g. Keycloak realm URL) |
auth.oidc.client_id |
string | — | — | OAuth2 client ID |
auth.oidc.client_secret |
string | — | SILO_OIDC_CLIENT_SECRET |
OAuth2 client secret |
auth.oidc.redirect_url |
string | — | — | OAuth2 callback URL (typically {base_url}/auth/callback) |
auth.oidc.scopes |
[]string | ["openid", "profile", "email"] |
— | OAuth2 scopes to request |
auth.oidc.admin_role |
string | — | — | Keycloak realm role that grants admin access |
auth.oidc.editor_role |
string | — | — | Keycloak realm role that grants editor access |
auth.oidc.default_role |
string | "viewer" |
— | Fallback role when no role claim matches |
Roles are extracted from the Keycloak realm_access.roles claim. If the user has the admin_role, they get admin. Otherwise if they have editor_role, they get editor. Otherwise default_role applies.
auth:
oidc:
enabled: true
issuer_url: "https://keycloak.example.com/realms/silo"
client_id: "silo"
client_secret: "" # use SILO_OIDC_CLIENT_SECRET env var
redirect_url: "https://silo.example.com/auth/callback"
admin_role: "silo-admin"
editor_role: "silo-editor"
default_role: "viewer"
CORS
| Key | Type | Default | Description |
|---|---|---|---|
auth.cors.allowed_origins |
[]string | — | Origins allowed for cross-origin requests from browser-based clients |
FreeCAD and other non-browser clients use direct HTTP and are not affected by CORS. This setting is for browser-based tools running on different origins.
auth:
cors:
allowed_origins:
- "https://silo.example.com"
Environment Variables
All environment variable overrides. These take precedence over values in config.yaml.
| Variable | Config Key | Description |
|---|---|---|
SILO_DB_HOST |
database.host |
PostgreSQL host |
SILO_DB_NAME |
database.name |
PostgreSQL database name |
SILO_DB_USER |
database.user |
PostgreSQL user |
SILO_DB_PASSWORD |
database.password |
PostgreSQL password |
SILO_SESSION_SECRET |
auth.session_secret |
Session cookie signing secret |
SILO_ADMIN_USERNAME |
auth.local.default_admin_username |
Default admin username |
SILO_ADMIN_PASSWORD |
auth.local.default_admin_password |
Default admin password |
SILO_LDAP_BIND_PASSWORD |
auth.ldap.bind_password |
LDAP service account password |
SILO_OIDC_CLIENT_SECRET |
auth.oidc.client_secret |
OIDC client secret |
SILO_SOLVER_DEFAULT |
solver.default_solver |
Default solver backend name |
Additionally, YAML values can reference environment variables directly using ${VAR_NAME} syntax, which is expanded at load time via os.ExpandEnv().
Deployment Examples
Development (no auth)
server:
host: "0.0.0.0"
port: 8080
base_url: "http://localhost:8080"
database:
host: "localhost"
port: 5432
name: "silo"
user: "silo"
password: "silodev"
sslmode: "disable"
storage:
backend: "filesystem"
filesystem:
root_dir: "./data"
schemas:
directory: "./schemas"
default: "kindred-rd"
auth:
enabled: false
Local Auth Only
auth:
enabled: true
session_secret: "change-me-to-a-random-string"
local:
enabled: true
default_admin_username: "admin"
default_admin_password: "change-me"
LDAP / FreeIPA
auth:
enabled: true
session_secret: "${SILO_SESSION_SECRET}"
local:
enabled: false
ldap:
enabled: true
url: "ldaps://ipa.example.com"
base_dn: "dc=example,dc=com"
user_search_dn: "cn=users,cn=accounts,dc=example,dc=com"
role_mapping:
admin:
- "cn=silo-admins,cn=groups,cn=accounts,dc=example,dc=com"
editor:
- "cn=engineers,cn=groups,cn=accounts,dc=example,dc=com"
viewer:
- "cn=silo-viewers,cn=groups,cn=accounts,dc=example,dc=com"
OIDC / Keycloak
auth:
enabled: true
session_secret: "${SILO_SESSION_SECRET}"
local:
enabled: false
oidc:
enabled: true
issuer_url: "https://keycloak.example.com/realms/silo"
client_id: "silo"
client_secret: "${SILO_OIDC_CLIENT_SECRET}"
redirect_url: "https://silo.example.com/auth/callback"
admin_role: "silo-admin"
editor_role: "silo-editor"
default_role: "viewer"