Skip to content

Customization

Config files

smelt loads Lua from a fixed sequence of files. Each one is optional; if it doesn't exist, smelt moves on.

Order File or phase What it is for
1 Config directory early.lua Runs before argv is parsed. Restricted API: smelt.cli, smelt.builtins, smelt.provider, and smelt.phase. See Early-phase config.
2 .smelt/early.lua Project-scoped early phase. Same restrictions; requires trust.
3 Bundled autoload modules Built-in modes, commands, tools, and plugins that were not disabled in early.lua.
4 Config directory init.lua Main config: providers, settings, permissions, MCP/LSP, keymaps, commands, and tools.
5 Config directory plugins/*.lua Global user plugins, loaded in filename order after init.lua.
6 .smelt/init.lua Project-local override. Requires trust.
7 .smelt/plugins/*.lua Project-local plugins. Requires trust.

The config directory is ~/.config/smelt on Linux and macOS and %APPDATA%\smelt on Windows. $XDG_CONFIG_HOME overrides its root on every platform. Override the init.lua path with --config <path>. If no config exists on first launch, the setup wizard creates one for you.

Project-local files (.smelt/*) are content-hash gated. Review them, then run /trust from the project to record the current SHA-256 hash. Any edit invalidates trust until you review and run /trust again. Use them for repo-specific keymaps, slash commands, permission rules, or MCP servers without polluting your global config. Project-local config is especially useful on teams: after reviewing and trusting it, a new clone carries the project's conventions and tooling.

The Getting Started guide covers basic provider setup. See the Configuration Reference for every provider/setting field, and the Plugin Authoring guide for writing larger extensions against the smelt Lua API.

Settings and startup defaults

Set preferences in init.lua by assigning to smelt.settings:

smelt.settings.vim = true
smelt.settings.auto_compact = true
smelt.settings.redact_secrets = false
smelt.settings.file_icons = true

Use --set key=value when you only want a one-off override for a single launch. See the Configuration Reference for every key and default.

Model, mode, and reasoning effort have two layers: a cold-start default and the last value you picked in the TUI. Pin the cold-start defaults with smelt.defaults.set, and opt out of last-used recall with smelt.remember.set when you want a value to reset on every launch:

smelt.defaults.set({
  model = "openai/gpt-5.5",
  mode = "plan",
  reasoning_effort = "high",
})

smelt.remember.set({
  mode = false,
  reasoning_effort = false,
})

Providers and helper models

Register providers in init.lua so you can run smelt without long CLI flags:

smelt.provider.register("ollama", {
  type = "openai-compatible",
  api_base = "http://localhost:11434/v1",
  models = { "qwen3.6:27b" },
})

smelt.provider.register("openai", {
  type = "openai",
  api_base = "https://api.openai.com/v1",
  api_key_env = "OPENAI_API_KEY",
  models = { "gpt-5.5" },
})

Use the provider's base URL for api_base, not a full request path such as /chat/completions, /responses, or /messages.

Background features such as title generation, compaction, prediction, /btw, and web_fetch can use cheaper helper models while your main session uses a larger model:

smelt.model.preferred("title", "openai/gpt-5-mini")
smelt.model.preferred("compact", "anthropic/claude-haiku-4-5")
smelt.model.preferred("predict", "openai/gpt-5-mini")

The model must be registered under a provider. References use the same provider/model or unambiguous bare-model resolution as /model.

Themes

Use /color <preset> for a session-local slug color. For persistent theme changes, put Lua in init.lua.

Tweak one highlight group after the TUI is ready:

smelt.lifecycle.on_ready(function()
  smelt.theme.set("SmeltAccent", { fg = { ansi = 208 }, bold = true })
  smelt.theme.set("Comment", { fg = { ansi = 244 } })
end)

Or create a colorscheme module at ~/.config/smelt/lua/smelt/colorschemes/mytheme.lua and load it:

-- ~/.config/smelt/lua/smelt/colorschemes/mytheme.lua
return {
  name = "mytheme",
  groups = {
    SmeltAccent  = { fg = { ansi = 208 } },
    SmeltProcess = { fg = { ansi = 117 } },
    SmeltUserBg  = { bg = { dark = { ansi = 236 }, light = { ansi = 254 } } },
    Comment      = { fg = { ansi = 244 } },
  },
}
-- ~/.config/smelt/init.lua
smelt.lifecycle.on_ready(function()
  smelt.theme.use("mytheme")
end)

Color values support { ansi = N }, { rgb = { R, G, B } }, or a { dark = ..., light = ... } pair. The built-in reference is runtime/lua/smelt/colorschemes/default.lua; the canonical group manifest with style roles and descriptions is runtime/lua/smelt/colorschemes/_groups.lua.

Keymaps

Bind chords with smelt.keymap.set(mode, chord, handler). Modes are "n"|"i"|"v"|"" (or the long forms normal/insert/visual); "" binds in every mode.

smelt.keymap.set("n", "<C-s>", function()
  smelt.cmd.run("fork")
  smelt.notify.info("session forked")
end)

Built-in chords are listed in the Keybindings Reference. Deeper UI integration belongs in the Plugin Authoring guide.

Custom Commands

Markdown commands

Drop a .md file in ~/.config/smelt/commands/ and it becomes a slash command. Markdown commands are ideal for prompts you want to version-control or share with a team: anyone can edit the text and frontmatter without writing Lua. For example, ~/.config/smelt/commands/commit.md:

---
description: commit staged changes
model: openai/gpt-4o
temperature: 0.2
reasoning_effort: low
bash:
  allow: ["git *"]
---

Create a conventional commit for the staged changes.

Staged diff:

!`git diff --cached`

Recent commits for style reference:

!`git log --oneline -5`

Type /commit and the agent receives the evaluated prompt with shell outputs inlined. Arguments are appended: /commit fix typos.

To also expose a command as reusable agent context, see the smelt.skills reference.

See Custom Commands for all frontmatter fields and template syntax.

Lua commands

Register from init.lua with smelt.cmd.register:

smelt.cmd.register("hello", function(arg)
  local name = (arg and arg ~= "") and arg or "world"
  smelt.notify.info("hello, " .. name .. "!")
end, { desc = "say hi" })

Permissions

For common workflows, add a few narrow allow rules instead of switching to Yolo mode everywhere:

smelt.permissions.extend({
  default = {
    patterns = {
      bash = { allow = { "git status *", "git diff *", "git log *" } },
    },
  },
  apply = {
    patterns = {
      bash = { allow = { "cargo test *", "cargo clippy *" } },
    },
  },
})

Saved approvals from confirmation dialogs are workspace-scoped and managed with /permissions. See the Permissions Reference for the default matrix and rule grammar.

Skills

Skills are on-demand knowledge packs the agent can load during a conversation. They keep the system prompt lean: only the skills relevant to the current task are injected, so the agent stays focused and you save context tokens. Place a SKILL.md file in ~/.config/smelt/skills/<name>/ (global) or .smelt/skills/<name>/ (project-local). See the Configuration Reference for the full format.

External Tools (MCP)

Connect external tool servers via the Model Context Protocol. Servers run as child processes and their tools become available to the agent. MCP lets you extend smelt without writing Lua: if a server exists for Postgres, Slack, or your internal API, the agent can use it immediately. Register them in init.lua with smelt.mcp.register; see the Configuration Reference for setup.

Inspect connected servers at runtime with smelt.mcp.list(), smelt.mcp.tools(server?), and smelt.mcp.status(name). Useful for statusline indicators and conditional keymaps.

Early-phase config

early.lua runs before the binary parses argv, so it's the only place where you can declare new CLI flags or opt out of bundled modules. Use it when you need to change smelt's behaviour from the command line, for example, adding a --ci flag that switches to headless mode and disables interactive dialogs, or to prevent unwanted built-in tools from ever loading. The rest of init.lua runs as normal afterwards.

-- ~/.config/smelt/early.lua
smelt.cli.register_flag({ name = "experimental", kind = "boolean" })
smelt.builtins.disable({ tools = { "web_fetch" } })
-- ~/.config/smelt/init.lua
if smelt.cli.get("experimental") then
  -- ...
end

smelt.cli, smelt.builtins, smelt.provider, and smelt.phase are available here; most UI and runtime APIs are not. See smelt.cli and smelt.builtins for the common early-phase surfaces.

Custom Instructions (AGENTS.md)

Place an AGENTS.md file in your project root (or ~/.config/smelt/AGENTS.md for global instructions). Its contents are automatically appended to the system prompt for every conversation in that directory.

Use it for project conventions, coding standards, or any persistent context the agent should know. Keeping this in a file means the rules travel with the repo: a new teammate clones the project and the agent already knows the naming conventions, test patterns, and architectural constraints. Disable with --no-system-prompt.