Configuration Sync

Nash seeds nash.toml and themes.toml in your configuration directory on first launch. Later releases add missing preferences without replacing your values.

Since Nash 0.10.0, commands, default shortcuts, and tasks work differently: Nash reads bundled defaults from its binary, and your commands.toml and tasks.toml contain only your overrides. They are not seeded or synced. See the “Commands and tasks” section below.

So Nash merges the defaults of your build into the files you already have. It does this by itself the first time a new build starts, and nash config sync runs the same merge whenever you ask. Either way the merge only adds. Your values, comments, and key order stay exactly as you wrote them.

The files

Nash ships four TOML files:

FileWhat it holds
nash.tomlSettings, such as fonts, tabs, panes, and key bindings.
themes.tomlThe bundled color themes.
commands.tomlCommand, menu, and default-shortcut overrides.
tasks.tomlGlobal task overrides.

They live in ~/.config/nash by default. If XDG_CONFIG_HOME is set to an absolute path, they live in $XDG_CONFIG_HOME/nash. A non-empty NASH_CONFIG_DIR overrides both.

Inspect bundled defaults

Use Nash 0.10.0 or newer to print the defaults without changing your files:

nash config defaults commands.toml nash config defaults tasks.toml nash config defaults nash.toml nash config defaults themes.toml

For commands and tasks, find the id you want to customize and add an entry with that ID to your own file.

Commands and tasks

Commands and tasks merge in layers: bundled defaults, your global TOML file, then the active project's .nash.toml. An entry with the same id changes only the fields it sets; omitted fields keep their values from lower layers. New IDs add new entries.

For example, in ~/.config/nash/commands.toml:

version = 1 [[command]] id = "clear_scrollback" keys = [{ key = "k", mods = "SUPER|ALT" }] [[command]] id = "quit_application" keys = [] [[command]] id = "hide_application" enabled = false
  • keys replaces the entire shortcut list; keys = [] unbinds the entry.
  • enabled = false removes an entry. A higher layer can restore it with enabled = true.
  • A command's action and submenu replace one another. A task's command, argv, and step replace one another.
  • palette = false hides a command from the palette; menubar = [] hides it from the macOS menu bar. Neither removes its shortcuts.
  • Delete an override field or entry to inherit the current bundled default.

Project overrides affect the palette and execution through RunCommand or RunTask. Shortcut bindings and menu entries use the bundled and global layers, not project keys. On macOS, clicking a menu item with a shortcut runs the action bound to that shortcut, including project-aware RunCommand.

The palette and menus display effective shortcuts from the live bindings, including Lua overrides and RunCommand aliases. Inspect all bindings with nash show-keys --lua. disable_default_key_bindings disables bundled keys, not keys explicitly set in your files or Lua configuration.

The old command_palette_key preference was removed in 0.10.0. Change the keys of command ID command_palette in commands.toml instead.

Historical behavior (before 0.10.0): older releases copied complete command and task files into your config directory. Manual sync, introduced in 0.7.0, could merge all four bundled TOML files with --all; from 0.7.3, the first launch after a version change also synced settings, themes, commands, and tasks. These merges preserved explicit values, comments, blank lines, and key order, respected commented-out entries, and backed up changed files to <name>.bak. This is not how commands and tasks work in current releases.

Those older files still work, but every field they set counts as an explicit override. Remove unchanged entries to inherit newer defaults; keep the entries you customized. Nash does not rewrite these files for you.

See Scope & Overrides for task examples and VS Code task handling.

What happens on its own

Nash records the version that last synced your files in ~/.config/nash/state/config-sync.json. On the first launch of a build that differs from that record (Nash 0.7.3 or newer), Nash merges the defaults into nash.toml and themes.toml before it reads them, so additions take effect on that launch. On every later launch of the same build it skips this merge.

  • A file that changes is copied to <name>.bak first.
  • A file that Nash cannot read, parse, or write stays exactly as it is. Nash still syncs the other files and writes the reason into its log. Fix the file, then run nash config sync --all.
  • Whenever Nash loads its bundled configuration, it creates a missing nash.toml or themes.toml before checking the sync record. A file that you deleted therefore comes back, even on the same build. This seeding is separate from the version-gated merge.
  • Going back to an older build syncs as well. Nash compares the recorded version with the running one, and an older bundle can still hold a key that a newer one dropped.

To see what a build would add before you take it, run nash config sync --all --dry-run.

Run it yourself

nash config sync

Nash reports what it would change and asks before it writes:

/Users/you/.config/nash/nash.toml + pane.pane_agent_status_indicator = "badge" - tab.active_tab_highlight_color (commented out in your file) Write this change? [y/N] y Wrote /Users/you/.config/nash/nash.toml The file as it was is in /Users/you/.config/nash/nash.toml.bak

A + line is something the merge adds. A - line is something it leaves out, and the reason is on the line. A ! line is a file that Nash could not finish. A second run reports that the files are up to date and writes nothing.

The command needs Nash 0.7.0 or newer.

Options

