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:
| File | What it holds |
|---|---|
nash.toml | Settings, such as fonts, tabs, panes, and key bindings. |
themes.toml | The bundled color themes. |
commands.toml | Command, menu, and default-shortcut overrides. |
tasks.toml | Global 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
keysreplaces the entire shortcut list;keys = []unbinds the entry.enabled = falseremoves an entry. A higher layer can restore it withenabled = true.- A command's
actionandsubmenureplace one another. A task'scommand,argv, andstepreplace one another. palette = falsehides 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>.bakfirst. - 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.tomlorthemes.tomlbefore 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
| Option | What it does |
|---|---|
PATH | The file to sync, or the directory that holds it. The default is the Nash configuration directory. |
--all | Syncs themes.toml as well as nash.toml. |
--dry-run, -n | Reports what would change and writes nothing. |
--yes, -y | Does not ask for confirmation. You need it when stdin is not a terminal. |
--no-backup | Does 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 itskey. 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.tomlgivesbackgroundto every theme, so commenting outbackgroundunder 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
| Status | What it means |
|---|---|
| 0 | Nothing to add, or the write finished. |
| 1 | A dry run found something to add. Only --dry-run reports this way. |
| 2 | Nash 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.
- Nash refuses a file that is not valid TOML. With
--all, it refuses that file alone and still syncs the others. - 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.
- Nash copies the file to
<name>.bakbefore it writes. It keeps one copy, so a second sync writes over the first. Pass--no-backupto skip the copy. - 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.
- Nash writes to a temporary file in the same directory and renames it over the target, so an interrupted run leaves the file whole.
- A symbolic link stays a symbolic link. Nash follows the link and writes the
file it points at, and the
.bakcopy 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
- The nash Command lists the other subcommands.
- Updating Nash explains the update that triggers the automatic sync.