Config schema
Blak validates its merged config on load. Known option shapes are checked before runtime setup. Plugin-specific options are validated by their plugins. The validation rules live in lua/blak/config/schema.lua.
Top-level keys
Section titled “Top-level keys”All present after merging with the defaults. Keys marked validated are
checked by schema.lua on load; the rest are deep-merged and passed to the
modules that consume them without per-field validation.
| Key | Type | Notes |
|---|---|---|
version |
string |
Blak’s own version string. Informational; do not set it in user.lua |
leader |
string |
Default " ". Validated |
localleader |
string |
Default "\\". Validated |
package |
table |
See below. Validated |
ui |
table |
See below. Validated |
editor |
table |
See below. Validated |
completion |
table |
See below. Validated |
performance |
table |
See below |
picker |
table |
See below. Validated |
explorer |
table |
See below. Validated |
terminal |
table |
See below. Validated |
keymaps |
table |
List of user keymap specs. Validated |
plugins |
table |
Personal lazy.nvim specs. Validated |
hooks |
table |
Lua hooks for pre-validation and post-setup customization. Validated |
ai |
table |
See below. Validated |
mini |
table |
See below. Validated |
snacks |
table |
See below |
treesitter |
table |
See below |
lsp |
table |
See below |
mason |
table |
See below |
format |
table |
See below |
lint |
table |
See below |
extras |
table |
See below. Validated |
package
Section titled “package”| Key | Type | Allowed |
|---|---|---|
backend |
string |
"lazy" |
channel |
string |
"stable", "edge", or "nightly" |
check_updates |
boolean |
— |
Setting an unsupported channel raises:
Blak config validation failed:- package.channel must be stable, edge, or nightly| Key | Type | Allowed |
|---|---|---|
colorscheme |
string |
Any installed colorscheme name |
transparent |
boolean |
true or false |
theme |
table |
Options passed to a colorscheme Lua setup() function when available |
Set ui.transparent = true to clear editor background highlights after the
active colorscheme loads. Use ui.theme for colorscheme-native setup options.
Blak tries the colorscheme name first, then the name before the final dash.
Configure custom themes with unusual setup rules through plugins.specs.
editor
Section titled “editor”| Key | Type | Notes |
|---|---|---|
clipboard |
boolean |
Use the system clipboard when available |
confirm |
boolean |
Prompt before commands abandon unsaved changes |
relative_number |
boolean |
Toggle relative line numbers |
scrolloff |
number |
Context lines above and below the cursor |
sidescrolloff |
number |
Context columns beside the cursor |
tabstop |
number |
Width used to display a tab character |
shiftwidth |
number |
Indent width for operators and new lines |
expandtab |
boolean |
Insert spaces instead of tab characters |
Disable confirm prompts in user.lua:
return { editor = { confirm = false, },}picker
Section titled “picker”| Key | Type | Allowed |
|---|---|---|
provider |
string |
"fff", "snacks", "telescope", or "fzf_lua" |
Switching providers swaps the implementation behind :BlakPick without changing the keymaps. If you want a provider that doesn’t exist yet, add it under lua/blak/providers/picker.lua and submit a PR.
completion
Section titled “completion”| Key | Type | Allowed |
|---|---|---|
super_tab |
boolean |
true or false |
Set completion.super_tab = true to use the completion engine’s SuperTab-style
keymap preset where Blak can delegate to one. The default is false, so stable
updates do not change completion muscle memory.
explorer
Section titled “explorer”| Key | Type | Allowed |
|---|---|---|
provider |
string |
"oil" or "snacks" |
Switching providers swaps the implementation behind <leader>e and directory-buffer takeover. The usual path is :BlakExtras enable editor.snacks-explorer, which sets this option and enables the Snacks explorer module for you.
terminal
Section titled “terminal”| Key | Type | Allowed |
|---|---|---|
provider |
string |
"native" or "snacks" |
toggle_key |
string or false |
Any key accepted by vim.keymap.set(), or false to skip the keymap |
The usual path for Snacks terminal is :BlakExtras enable editor.snacks-terminal,
which sets terminal.provider = "snacks" and enables the Snacks terminal module
for you. Set terminal.toggle_key when you want a different toggle mapping:
return { extras = { enabled = { "editor.snacks-terminal" } }, terminal = { toggle_key = "<C-/>", },}keymaps
Section titled “keymaps”keymaps is a list of user mappings applied after core and enabled extras.
| Key | Type | Notes |
|---|---|---|
mode |
string or string[] |
Optional; defaults to "n" |
modes |
string or string[] |
Alias for mode; use one or the other |
key |
string |
Required key to map |
action |
string, function, or false |
Required action; false disables this key |
description |
string |
Required for active mappings so :BlakKeys can show it |
disable |
boolean |
Set true to remove this key from Blak |
opts |
table |
Optional vim.keymap.set() options |
return { keymaps = { { key = "<leader>sg", action = "<cmd>BlakPick grep<cr>", description = "Grep" }, { mode = { "n", "x" }, key = "<leader>y", action = '"+y', description = "Yank to clipboard", }, { key = "<leader>rn", action = function() vim.lsp.buf.rename() end, description = "Rename symbol", }, { key = "<leader>/", disable = true }, },}To move a default action, disable the old key and add the new one.
This keeps user muscle memory explicit without hiding mappings from
:BlakKeys.
Blak still accepts lhs, rhs, and desc as aliases for users already
familiar with Vim terminology, but the documented user.lua shape uses the
more direct names above.
plugins
Section titled “plugins”| Key | Type | Notes |
|---|---|---|
specs |
table |
List of lazy.nvim specs appended after Blak core and enabled extras |
return { plugins = { specs = { { "tpope/vim-sleuth", event = "BufReadPost" }, }, },}Use this for personal plugins. If the behavior is broadly useful and
reversible, prefer a documented extra so other users can enable and disable it
through :BlakExtras.
| Key | Type | Notes |
|---|---|---|
before |
function or function[] |
Runs after merge, before validation and extras |
after |
function or function[] |
Runs after startup and after successful user.lua reloads |
return { hooks = { after = function(config) vim.opt.cursorline = false end, },}Hooks receive (config, blak). config is the merged Blak config table, and
blak.util is available on the second argument.
| Key | Type | Notes |
|---|---|---|
claudecode |
table |
Options passed to coder/claudecode.nvim when ai.claudecode is enabled. Blak sets terminal.provider = "snacks" by default. |
sidekick |
table |
Options passed to folke/sidekick.nvim when ai.sidekick is enabled. Blak sets nes.enabled = false by default. |
supermaven |
table |
Options passed to supermaven-inc/supermaven-nvim when ai.supermaven is enabled. Blak always disables the plugin’s built-in keymaps. |
Use this table for Claude Code configuration:
return { extras = { enabled = { "ai.claudecode" } }, ai = { claudecode = { terminal = { provider = "snacks", }, diff_opts = { layout = "vertical", }, }, },}Use ai.sidekick for Sidekick CLI and NES configuration:
return { extras = { enabled = { "ai.sidekick" } }, ai = { sidekick = { nes = { enabled = true }, cli = { mux = { enabled = true, backend = "tmux" }, }, }, },}Use ai.supermaven to tune Supermaven without enabling its hidden keymaps:
return { extras = { enabled = { "ai.supermaven" } }, ai = { supermaven = { ignore_filetypes = { markdown = true }, log_level = "info", }, },}| Key | Type | Notes |
|---|---|---|
modules |
string[] |
Mini module slugs to install and set up when editor.mini is enabled. Use ai, surround, or mini.ai; mini.icons and pair handling already ship in core. |
opts |
table<string, table> |
Per-module options passed to require("mini.<module>").setup() |
The Mini extra is intentionally inert until you choose modules:
return { extras = { enabled = { "editor.mini" } }, mini = { modules = { "ai", "surround" }, opts = { surround = { n_lines = 80 }, }, },}performance
Section titled “performance”| Key | Type | Notes |
|---|---|---|
bigfile_size |
number |
Size in bytes above which Snacks bigfile mode trims heavy features. Default 1.5 MiB |
max_treesitter_lines |
number |
Buffers with more lines than this skip Treesitter highlighting. Default 10000 |
snacks
Section titled “snacks”A table deep-merged over Blak’s own snacks.nvim options, last-write-wins.
Use it to tune or disable individual Snacks modules:
return { snacks = { words = { enabled = false }, },}The full option surface is the upstream snacks.nvim config; Blak validates
only that the value is mergeable.
treesitter
Section titled “treesitter”| Key | Type | Notes |
|---|---|---|
ensure_installed |
string[] |
Parsers requested on file events when the tree-sitter CLI is available |
Per the deep merge semantics below, setting ensure_installed in the simple
table form replaces the default parser list. Use the function form or an
extra to append.
| Key | Type | Notes |
|---|---|---|
automatic_enable |
boolean |
Enable configured servers automatically through vim.lsp.enable() |
servers |
table<string, table> |
Per-server options passed to vim.lsp.config() |
diagnostics |
table |
Passed to vim.diagnostic.config() |
return { lsp = { servers = { gopls = {}, }, diagnostics = { virtual_text = false, }, },}Language extras add their servers to lsp.servers for you; use this table
directly when you want a server without the rest of an extra. Validation only
checks the LSP table, automatic-enable flag, server tables, and diagnostic table.
| Key | Type | Notes |
|---|---|---|
automatic_install |
boolean |
Automatically install configured Mason tools and language servers |
ensure_installed |
string[] |
Mason package names |
format
Section titled “format”| Key | Type | Notes |
|---|---|---|
enabled |
boolean |
Format on save. vim.g.blak_disable_autoformat and vim.b.blak_disable_autoformat override per session or buffer |
timeout_ms |
number |
Formatter timeout per save |
lsp_format |
string |
Conform’s lsp_format mode; default "fallback" |
formatters_by_ft |
table<string, string[]> |
Conform formatters per filetype |
| Key | Type | Notes |
|---|---|---|
events |
string[] |
Autocmd events that trigger nvim-lint; empty list disables event-driven linting |
linters_by_ft |
table<string, string[]> |
nvim-lint linters per filetype |
extras
Section titled “extras”| Key | Type | Notes |
|---|---|---|
enabled |
blak.ExtraId[] |
List of extra IDs. lua_ls completes known IDs like lang.typescript, editor.mini, and git.lazygit. Validation only checks that entries are strings — unknown IDs surface as a warning at runtime, not a hard error. |
The runtime warning gives you a chance to keep using your config after renaming an extra in the repo.
Deep merge semantics
Section titled “Deep merge semantics”The simple user.lua form returns a table that is deep-merged into the
defaults via vim.tbl_deep_extend("force", defaults, user):
- Scalars in your table replace defaults.
- Tables are merged key by key.
- Lists are replaced wholesale. If you write
treesitter = { ensure_installed = { "rust" } }, you lose the entire default list.
To append to default lists, use an extra or return a function:
return function(config) table.insert(config.treesitter.ensure_installed, "rust")endThe function form receives the config table Blak is building. Mutate it in place and return nothing, or return a table of final overrides.
Error handling
Section titled “Error handling”If validation fails on startup, require("blak").setup() raises and Blak does not load. You’ll see the original Neovim banner and the error message in :messages.
If validation or evaluation fails during an automatic user.lua reload, Blak warns and keeps the previous in-session config active. Fix user.lua and save it again.
The error message is verbose on purpose:
Blak config validation failed:- package.channel must be stable, edge, or nightly- picker.provider must be fff, snacks, telescope, or fzf_lua- completion.super_tab must be boolean, got string- explorer.provider must be oil or snacks- terminal.provider must be native or snacks- extras.enabled entries must be stringsMultiple problems are reported in one pass so you don’t fix one and immediately hit the next.