Synapse reads configuration in cascading layers. Later layers override earlier ones:
- Compiled-in defaults (zero config).
- System config:
/etc/synapse/config.toml(POSIX only; skipped on Windows). - Global user config: see Paths below for the OS-specific location.
- Workspace config:
<workspace>/.synapse/config.toml. - Runtime overrides: CLI flags and environment variables.
Missing files at any layer are not errors: they just contribute nothing.
Config schema
# ~/.config/synapse/config.toml (or wherever your OS puts it)
# IETF language tag. Omit to follow the system locale.
lang = "pt-BR"
# Default --format when not overridden. text | json
format = "text"
# Workspace freshness advisory (SYN-93, ADR-011).
[freshness]
enabled = true # global kill-switch
interval_minutes = 30 # minimum gap between two checks on the same workspace
silent_cli = false # suppress the stderr line; MCP enrichment is independent
# Write-proposal auto-apply policy (SYN-218, ADR-022). Evolves BR-12.3
# from an absolute gate into a confidence tier.
[proposals]
# "manual" (default): every MCP proposal queues for `syn pending accept`
# (the pure propose/accept invariant).
# "safe" : auto-apply only the low-risk, reversible tier
# (today: link_entity between two entities that already
# exist and are not the `self` person); everything else
# still queues. Auto-applied writes are stamped and
# recorded on the audit trail as `auto-accepted`.
auto_apply = "manual"
# Semantic layer (v0.5 / BR-13): embedding + NER pipeline that runs
# inside Workspace::tx on every write. Active in the default build
# (the semantic layer ships by default, SYN-168); on a minimal core
# build (`--no-default-features --features mcp`) the block is still
# parsed but ignored, so the same config travels across builds.
[enrichment]
mode = "heuristic+ner" # "heuristic" (no NER) | "heuristic+ner" | "off"
embedding_model = "bge-m3" # fp32 ~2.2 GB (default); "bge-m3-int8" (~560 MB, same 1024-dim space, small recall cost); "bge-small-en-v1.5-q" (~65 MB, English only)
ner_model = "gliner-multi" # ~350 MB cached, multilingual (default); or "gliner-base-en" (~260 MB, English only)
ner_threshold = 0.85 # spans below this confidence are dropped
# model_cache_dir = "/custom/path" # override the platform default (see below)
# Opt-in network embedding provider (SYN-165): default is local
# fastembed (content never leaves the laptop). "openai"/"voyage" send
# each entity's text to a third party per write; warned at `syn init`.
# Requires a build with `--features network_backends`. See IDENTITY.md.
# provider = "openai" # or "voyage"; default is local fastembed
# [enrichment.openai]
# model = "text-embedding-3-small" # key via OPENAI_API_KEY env var (preferred) or api_key here
# base_url = "https://api.openai.com/v1" # override for a proxy / Azure gateway
# [enrichment.voyage]
# model = "voyage-3" # key via VOYAGE_API_KEY env var or api_key here
The whole [enrichment] block takes effect on any build that includes the semantic layer, which is the default build (cargo build --release, SYN-168). A minimal core build (--no-default-features --features mcp) parses and ignores the block, so one config file travels across builds. The local models are not bundled and download only on consent (the syn init onboarding prompt or syn embed --all): see INSTALL.md → Feature flags for the footprint (~2.5 GB for the multilingual defaults, ~325 MB for the English opt-downs).
Only fields actually consumed by code live in the schema. Extra fields are preserved on read but ignored: handy for staging future settings.
Paths
| Layer | macOS | Linux | Windows |
|---|---|---|---|
| Global config | ~/Library/Application Support/synapse/config.toml | ${XDG_CONFIG_HOME:-~/.config}/synapse/config.toml | %APPDATA%\synapse\config.toml |
| System config | /etc/synapse/config.toml | /etc/synapse/config.toml | n/a |
| Workspace config | <workspace>/.synapse/config.toml | same | same |
| Model cache (v0.5) | ~/Library/Caches/synapse/models/ | ${XDG_CACHE_HOME:-~/.cache}/synapse/models/ | %LOCALAPPDATA%\synapse\models\ |
Paths are resolved by the etcetera crate (ADR-001 + SYN-30).
The model cache directory may be overridden, in precedence order, by [enrichment] model_cache_dir = "…" in any config layer or by the SYNAPSE_MODEL_CACHE environment variable. First-run model downloads (~2.2 GB BGE-M3 + ~350 MB GLiNER-multi v2.1 quantised by default: about 2.5 GB total) land here and are reused across workspaces; sharing the cache between repos is intentional. The English opt-down models are far smaller (~65 MB BGE-small + ~260 MB GLiNER-base ≈ 325 MB).
For the full story on the models: source repos, when/how they download, offline & air-gapped provisioning, what touches the network, privacy posture, licenses, and platform compatibility (incl. the Linux glibc ≥2.38 requirement): see MODELS.md.
Environment overrides
| Variable | Effect |
|---|---|
SYNAPSE_LANG | Locale override (en, pt-BR). Same as --lang. |
SYNAPSE_NO_FRESHNESS | Any non-empty value suppresses the freshness advisory for this invocation. |
SYNAPSE_MODEL_CACHE | Override the model cache directory (see Paths). |
SYNAPSE_ENRICHMENT_MODE | Override [enrichment] mode for a single invocation (off / heuristic / heuristic+ner). Handy for a one-off fast write that skips the BR-13 insertion-time pipeline without editing the workspace config, e.g. SYNAPSE_ENRICHMENT_MODE=off syn project add …. |
Bootstrapping the global config + identity (v0.6)
syn setup # guided in a TTY: locale, format, then your self-profile
syn setup --force # overwrite existing config + re-capture identity
As of v0.6 syn setup is guided and compulsory (BR-14.1): on a fresh
interactive machine syn init runs it inline before proceeding, and it
captures a global self-profile: name, birthdate, profession, employers:
into a profile.toml kept separate from config.toml (tool behaviour
cascades; identity does not). That profile seeds the self: true person into
every workspace on syn init (ADR-020). Override the profile path with
SYNAPSE_PROFILE.
Non-TTY (CI, piped install, --no-input, SYNAPSE_AGENT) falls back to
compiled defaults silently and skips identity capture: syn setup/syn init
never block a build.
Locale precedence (BR-10.1)
--lang <CODE> > SYNAPSE_LANG=<CODE> > sys-locale > en (fallback)
Examples:
syn --lang en project add "Projeto Alfa" # one-off override
SYNAPSE_LANG=pt-BR syn info # shell-level override
unset SYNAPSE_LANG && syn info # fall back to system
Locale strings follow IETF BCP-47 (en, pt-BR, es-MX, …). Unknown locales silently fall back to en (every key is guaranteed in en per BR-10.2).
Environment variables
| Variable | Purpose |
|---|---|
SYNAPSE_LANG | Locale override (see precedence above). |
SYNAPSE_PLAIN | Force raw, unstyled output (same as --plain/--raw). |
SYNAPSE_NO_COLOR / NO_COLOR | Drop ANSI colour, keep structure (TERM=dumb too). |
SYNAPSE_AGENT | Mark the caller as an AI agent: implies --plain and --no-input. |
SYNAPSE_PROFILE | Path to the global self-identity profile.toml (overrides the default location). |
SYNAPSE_MODEL_CACHE | Override the model cache directory (see Paths). |
SYNAPSE_ENRICHMENT_MODE | Override [enrichment] mode for one invocation (off / heuristic / heuristic+ner). |
SYNAPSE_NO_FRESHNESS | When set (any value), suppresses the freshness advisory for this invocation (same as --no-freshness). CI-friendly. |
RUST_LOG | Standard tracing-compatible log filter (e.g. RUST_LOG=synapse=debug). |
INSTALL_DIR | Used by the install.sh installer only; ignored by the binary. |
Output & styling (v0.6, ADR-019/021)
Output is rich by default on a TTY: colour, ✓/▲ glyphs, unicode tables,
entity panels, the graph tree, progress spinners/bars, and the
graph-constellation mascot. It degrades to plain bytes on a pipe and is
controlled by: --plain/--raw (or SYNAPSE_PLAIN) for fully raw output;
--no-color/NO_COLOR/TERM=dumb to drop colour but keep structure;
--quiet/-q to suppress non-essential lines; --no-input/--yes to never
prompt. --format json is always machine-clean and unstyled.
Workspace freshness (SYN-93)
The [freshness] block governs the advisory described in detail in ADR-011. Three knobs and a per-workspace override:
| Knob | Where | Default | Effect |
|---|---|---|---|
freshness.enabled | global / system / workspace config | true | Master kill-switch. false means no check ever fires and the advisory is silent. |
freshness.interval_minutes | same | 30 | Minimum minutes between two checks on the same workspace. Two parallel commands seeing a stale stamp may both fire; the race is benign. |
freshness.silent_cli | same | false | When true, the CLI stderr line is suppressed even when a workspace is behind/diverged. The MCP enrichment is independent. |
freshness_disabled | per-workspace, in the registry | 0 | Toggle with syn ws freshness on|off <name>. Set to opt this workspace out without disabling the feature globally. |
SYNAPSE_NO_FRESHNESS | env var | unset | Per-invocation kill (cascades over every config). |
--no-freshness | CLI flag (global) | absent | Same effect as the env var, but only on the current command. |
Future settings (not in v0.1)
The cascade is intentionally minimal today. Coming up:
| Setting | Purpose | Ticket |
|---|---|---|
editor | $EDITOR override for syn open | SYN-70 (v0.2) |
mcp.transport | Pick stdio / HTTP for the MCP server | SYN-207 (backlog) |
watcher.debounce_ms | syn watch debounce | SYN-65 (v0.2) |
Embedding/NER backend selection shipped in v0.5 as the
[enrichment]block above, not a future setting.
Add them via a versioned migration (the same pattern the index uses); never by silent format change.