Clone
1
Configuration
Jaroslav Beneš edited this page 2026-10-09 22:40:23 +00:00

Configuration — for developers

Every key and what it does is documented for users at https://llembas.eu/docs/cli-configuration.html. This page is about the machinery: where configuration comes from, in what order, what a project may and may not set, and what to touch when adding a key.

The files

File Scope Notes
~/.config/lembas/connections.yaml global only Endpoints, dialects, models, keys. Written chmod 600. A project can never define or override a connection.
~/.config/lembas/config.yaml global Everything else.
<project>/.agent/config.yaml project Read only once the directory is trusted. .lembas/ is used instead when .agent/ already belongs to another tool (project/root.ts).
~/.config/lembas/{agents,commands,skills,memory}/ global Subagents, custom commands, skills, memory. The project's .agent/agents, .agent/commands and .agent/skills count only when trusted.
~/.local/share/lembas/ data sessions.db, the library, snapshots, worktrees, mcp-auth.json.
~/.local/state/lembas/ state learned.json, prompt history, the hub socket, the service's status.

All three roots follow XDG; LEMBAS_HOME roots all three at once, which is what the tests and the smoke test use (config/paths.ts).

Loading (src/config/load.ts)

  1. Read the YAML, then translate legacy keys and former names (a mode such as unrestricted, a renamed permission key) with a note for the user.
  2. Drop a project's global-only keys before validation, so their shape cannot break the file: GLOBAL_ONLY = hardline_extra, hardline_disable, voice, update, settings_tool, embedding, remote, library, instructions, personality_custom. Each one dropped is a warning. A repository must not be able to weaken the floor, redirect speech or updates, or write words into the system prompt in the user's voice.
  3. Validate with zod, then substitute. {env:NAME} and {file:path} are filled after validation (config/substitute.ts); a missing variable or file is an error, never an empty string. A URL field accepts a placeholder and is checked again after substitution. mcp, voice, search and update are filled one entry at a time, so one broken server or service turns off that one thing, not the whole file. A connection whose substitution fails lands in broken with the reason.
  4. Merge: objects key by key, everything else replaced, project over global. Permission rules stack instead (global first, then project), and a project's rule cannot loosen a global one.
  5. webui connections are expanded (lembas/webui.ts): one entry naming a LLeMbas instance becomes the OpenAI-chat connection it is spoken to as, with the account's models from /v1/models — refreshed at every start, kept from the last good read when the instance cannot be reached. The account's personalization replaces the local keys while logged in (lembas/personal.ts). Models get refs (provider/refs.ts): an instance's are <provider>/<model>.

Settings while running (src/config/settings.ts, src/settings.ts)

One list, SETTINGS, is read three ways: /settings, lembas config get|set|list, and the agent's settings tool. Each entry has a kind, the scopes it may be set at (session, global, project), whether the agent may change it (with approval; a less strict mode is asked every time), whether it needs /reload, and what it is when unset. A value is resolved from the session, then the project's file, then the global file, then the fallback. Writing uses yaml's parseDocument … setIn, so the user's comments and layout survive.

Not in the list, on purpose: permission rules, the hardline, MCP servers, connections, the update source and key, and settings_tool itself. Those are edited by hand, never by the agent.

JSON Schemas

schema/config.schema.json and schema/connections.schema.json are generated from the zod schemas (config/jsonschema.ts) by bun run schema, and written beside a user's config by lembas config schema, so an editor with a YAML language server completes and checks keys. Regenerate them in the same commit as a schema change; a test compares them.

Adding a key

  1. Add it to the zod schema in config/schema.ts with a .describe() — the description is what the JSON Schema and the editor show.
  2. Decide whether a project may set it. If a cloned repository could use it to weaken a check, redirect traffic or a key, or speak in the user's voice, add it to GLOBAL_ONLY.
  3. If it may be changed while running, add it to SETTINGS with its scopes, and say whether the agent may change it. The default is no.
  4. Write its reader in the same change, with a test that reads the effect — a key the schema accepts and nothing reads is a promise the program does not keep.
  5. bun run schema, and document it on the website's configuration page.