Zed Editor Skill
Configure and customize the Zed code editor by reading and writing its JSON config files, managing keybindings (including workspace::SendKeystrokes command chaining), defining tasks, and launching Zed via CLI.
Config File Locations
macOS
~/Library/Application Support/Zed/settings.json # Editor settings
~/Library/Application Support/Zed/keymap.json # Keybindings
~/Library/Application Support/Zed/tasks.json # Global tasks
Linux
~/.config/zed/settings.json
~/.config/zed/keymap.json
~/.config/zed/tasks.json
Per-project overrides
<project>/.zed/settings.json
<project>/.zed/tasks.json
Detect OS first — check uname to determine which paths to use.
Core Workflow
- Detect OS to resolve config paths
- Read existing config before making any changes (preserve user's work)
- Validate JSON — all Zed configs are JSON arrays or objects; malformed JSON will silently break the editor config
- Write changes using careful JSON merging — don't clobber existing bindings/settings
- Verify the file is valid JSON after writing
Reading Config Safely
# macOS
CONFIG_DIR="$HOME/Library/Application Support/Zed"
# Linux
CONFIG_DIR="$HOME/.config/zed"
# Read keymap (may not exist yet)
cat "$CONFIG_DIR/keymap.json" 2>/dev/null || echo "[]"
# Read settings
cat "$CONFIG_DIR/settings.json" 2>/dev/null || echo "{}"
Keybindings (keymap.json)
The keymap file is a JSON array of binding objects. Each object can have an optional context and a required bindings map.
Structure
[
{
"context": "Editor && vim_mode == normal",
"bindings": {
"key-combo": "action::Name",
"key-combo": ["action::Name", { "param": "value" }]
}
}
]
Key Syntax
Keys use modifier-key format separated by -:
- Modifiers:
cmd,ctrl,alt,shift,fn - Special keys:
up,down,left,right,enter,escape,tab,space,backspace,delete,home,end,pageup,pagedown - Letters/numbers:
a-z,0-9 - Multi-key sequences:
"g e"(space-separated, typed in sequence)
Examples: "cmd-shift-p", "ctrl-w h", "alt-down", "g e"
Context Expressions
Contexts scope bindings to specific UI states. Use && for AND, || for OR, ! for NOT, > for ancestor matching.
Common contexts:
Editor— any editor paneTerminal— terminal panelProjectPanel— file treeDock— any dock panelvim_mode == normal/insert/visual— vim mode statesVimControl— normal + visual modes combinedmenu— autocomplete/palette is openEmptyPane— no file open
Examples:
"context": "Editor && vim_mode == normal && !menu"
"context": "Terminal"
"context": "VimControl && !menu"
workspace::SendKeystrokes — Command Chaining
This is Zed's most powerful keybinding primitive. It dispatches a sequence of keystrokes synchronously, letting you chain multiple actions into a single keybinding without writing an extension.
Syntax
"key": ["workspace::SendKeystrokes", "keystroke1 keystroke2 keystroke3"]
Keystrokes are space-separated. Each keystroke uses the same modifier-key syntax as keybinding keys.
Important Constraints
- Synchronous only: SendKeystrokes dispatches all keys before any async operation completes. You CANNOT rely on async results (opening files, language server responses, command palette searches) between keystrokes.
- No cross-view chaining: You cannot send keys to a view that opens as a result of a previous keystroke in the same sequence.
- Async operations include: opening command palette, language server communication, changing buffer language, network requests.
Patterns
Chain copy + deselect:
"alt-w": ["workspace::SendKeystrokes", "cmd-c escape"]
Move down N lines:
"alt-down": ["workspace::SendKeystrokes", "down down down down"]
Select syntax node + copy + undo selection:
"cmd-alt-c": [
"workspace::SendKeystrokes",
"ctrl-shift-right ctrl-shift-right ctrl-shift-right cmd-c ctrl-shift-left ctrl-shift-left ctrl-shift-left"
]
Vim yank to end of line (neovim style):
{
"context": "vim_mode == normal && !menu",
"bindings": {
"shift-y": ["workspace::SendKeystrokes", "y $"]
}
}
Vim insert mode escape via jk:
{
"context": "Editor && vim_mode == insert",
"bindings": {
"j k": ["workspace::SendKeystrokes", "escape"]
}
}
Strategy for Building SendKeystrokes Chains
- First identify the individual actions needed (use
zed: open default keymapor the All Actions reference) - Find the existing keybindings for each action
- Chain those key combos in a single SendKeystrokes string
- Test that none of the intermediate actions are async
Common Actions Reference
Editor Actions
| Action | Description | |--------|-------------| | editor::Copy | Copy selection | | editor::Cut | Cut selection | | editor::Paste | Paste | | editor::Undo | Undo | | editor::Redo | Redo | | editor::SelectAll | Select all | | editor::Format | Format document | | editor::ToggleComments | Toggle line comments | | editor::MoveLineUp | Move current line up | | editor::MoveLineDown | Move current line down | | editor::DuplicateLineDown | Duplicate line | | editor::SelectLargerSyntaxNode | Expand selection to syntax | | editor::SelectSmallerSyntaxNode | Shrink selection | | editor::GoToDefinition | Go to definition | | editor::GoToDeclaration | Go to declaration | | editor::GoToImplementation | Go to implementation | | editor::Rename | Rename symbol | | editor::ToggleCodeActions | Show code actions | | editor::Newline | Insert newline | | editor::Tab | Insert tab/indent | | editor::Outdent | Outdent | | editor::FoldAll | Fold all | | editor::UnfoldAll | Unfold all |
Workspace Actions
| Action | Description | |--------|-------------| | workspace::NewFile | New file | | workspace::Save | Save | | workspace::SaveAll | Save all | | workspace::Open | Open file dialog | | workspace::ToggleLeftDock | Toggle left dock | | workspace::ToggleRightDock | Toggle right dock | | workspace::ToggleBottomDock | Toggle bottom dock | | workspace::ActivateNextPane | Focus next pane | | workspace::ActivatePreviousPane | Focus previous pane | | workspace::SendKeystrokes | Chain keystrokes |
Navigation
| Action | Description | |--------|-------------| | file_finder::Toggle | Open file finder | | project_symbols::Toggle | Open symbol search | | buffer_search::Deploy | Find in file | | project_search::ToggleFocus | Find in project | | outline::Toggle | Open outline view | | go_to_line::Toggle | Go to line number | | tab_switcher::Toggle | Switch tabs | | diagnostics::Deploy | Open diagnostics |
Terminal
| Action | Description | |--------|-------------| | terminal_panel::ToggleFocus | Toggle/focus terminal | | workspace::NewTerminal | New terminal tab |
Git
| Action | Description | |--------|-------------| | git_panel::ToggleFocus | Toggle/focus git panel | | git::Diff | Open project diff view | | git::OpenModifiedFiles | Open all modified files | | git::StageAndNext | Stage current hunk, advance to next | | git::UnstageAndNext | Unstage current hunk, advance to next | | git::ToggleStaged | Toggle staged state | | git::Commit | Commit staged changes | | git::GenerateCommitMessage | AI-generated commit message | | git::Fetch | Fetch from remote | | git::Push | Push to remote | | git::Pull | Pull from remote | | git::Restore | Restore/undo changes | | editor::GoToHunk | Navigate to next diff hunk | | editor::GoToPreviousHunk | Navigate to previous diff hunk | | editor::ExpandAllDiffHunks | Expand all hunks inline | | editor::ToggleSelectedDiffHunks | Toggle diff for selected hunks |