Configure, customize, and manage the Zed code editor. Use when the user wants to modify Zed keybindings, settings, tasks, or extensions — especially for chaining editor actions via workspace::SendKeystrokes, creating custom workflows, or opening projects in Zed. Also use when launching Zed from the CLI, setting up vim/helix mode bindings, or troubleshooting Zed configuration.
Resources
1Install
npx skillscat add diegosouzapw/awesome-omni-skill/zed-editor Install via the SkillsCat registry.
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 tasksLinux
~/.config/zed/settings.json
~/.config/zed/keymap.json
~/.config/zed/tasks.jsonPer-project overrides
<project>/.zed/settings.json
<project>/.zed/tasks.jsonDetect 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 |
Settings (settings.json)
Settings is a JSON object. Key settings to know about:
{
// Font
"buffer_font_family": "Berkeley Mono",
"buffer_font_size": 14,
// Theme
"theme": "One Dark",
// Vim/Helix mode
"vim_mode": true,
"helix_mode": false,
// Formatting
"format_on_save": "on",
"formatter": "auto",
// Tab settings
"tab_size": 2,
"hard_tabs": false,
// Soft wrap
"soft_wrap": "editor_width",
"preferred_line_length": 100,
// Autosave
"autosave": { "after_delay": { "milliseconds": 1000 } },
// Per-language overrides
"languages": {
"Python": {
"tab_size": 4,
"formatter": {
"external": {
"command": "black",
"arguments": ["-"]
}
}
}
},
// Inlay hints
"inlay_hints": {
"enabled": true
},
// Telemetry
"telemetry": {
"diagnostics": false,
"metrics": false
},
// AI / Assistant
"assistant": {
"default_model": {
"provider": "anthropic",
"model": "claude-sonnet-4-5-20250514"
}
}
}Git Settings
{
"git_panel": {
"button": true,
"dock": "left",
"default_width": 360,
"status_style": "icon",
"sort_by_path": false,
"tree_view": false
},
"git": {
"git_gutter": "tracked_files",
"inline_blame": {
"enabled": true,
"delay_ms": 600,
"show_commit_summary": true
},
"hunk_style": "staged_hollow"
}
}Tasks (tasks.json)
Tasks let you run shell commands from Zed with access to editor context variables.
Structure
[
{
"label": "Run current file",
"command": "python $ZED_FILE",
"use_new_terminal": false,
"allow_concurrent_runs": false,
"reveal": "always"
}
]Available Environment Variables
| Variable | Value |
|---|---|
$ZED_FILE |
Absolute path of current file |
$ZED_FILENAME |
Filename only |
$ZED_DIRNAME |
Directory of current file |
$ZED_RELATIVE_FILE |
File path relative to project root |
$ZED_RELATIVE_DIR |
Directory relative to project root |
$ZED_STEM |
Filename without extension |
$ZED_ROW |
Current cursor row |
$ZED_COLUMN |
Current cursor column |
$ZED_SELECTED_TEXT |
Currently selected text |
$ZED_WORKTREE_ROOT |
Project root directory |
Task Options
| Option | Values | Default |
|---|---|---|
use_new_terminal |
true/false |
false |
allow_concurrent_runs |
true/false |
false |
reveal |
"always", "no_focus", "never" |
"always" |
hide |
"never", "always", "on_success" |
"never" |
cwd |
path string | project root |
env |
object of env vars | {} |
tags |
array of strings | [] |
CLI Usage
# Open a file or directory
zed .
zed file.txt
zed project/ file.txt
# Open in new window
zed --new file.txt
# Diff two files
zed --diff old.rs new.rs
# Wait for file to close (for EDITOR usage)
zed --wait file.txt
# Open at specific line:column
zed file.txt:42
zed file.txt:42:10
# Set as default editor
export EDITOR="zed --wait"
export VISUAL="zed --wait"
# Open settings/keymap directly
zed zed://settings
zed zed://keymap
# macOS: choose release channel
zed --stable file.txt
zed --preview file.txt
zed --nightly file.txtExtensions
Installed extensions location
- macOS:
~/Library/Application Support/Zed/extensions/installed/ - Linux:
~/.local/share/zed/extensions/installed/
Extensions are primarily managed through the Zed UI (cmd-shift-x / ctrl-shift-x), but you can inspect installed extensions via the filesystem.
Workflow: Adding a Custom Keybinding
This is the most common task. Follow this procedure:
Read the current keymap:
cat "$CONFIG_DIR/keymap.json" 2>/dev/null || echo "[]"Parse the JSON and check for conflicting bindings on the same key in the same context.
Determine the action(s) needed. If a single action suffices, bind directly:
"cmd-shift-d": "editor::DuplicateLineDown"If multiple actions are needed, use
workspace::SendKeystrokes:- Look up existing keybindings for each desired action
- Chain them:
["workspace::SendKeystrokes", "key1 key2 key3"] - Verify none are async
Add the binding to the appropriate context block (or create a new one).
Write the file and validate JSON:
python3 -c "import json; json.load(open('$CONFIG_DIR/keymap.json'))" && echo "Valid JSON"
Workflow: Opening a Project in Zed
# Check if zed CLI is available
which zed || echo "Zed CLI not installed. Run 'Zed > Install CLI' from the app menu."
# Open project
zed /path/to/project
# Open project with specific file focused
zed /path/to/project /path/to/project/src/main.rsWorkflow: Creating a Project Task Runner
- Create
.zed/tasks.jsonin the project root - Define tasks that use Zed environment variables
- Run tasks from the command palette or bind them to keys
Example — Rust project:
[
{
"label": "cargo run",
"command": "cargo run",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "cargo test current file",
"command": "cargo test --lib $ZED_STEM",
"cwd": "$ZED_WORKTREE_ROOT",
"reveal": "always"
},
{
"label": "cargo clippy",
"command": "cargo clippy --all-targets",
"cwd": "$ZED_WORKTREE_ROOT",
"hide": "on_success"
}
]Gotchas
- JSON only — Zed configs don't support comments (unlike VS Code's JSONC). Strip any
//comments before writing. - Array vs Object —
keymap.jsonandtasks.jsonare arrays[].settings.jsonis an object{}. - Later bindings win — If two bindings match the same context+key, the one defined later takes precedence. User bindings always override defaults.
- SendKeystrokes is synchronous — Don't try to chain actions that depend on async results (file opens, palette searches, LSP responses).
- Context matching — Contexts match at specific tree levels.
vim_modeis set atEditorlevel, so"Workspace && vim_mode == normal"will never match. - Zed auto-reloads config — changes to keymap.json and settings.json take effect immediately without restarting.
Claude Code Integration: Change Review Workflow
This workflow bridges Claude Code (running in Warp, Ghostty, or any external terminal) with Zed for seamless change review.
How It Works
- A PostToolUse hook in Claude Code records every file edit to a session manifest
- A Zed task reads the manifest and opens all changed files at the right lines
- Git review keybindings let you cycle through diffs, stage/revert per hunk
Setup
Step 1: Install the hook
Copy the hook script to a permanent location:
mkdir -p ~/.claude/hooks
cp hooks/post-tool-use.sh ~/.claude/hooks/post-tool-use.sh
chmod +x ~/.claude/hooks/post-tool-use.shStep 2: Configure Claude Code
Add to ~/.claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/post-tool-use.sh"
}
]
}
]
}
}Step 3: Add the Zed tasks
Merge the contents of examples/tasks.json into your global Zed tasks file:
- macOS:
~/Library/Application Support/Zed/tasks.json - Linux:
~/.config/zed/tasks.json
Step 4: Add review keybindings (optional)
Merge examples/keymap.json into your Zed keymap:
- macOS:
~/Library/Application Support/Zed/keymap.json - Linux:
~/.config/zed/keymap.json
Step 5: Configure git panel (optional)
Merge examples/settings.json into your Zed settings to dock the git panel on the right for a review-friendly layout.
Usage
- Run Claude Code in your terminal -- it edits files as usual
- Switch to Zed
- Run the "Review Claude Changes" task from the command palette (
cmd-shift-p> "task: spawn" > "Review Claude Changes") - All files Claude edited open at the relevant lines
- Use
alt-]/alt-[to jump between diff hunks - Use
alt-\to expand all diffs inline - Use the git panel to stage/revert changes
- When done reviewing, run "Clear Claude Change Manifest" to reset
Change Manifest
Changes accumulate per Claude Code session at ~/.claude/changes/<session-id>.json. A symlink at ~/.claude/changes/latest.json always points to the current session.
Format:
{
"session_id": "abc123",
"started": "2026-02-14T10:30:00Z",
"changes": [
{"file": "/path/to/file.rs", "line": 42, "tool": "Edit", "timestamp": "..."},
{"file": "/path/to/new.rs", "line": 1, "tool": "Write", "timestamp": "..."}
]
}