pub struct Settings {Show 28 fields
pub default_download_path: Option<String>,
pub default_context_size: Option<u64>,
pub proxy_port: Option<u16>,
pub llama_base_port: Option<u16>,
pub max_download_queue_size: Option<u32>,
pub show_memory_fit_indicators: Option<bool>,
pub max_tool_iterations: Option<u32>,
pub max_stagnation_steps: Option<u32>,
pub default_model_id: Option<i64>,
pub inference_defaults: Option<InferenceConfig>,
pub inference_profiles: Option<Vec<InferenceProfile>>,
pub setup_completed: Option<bool>,
pub title_generation_prompt: Option<String>,
pub bind_host: Option<String>,
pub share_lan: Option<bool>,
pub proxy_api_key: Option<String>,
pub trust_client_sampling: Option<bool>,
pub loop_guard_mode: Option<LoopGuardMode>,
pub proxy_loop_detection: Option<bool>,
pub tool_call_repair: Option<bool>,
pub agentic_sampling: Option<bool>,
pub proxy_autostart: Option<bool>,
pub close_to_tray: Option<bool>,
pub start_at_login: Option<bool>,
pub remote_pairing: Option<RemotePairing>,
pub remote_enabled: Option<bool>,
pub remote_serve: Option<RemoteServe>,
pub remote_devices: Option<Vec<Device>>,
}Expand description
Application settings structure.
All fields are optional to support partial updates and graceful defaults.
Fields§
§default_download_path: Option<String>Default directory for downloading models.
default_context_size: Option<u64>Default context size for models (e.g., 8192, 32768).
None means the user has chosen nothing, and is the ordinary state —
it is what lets the daemon size each launch rather than pinning it.
A value here is read as a number the user typed and outranks that, so
nothing writes one on their behalf and settings unset returns it. See
crate::server_config::resolve_context_size_with_source for the chain
and Self::with_defaults for why this field is the one left unset.
proxy_port: Option<u16>Port for the OpenAI-compatible proxy server.
llama_base_port: Option<u16>Base port for llama-server instance allocation (first port in range).
Note: The OpenAI-compatible proxy listens on proxy_port.
max_download_queue_size: Option<u32>Maximum number of downloads that can be queued (1-50).
show_memory_fit_indicators: Option<bool>Whether to show memory fit indicators in HuggingFace browser.
max_tool_iterations: Option<u32>Maximum iterations for tool calling agentic loop.
max_stagnation_steps: Option<u32>Maximum stagnation steps before stopping agent loop.
default_model_id: Option<i64>Default model ID for commands that support a default model.
inference_defaults: Option<InferenceConfig>Global inference parameter defaults.
Applied when neither request nor per-model defaults are specified. If not set, hardcoded defaults are used as final fallback.
inference_profiles: Option<Vec<InferenceProfile>>Named sampling profiles, selectable per request as {model}:{profile}.
Global rather than per-model: one coding profile applies to every
model, and its sparse fields fall through to that model’s own
inference_defaults for anything it does not set. See
crate::domain::inference_profile.
setup_completed: Option<bool>Whether the first-run setup wizard has been completed.
title_generation_prompt: Option<String>Custom prompt template for generating chat titles.
bind_host: Option<String>Override the bind host for gglib web.
None → use the compiled-in default (127.0.0.1). The --host flag
takes precedence for a single run without changing this value.
Whether gglib web binds all LAN interfaces and broadcasts over mDNS.
None/Some(false) → localhost-only. The --share-lan flag can turn
this on for a single run, but cannot turn it off — clear it here.
proxy_api_key: Option<String>Bearer token required on the proxy’s /v1/* and /mcp routes.
None leaves the endpoint unauthenticated, which is the historical
behaviour and remains the default for a loopback bind. The proxy mints
one here automatically the first time it binds a non-loopback host, so
an endpoint that reaches a network is never left open by omission.
--api-key and GGLIB_API_KEY override this for a single run without
changing it. The desktop app reads it from here — that is how the GUI
dashboard authenticates against the proxy it started.
trust_client_sampling: Option<bool>Whether a client’s own sampling parameters (temperature, top_p,
top_k, presence_penalty, repeat_penalty, min_p) are honoured
by the proxy at all.
None/Some(false) → the client’s sampling opinions are dropped from
the resolution hierarchy entirely; the request falls straight through
to the profile / per-model / global / floor layers as if the client
had sent none of them.
The carve-out is a category, not one exception: the client’s own
budgets are unaffected either way, because a budget says what the
request is rather than how it should sample. max_tokens was the
only member for a long time — ignoring it would silently truncate that
client’s own turns — and reasoning_budget_tokens joined it, capping
what this turn may spend thinking within a range llama.cpp itself
enforces. The list is
CLIENT_AUTHORITATIVE_KEYS,
which carries the rule for what may join it; this doc names members
rather than owning them.
Defaults to distrust because most clients that talk to this proxy
send fixed sampling values with no user-facing control behind them —
boilerplate the client always sends, not a deliberate choice by
whoever is using it (VS Code Copilot’s LLM Gateway hardcodes
temperature: 0 on every request, for one). Letting that boilerplate
silently outrank a model’s own tuned defaults and this server’s
global settings defeats the point of configuring either. Set true
for a client that does expose real sampling controls to its user
(OpenWebUI’s sliders, for instance).
loop_guard_mode: Option<LoopGuardMode>What the proxy’s turn-level loop/stagnation guard does on
/v1/chat/completions when a replayed history trips it.
A conversation that repeats the same tool-call batch back to back and
gets the same answer back each time, or repeats the same assistant
response anywhere in the session, beyond the shared agent-path
thresholds, is answered per LoopGuardMode: note (absent, and the
default) forwards it with a note saying what repeated, refuse rejects
it with a clean HTTP 400 before admission, and off does not scan.
Replaying identical batches across a history does not trip it — the
batch count is back to back — and a repeat whose answer changed is not
counted at all.
Note the polarity: absent means the guard is on, because it is
protection the endpoint should not silently lose, unlike
Self::trust_client_sampling, which is authority a client must be
explicitly granted.
The stagnation threshold itself comes from
Self::max_stagnation_steps, shared with the built-in agent loop so
the two paths cannot drift.
Read through Self::effective_loop_guard_mode, never directly: the
deprecated Self::proxy_loop_detection still answers for a settings
file written by an older build.
proxy_loop_detection: Option<bool>Deprecated, for one release: the boolean Self::loop_guard_mode
replaces.
Some(false) still means LoopGuardMode::Off. Some(true) means
the guard is on, which is now LoopGuardMode::Note rather than a
refusal — a deliberate behaviour change for anyone who asked for the
guard by name, and the point of #1052.
The two never disagree on disk: Self::merge clears each when the
other is written to a value — clearing one leaves the other alone,
since an explicit null means “forget this field”, not “forget both” —
so precedence is only ever consulted for a settings file an older build
wrote. gglib config settings set --proxy-loop-detection false therefore keeps working for the release
it is promised, for anyone who scripted it while the guard’s own 400
bodies still named it.
tool_call_repair: Option<bool>Whether a tool call that fails schema validation is re-issued, with
tool_choice: "required" or as a second draw under gglib’s grammar.
None (the default) means on, the same inverse polarity as
Self::proxy_loop_detection and for the same reason: it is
protection the endpoint should not lose silently. Some(false)
forwards every call as emitted.
Worth turning off only for a client that depends on receiving the
model’s literal output — the repair costs one extra generation on a
failed call, and nothing on a conformant one. The
GGLIB_DISABLE_TOOL_REPAIR environment switch reaches the same gate
without persisting a setting.
See Tool-call repair.
agentic_sampling: Option<bool>Whether a request carrying tools gets the agentic-turn temperature
ceiling — see
InferenceConfig::agentic_temperature_ceiling.
None/Some(true) → active (the default): a turn that may emit
structured output has its temperature capped, but only over a value
nobody deliberately chose — an auto-detected recipe or the floor —
and only on a model class that still has a ceiling. Since the
2026-08-10 measurement (see agentic_temperature_ceiling) reasoning
models have none, so on them this setting currently gates nothing.
Anything set by a person stands. Some(false) disables the cap.
Same polarity as Self::proxy_loop_detection, and for the same
reason: this is a correction the endpoint should not silently lose.
The tool_call_floor alias is the name this shipped under briefly in
#741, before verification showed the adjustment fires on every agentic
turn rather than only on tool emission. Kept so a config written in
that window still loads.
proxy_autostart: Option<bool>Whether the desktop app starts the OpenAI-compatible proxy as soon as it launches, rather than waiting for the user to switch it on.
This is what makes the proxy a background service rather than a
feature you remember to enable: combined with Self::start_at_login
and Self::close_to_tray, the endpoint is simply always there for
clients like VS Code Copilot, with no terminal held open.
Read by the desktop app only. gglib proxy and gglib serve are
explicit foreground commands — starting a second proxy underneath them
would contend for the same port.
close_to_tray: Option<bool>Whether closing the desktop app’s window hides it to the system tray instead of quitting.
None/Some(false) → closing the window shuts the app down, stopping
the proxy and any running llama-server with it (the historical
behaviour). Some(true) → the window hides and the app keeps serving;
quitting is then an explicit action from the tray menu.
start_at_login: Option<bool>Whether the desktop app registers itself to launch on login.
Backed by the OS autostart mechanism for each platform (macOS login
item, Windows Run key, XDG autostart entry on Linux). Toggling this
registers or unregisters immediately rather than at next launch, so the
stored value and the OS state cannot drift apart.
remote_pairing: Option<RemotePairing>The machine this one paired with, and the key it issued — see
RemotePairing for why those are one value and not two.
Received, not chosen: gglib remote join redeems the far
machine’s one-time code through the tunnel and stores what comes back
here, so later sessions need only the ticket — or nothing, since the
ticket is part of the record. gglib q --remote and
gglib chat --remote attach the key as the bearer. Nothing writes it
by hand, and gglib config settings show reports the key as held or
not rather than printing it, because re-pairing replaces it and
nothing needs to read it back.
A database written before the halves were bound holds
remote_api_key and remote_last_ticket as separate rows, and both
are ignored — no alias, deliberately. Neither is evidence about the
other, and reading the one as belonging to the other is exactly the
defect this field closes; such a machine loads as never paired and
pairs again, which a stale ticket already required of it.
remote_enabled: Option<bool>Reachable across restarts, and how — see RemoteServe.
remote_serve: Option<RemoteServe>See RemoteServe.
remote_devices: Option<Vec<Device>>The roster of paired devices, keys excluded — see Device.
Implementations§
Source§impl Settings
impl Settings
Sourcepub(super) fn merge_remote(&mut self, other: &SettingsUpdate)
pub(super) fn merge_remote(&mut self, other: &SettingsUpdate)
Apply the remote half of other: every remote field, and only those.
Source§impl Settings
impl Settings
Sourcepub const fn with_defaults() -> Self
pub const fn with_defaults() -> Self
Create settings with sensible defaults.
Sourcepub const fn effective_proxy_port(&self) -> u16
pub const fn effective_proxy_port(&self) -> u16
Get the effective proxy port (with default fallback).
Sourcepub const fn effective_llama_base_port(&self) -> u16
pub const fn effective_llama_base_port(&self) -> u16
Get the effective llama-server base port (with default fallback).
Sourcepub const fn effective_loop_guard_mode(&self) -> LoopGuardMode
pub const fn effective_loop_guard_mode(&self) -> LoopGuardMode
What the loop guard does, reconciling Self::loop_guard_mode with
the deprecated Self::proxy_loop_detection.
The new setting wins outright when present. The boolean is consulted
only when it is absent, which Self::merge makes true of anything
this build has written to a value — an explicit clear of one spelling
leaves the other standing, so both can be absent and the default
answers: Some(false) is LoopGuardMode::Off, and
Some(true) or absent is the default, LoopGuardMode::Note. An
explicit old “on” therefore becomes a note rather than a refusal,
which is the behaviour change #1052 exists to make.
The one place this precedence is decided, so the proxy, the CLI and anything that reports the setting cannot disagree about it.
Sourcepub fn merge(&mut self, other: &SettingsUpdate)
pub fn merge(&mut self, other: &SettingsUpdate)
Merge another settings into this one, only updating fields that are Some.