OptionWhat it does
PATHThe file to sync, or the directory that holds it. The default is the Nash configuration directory.
--allSyncs themes.toml as well as nash.toml.
--dry-run, -nReports what would change and writes nothing.
--yes, -yDoes not ask for confirmation. You need it when stdin is not a terminal.
--no-backupDoes not keep a .bak copy of a file that changes.

PATH takes a directory or a file:

nash config sync # nash.toml in your configuration directory nash config sync --all # nash.toml and themes.toml nash config sync ~/dotfiles/nash # nash.toml in that directory nash config sync ~/dotfiles/themes.toml # that one file

A file name decides which defaults Nash merges into it, so a single file must be named nash.toml or themes.toml. Sync refuses commands.toml and tasks.toml; use nash config defaults to inspect their bundled entries. A supported file that does not exist yet is created from the bundled defaults, and so is a configuration directory that does not exist yet.

The global --config-file option does not apply to this command. It names a Lua file, and nash config sync works on the TOML files. Use PATH, or set NASH_CONFIG_DIR.

What the merge does

The merge adds and nothing else.

  • A key you already have keeps its value, its comment, and its place in the file.
  • A key that your build defines and your file lacks goes next to the keys it belongs with, together with the comment that documents it.
  • A whole table such as [mux], or a [[keys]] entry that your file lacks, is added whole.
  • Nothing is removed. A key you added yourself stays, and so does a key that a later build dropped.

Nash matches [[keys]] entries by key alone and never merges into one: key, mods, action, and text are one decision, and a binding you wrote stays exactly as you wrote it. Command and task layering is separate from this file merge.

Turn off something the build ships

Comment it out. That is the one signal the merge reads, and it works for a key, a table, and an array entry:

# A key you do not want: # active_tab_highlight_color = '#ffffff' # A table you do not want: # [mux] # enabled = false # domain = "mux" # A key binding you do not want: # [[keys]] # key = "Delete" # action = "SendString" # text = '\u001b[3~'

Deleting is not enough. A key or entry that you delete comes back on the next sync, and an upgrade is a sync, because a file that never had it and a file that lost it look the same. A commented-out one is reported as left out and stays gone.

For commands and tasks, commenting out an override restores the lower-layer value instead of disabling the default. Use enabled = false or keys = [] as shown above.

  • Keep the line that names a binding. Nash identifies a [[keys]] binding by its key. Comment that line out with the rest of the block. Without it Nash cannot tell which entry you meant, and the entry comes back.
  • Nash reads a commented-out key in the table where it sits. themes.toml gives background to every theme, so commenting out background under one theme leaves the other themes alone.
  • Commented-out settings at the end of a file stay in the table they follow when Nash adds new tables after them (Nash 0.9.1 or newer). Before 0.9.1 such a comment could end up in the wrong table, and the next sync added the setting back.

Exit status

StatusWhat it means
0Nothing to add, or the write finished.
1A dry run found something to add. Only --dry-run reports this way.
2Nash could not finish. Every file that it could finish is still done.

Status 1 means drift and nothing else. A path Nash cannot use, a file it cannot read, and a file that is not valid TOML all exit with 2. That lets a script check whether your configuration has drifted from your build:

nash config sync --all --dry-run

What protects your file

A configuration file is not something to be wrong about, so the command checks its own work.

  1. Nash refuses a file that is not valid TOML. With --all, it refuses that file alone and still syncs the others.
  2. Nash parses the merged text again and compares it with your file. Every value your file held must still be there, unchanged. If not, Nash writes nothing.
  3. Nash copies the file to <name>.bak before it writes. It keeps one copy, so a second sync writes over the first. Pass --no-backup to skip the copy.
  4. Nash checks that the file is still what it read. An edit you make while the prompt waits is never overwritten, and neither is a file that you create while the prompt waits.
  5. Nash writes to a temporary file in the same directory and renames it over the target, so an interrupted run leaves the file whole.
  6. A symbolic link stays a symbolic link. Nash follows the link and writes the file it points at, and the .bak copy goes next to that file. A configuration directory made of links into a dotfiles repository keeps its links.

Nash keeps the line endings of a file written with CRLF, and the byte order mark of a file that starts with one.

From the command palette

Two bundled tasks run the same commands. Each opens a new tab that stays open:

  • Check Config for New Settings runs nash config sync --all --dry-run.
  • Sync Config Settings runs nash config sync --all.

You never need these after an upgrade. They are there for a file that Nash could not finish on its own, and for a look at what a build added.

Troubleshooting

Your file is not valid TOML

your file is not valid TOML, so Nash cannot merge into it

Nash names the line that failed. Fix it, then run nash config sync --all.

The file changed while Nash waited

the file changed while Nash waited for your answer. Nash wrote nothing. Run the command again.

You, or a program, edited the file between the report and your answer. Run the command again.

Nash ships no defaults for a file

When you name an existing file that Nash has no defaults for, such as ~/dotfiles/custom.toml, the command lists the supported sync targets. Point PATH at nash.toml, themes.toml, or their directory. For commands and tasks, use nash config defaults <file> rather than sync.

A setting you deleted came back

Delete is not enough. Comment the key out instead. See "Turn off something the build ships" above.

Related pages