Files
homelab/services/desktop/librechat.nix
T
darmanandClaude Sonnet 5 6f24ab69ad docs: condense comments across the repo
Comments had drifted into multi-paragraph narrative (git commit
lineage, debugging stories, restated code) in several hot spots
(scripts/deploy, hermes-agent.nix, flake.nix, gitea.nix, headscale.nix).
Trim every comment to its load-bearing "why" — gotchas, safety
warnings, and non-obvious rationale survive verbatim in substance,
just tightened to 1-2 sentences; historical narrative and anything
already covered in CLAUDE.md is cut. No code/logic changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJqEmY1y3AYX3JoX4Y6b21
2026-09-18 21:36:30 +02:00

88 lines
4.2 KiB
Nix

{ config, ... }:
# LibreChat — web chat UI, talking to the local ollama server (see
# hosts/terra/configuration.nix) over its OpenAI-compatible /v1 route.
# Only reachable over the tailnet (networking.firewall.trustedInterfaces =
# [ "tailscale0" ] in services/vpn/tailscale.nix) — openFirewall stays off.
{
services.librechat = {
enable = true;
enableLocalDB = true; # spins up a local, unauthenticated-on-localhost mongodb
# LibreChat's isEnabled() treats an unset var as false, not true (despite
# .env.example suggesting true is the default), so this must be explicit.
# Fine to leave open since it's tailnet-only; flip to false once your
# account exists to lock it down.
env.ALLOW_REGISTRATION = true;
credentials = {
CREDS_KEY = config.sops.secrets.librechat_creds_key.path;
CREDS_IV = config.sops.secrets.librechat_creds_iv.path;
JWT_SECRET = config.sops.secrets.librechat_jwt_secret.path;
JWT_REFRESH_SECRET = config.sops.secrets.librechat_jwt_refresh_secret.path;
};
settings = {
version = "1.2.1";
endpoints.custom = [
{
name = "Ollama";
# required field but unchecked by ollama's OpenAI-compat shim
apiKey = "ollama";
baseURL = "http://127.0.0.1:11434/v1";
models = {
# Schema requires >=1 entry even though fetch=true overwrites this at
# runtime with whatever's pulled (hosts/terra/configuration.nix) —
# kept roughly in sync so the UI has sane names before the first fetch.
default = [ "gemma4:12b" "qwen3.6:35b-a3b" "VladimirGav/qwen3.8-27B-14GB-IQ4:latest" ];
fetch = true; # pull the model list from ollama at startup
};
titleConvo = true;
}
];
# Persistent memory is opt-in at the config level — omitting this block
# leaves it off regardless of the user's Settings > Personalization toggle.
# `agent.provider` must match endpoints.custom[].name above exactly.
memory = {
personalize = true; # still needs a per-user opt-in toggle in the UI
# instructions REPLACES the default extraction prompt, not appends to it —
# needed because the smaller llama3.2:3b (since dropped) kept saving its
# own assistant boilerplate as memories, a capability ceiling rather than
# a prompting gap. validKeys whitelists what can be stored.
validKeys = [ "user_preferences" "personal_info" "ongoing_projects" "technical_context" ];
agent = {
enabled = true;
provider = "Ollama";
# same model as the chat endpoint's primary driver — when that's
# the active chat model, extraction needs no second model swapped
# into VRAM alongside it.
model = "gemma4:12b";
instructions = ''
Save memory ONLY using the keys below, and only when the user's
message states something durable and genuinely useful to recall
in a LATER, unrelated conversation. Small talk, greetings, and
anything about what the assistant said or is capable of are NOT
memories — if nothing meets the bar, save nothing.
set_memory REPLACES the entire value stored at a key — it does
NOT append to it. Before calling set_memory for a key, check the
"Existing memory" section below. If that key already has a
value, your new value MUST merge the old and new information
into one complete sentence or short paragraph — calling
set_memory with only the newest fact silently ERASES everything
already stored under that key. Only drop prior details if the
user is explicitly correcting or replacing them.
- user_preferences: explicitly stated preferences (tools, formats, style).
- personal_info: durable facts about the user (name, role, timezone).
- ongoing_projects: projects or tasks the user is actively working on.
- technical_context: durable facts about the user's setup/stack
relevant to future answers (e.g. "runs NixOS", "GPU is AMD ROCm").
'';
};
};
};
};
}