CLI configuration
Everything LLeMbas CLI reads, and where. Settings in ~/.config/lembas/, data in ~/.local/share/lembas/, state in ~/.local/state/lembas/.
The files
| File | What |
|---|---|
connections.yaml | Connections and models. Global only; keep it chmod 600. |
config.yaml | Everything else: defaults, permissions, search, voice, memory, MCP, updates, the remote link. |
AGENTS.md | Instructions for every project. |
commands/, agents/, skills/ | Your own slash commands, subagents and skills. |
memory/USER.md, memory/MEMORY.md | What it knows about you, and its own notes. Edit by hand or with /memory. |
themes/, prompts/ | Your colour themes; replacements for built-in prompts. |
schema/ | JSON Schemas for editors. lembas config schema --link points the files at them. |
.agent/ in a project | That project’s config.yaml, plans, commands, skills, agents, task board and decision log. Read only once the project is trusted. |
{env:NAME} and {file:path} work anywhere a string does, so keys never have to be written into a file.
connections.yaml
connections:
local: # the name used in model: local/<id>
dialect: openai-chat # openai-chat | responses | anthropic | gemini | ollama
base_url: https://llm.example/v1 # including /v1
api_key: "{env:LOCAL_KEY}" # or "{file:~/.secrets/k}", or key_cmd: "pass show llm/local"
tls: { ca: ~/.config/lembas/private-ca.crt } # a private CA; or insecure: true
timeout: 600 # seconds of silence before giving up — not reply length
discover: true # accept models found at /models that are not listed
one_model_at_a_time: false # true: one GPU behind llama-swap — no subagent on another model
models:
coder:
name: Local coder
context: 131072 # absent: learned after the first reply
max_output: 16384
temperature: 0.7
efforts: [low, medium, high] # the model's own vocabulary
effort: medium
vision: false
tools: true
notes: fast; fine for small edits
fallback: [cloud/coder] # when this server cannot be reachedThe five dialects:
| Dialect | Talks to | Auth sent as |
|---|---|---|
openai-chat | {base_url}/chat/completions — llama.cpp, vLLM, LM Studio, OpenRouter, DeepSeek… | bearer |
responses | OpenAI’s Responses API, stateless | bearer |
anthropic | {base_url}/messages | x-api-key |
gemini | Google’s Gemini API (not yet tested against real servers) | x-goog-api-key |
ollama | {base_url}/api/chat, with num_ctx sent (not yet tested against real servers) | bearer |
auth: overrides it: bearer, x-api-key, x-goog-api-key or none.
A LLeMbas server
lembas login https://your-server writes one entry, named after the server, and nothing else:
myserver:
type: webui
url: https://your-server
api_key: "{file:~/.config/lembas/lembas/myserver.key}" # the token, mode 600The models are read from the server at every start, with what its administrator set for each, and kept for a start without the network. They are named provider/model. With the server’s permission, login also points voice and web search at it, keeping what you had as the fallback (--keep-services leaves them alone). lembas logout removes exactly what login added.
config.yaml — the keys
Most keys can be set at three levels — global (~/.config/lembas/config.yaml), project (.agent/config.yaml) and session — and /settings shows each with where its value comes from. Some are global only, so a cloned repository can never change them; some are edited in the file by hand and never by the agent.
| Key | What | Where it can be set |
|---|---|---|
model | connection/model the session starts on | session, global, project |
small_model | for session titles and /commit messages; default: the session’s model | session, global, project |
mode | manual | edit | auto | plan | session, global, project |
effort | the reasoning effort a session starts with | session, global, project |
titles | model (a title from the model) or prompt (the first line) | session, global, project |
personality | concise | pragmatic | optimistic | funny | formal | socratic | custom | session, global, project |
personality_custom | your own words when personality: custom (≤ 1500 characters) | session, global |
instructions | how you want to be helped (≤ 4000 characters) | session, global |
instruction_files | more files for the system prompt, after AGENTS.md | global, project (in the file) |
settings_tool | ask | allow | off — the agent’s own settings tool | global |
limits.steps, limits.bash_timeout | steps per prompt; seconds per command | session, global, project |
limits.wall_seconds, limits.output_bytes, limits.completion_tokens | budgets for one prompt; unset by default | session, global, project |
permission | rules per tool: allow, ask, deny, by pattern | global, project (in the file) |
hardline_extra, hardline_disable | add to, or switch off rules of, the always-refused command list | global (in the file) |
search.order, search.max_results | web search providers in order: webui, searxng, firecrawl, ddg | session, global, project |
search.fetch | local, firecrawl or webui | global, project (in the file) |
compaction.auto_at, compaction.prune | compact past this share of the context window (1 = off); prune old tool output first | session, global, project |
memory.enabled | the memory tool and memory in the prompt | session, global, project |
embedding | connection/model of an embedding model, for knowledge bases | global |
knowledge | which knowledge bases are searched; absent = all | session, global, project |
library | local or lembas (your server’s library) | global |
question.unattended | headless with nobody present: recommended | first | fail | session, global, project |
busy_input | a message sent mid-task: steer (next step) or queue (after the task) | session, global |
theme, theme_background | a built-in theme or a file in themes/; terminal keeps your terminal’s background | session, global |
icons | emoji or plain for fonts without emoji | session, global |
mouse | false: the terminal keeps the mouse | global |
update.channel, update.auto | stable | beta; install | notify | off | global |
update.source, update.public_key, update.verify | where updates come from and how they are checked | global (in the file) |
remote | what a LLeMbas server may do on this machine | global (in the file) |
mcp | MCP servers | global, project (in the file) |
voice | speech to text and text to speech | global (in the file) |
skills.external_dirs, skills.disabled | extra read-only skill directories; skills to hide | global, project (in the file) |
model: local/coder
small_model: local/tiny
mode: manual
effort: high
personality: pragmatic
instructions: |
I know Python well and TypeScript a little.
limits: { steps: 200, bash_timeout: 120 }
permission:
bash: { "npm test *": allow, "npm publish *": deny }
edit: { "*.lock": ask }
search:
order: [searxng, ddg]
searxng: { base_url: https://searx.example }
compaction:
auto_at: 0.85
theme: moria
busy_input: steerChanging settings
/settings in the TUI, or from a shell: lembas config list, get <key>, set <key> <value> [--project]. Files keep their comments when written. You can also just ask — “think harder”, “plan first” — and the agent changes the setting through its settings tool, which you approve like any other call. A less strict mode is asked about every time. Permission rules, the hardline, MCP servers, connections, personality and where updates come from are never the agent’s to change.
Permission rules
Rules map a tool and a pattern to allow, ask or deny. A project’s rules stack after the global ones. A short list of catastrophic commands (rm -rf /, mkfs, force-push to main…) is refused in every mode; hardline_extra adds patterns and hardline_disable switches off a rule by id, globally only.
Personality and instructions
personality: concise # concise | pragmatic | optimistic | funny | formal | socratic | custom
personality_custom: "…" # your own words, when personality is custom
instructions: | # how you want to be helped
Answer briefly. Show the command before running it.Both go last in the system prompt. They are your words, so instructions and personality_custom are global only. Logged in to one LLeMbas server that offers personalization, these are your account’s, shared with the web UI.
Memory, skills and knowledge
memory:
enabled: true
memory_chars: 2200
user_chars: 1375
skills:
external_dirs: [~/shared-skills]
disabled: [some-skill]
embedding: local/nomic-embed # global: an embedding model for knowledge bases
knowledge: [manuals, specs] # the bases searched; absent = allA skill is skills/<name>/SKILL.md with a name and description in its front matter; every skill is also a /command. Knowledge bases are managed with lembas kb or /kb; lembas kb reindex after changing the embedding model.
MCP servers
mcp:
files: # local, over stdio
command: [npx, -y, "@modelcontextprotocol/server-filesystem", "."]
github: # remote
url: https://api.githubcopilot.com/mcp/
headers: { Authorization: "Bearer {env:GITHUB_TOKEN}" }
tools: { exclude: ["delete_*"] }
linear:
url: https://mcp.linear.app/mcp # sign in with /mcp auth linear
permission:
"mcp__github__*": allowTools are named mcp__<server>__<tool> and ask unless a rule allows them. A server’s prompts become /<server>:<prompt> commands.
Voice
voice:
stt:
provider: openai # or whispercpp, or webui (your server)
base_url: https://speech.example/v1
model: whisper-1
language: en
tts:
provider: openai # Kokoro-FastAPI, OpenAI; or piper-http, piper-cli, webui
base_url: https://speech.example/v1
model: kokoro
voice: af_heart
record_key: ctrl+t
record_mode: toggle # hold: letting go also stops
submit: draft # send: straight to the model
speak: false # read every reply aloudGlobal only. /voice shows what is in use; lembas voice check tests it from a shell.
The remote link
remote:
enabled: true
roots: [~/code, /srv/work]
max_mode: edit
approval_timeout: 600
require_trust: true
terminal: false
terminal_integration: trueGlobal only. See Agent chats.
Updates
update:
channel: stable # stable | beta
auto: install # install | notify | off
source: # default: the official GitHub releases
type: gitea # github | gitea (Forgejo too) | static
url: https://git.example.org
repo: you/LLeMbas-CLI
public_key: "ssh-ed25519 AAAA… your-release-key"
verify: signature # checksum: accept an unsigned source of your ownGlobal only — a project never decides what binary runs. A static source is any web directory with the release files in <url>/<tag>/ and the current tags in <url>/stable and <url>/beta.
Custom commands and agents
---
description: review a file for bugs
mode: plan # optional: for this one prompt
---
Review @$1 for bugs. Recent changes:
!`git log -5 --oneline -- $1`Save it as ~/.config/lembas/commands/review.md (or in a project’s .agent/commands/) and run /review src/app.ts. $ARGUMENTS is everything after the name, $1…$9 the words, and !`command` is replaced by its output.
A subagent is the same shape in agents/<name>.md, with optional model, mode and tools. Built in: explore (read-only) and general. /agents lists them.