Skip to content
Back to skills

Zed Editor

ASecurity

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.

  • 57 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added October 17, 2026
toolspythonrustgoshellbashnodeexpressgit

Works with

  • claude code
  • cursor
  • terminal
  • cli

Security analysis

A100/100

Scanned October 17, 2026

npx -y skills add diegosouzapw/awesome-omni-skill --skill zed-editor --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Zed Editor?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Zed Editor
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/diegosouzapw-zed-editor/badge)](https://www.skillsdirectory.com/skills/diegosouzapw-zed-editor)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: zed-editor
description: 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.
---

# 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

1. **Detect OS** to resolve config paths
2. **Read existing config** before making any changes (preserve user's work)
3. **Validate JSON** — all Zed configs are JSON arrays or objects; malformed JSON will silently break the editor config
4. **Write changes** using careful JSON merging — don't clobber existing bindings/settings
5. **Verify** the file is valid JSON after writing

### Reading Config Safely

```bash
# 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

```json
[
  {
    "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 pane
- `Terminal` — terminal panel
- `ProjectPanel` — file tree
- `Dock` — any dock panel
- `vim_mode == normal` / `insert` / `visual` — vim mode states
- `VimControl` — normal + visual modes combined
- `menu` — autocomplete/palette is open
- `EmptyPane` — no file open

Examples:
```json
"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

```json
"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:**
```json
"alt-w": ["workspace::SendKeystrokes", "cmd-c escape"]
```

**Move down N lines:**
```json
"alt-down": ["workspace::SendKeystrokes", "down down down down"]
```

**Select syntax node + copy + undo selection:**
```json
"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):**
```json
{
  "context": "vim_mode == normal && !menu",
  "bindings": {
    "shift-y": ["workspace::SendKeystrokes", "y $"]
  }
}
```

**Vim insert mode escape via jk:**
```json
{
  "context": "Editor && vim_mode == insert",
  "bindings": {
    "j k": ["workspace::SendKeystrokes", "escape"]
  }
}
```

### Strategy for Building SendKeystrokes Chains

1. First identify the individual actions needed (use `zed: open default keymap` or the All Actions reference)
2. Find the existing keybindings for each action
3. Chain those key combos in a single SendKeystrokes string
4. 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:

```json
{
  // 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

```json
{
  "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

```json
[
  {
    "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

```bash
# 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.txt
```

---

## Extensions

### 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:

1. **Read the current keymap:**
   ```bash
   cat "$CONFIG_DIR/keymap.json" 2>/dev/null || echo "[]"
   ```

2. **Parse the JSON** and check for conflicting bindings on the same key in the same context.

3. **Determine the action(s) needed.** If a single action suffices, bind directly:
   ```json
   "cmd-shift-d": "editor::DuplicateLineDown"
   ```

4. **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

5. **Add the binding** to the appropriate context block (or create a new one).

6. **Write the file** and validate JSON:
   ```bash
   python3 -c "import json; json.load(open('$CONFIG_DIR/keymap.json'))" && echo "Valid JSON"
   ```

---

## Workflow: Opening a Project in Zed

```bash
# 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.rs
```

---

## Workflow: Creating a Project Task Runner

1. Create `.zed/tasks.json` in the project root
2. Define tasks that use Zed environment variables
3. Run tasks from the command palette or bind them to keys

Example — Rust project:
```json
[
  {
    "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.json` and `tasks.json` are arrays `[]`. `settings.json` is 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_mode` is set at `Editor` level, 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

1. A PostToolUse hook in Claude Code records every file edit to a session manifest
2. A Zed task reads the manifest and opens all changed files at the right lines
3. 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:

```bash
mkdir -p ~/.claude/hooks
cp hooks/post-tool-use.sh ~/.claude/hooks/post-tool-use.sh
chmod +x ~/.claude/hooks/post-tool-use.sh
```

**Step 2: Configure Claude Code**

Add to `~/.claude/settings.json`:

```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

1. Run Claude Code in your terminal -- it edits files as usual
2. Switch to Zed
3. Run the **"Review Claude Changes"** task from the command palette (`cmd-shift-p` > "task: spawn" > "Review Claude Changes")
4. All files Claude edited open at the relevant lines
5. Use `alt-]` / `alt-[` to jump between diff hunks
6. Use `alt-\` to expand all diffs inline
7. Use the git panel to stage/revert changes
8. 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:
```json
{
  "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": "..."}
  ]
}
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.