tasks.md

  1---
  2title: Tasks - Run Commands in Zed
  3description: Run and rerun shell commands from Zed with task definitions. Supports variables, templates, and language-specific tasks.
  4---
  5
  6# Tasks
  7
  8Zed supports ways to spawn (and rerun) commands using its integrated [terminal](./terminal.md) to output the results. These commands can read a limited subset of Zed state (such as a path to the file currently being edited or selected text).
  9
 10```json [tasks]
 11[
 12  {
 13    "label": "Example task",
 14    "command": "for i in {1..5}; do echo \"Hello $i/5\"; sleep 1; done",
 15    //"args": [],
 16    // Env overrides for the command, will be appended to the terminal's environment from the settings.
 17    "env": { "foo": "bar" },
 18    // Current working directory to spawn the command into, defaults to current project root.
 19    //"cwd": "/path/to/working/directory",
 20    // Whether to use a new terminal tab or reuse the existing one to spawn the process, defaults to `false`.
 21    "use_new_terminal": false,
 22    // Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish, defaults to `false`.
 23    "allow_concurrent_runs": false,
 24    // What to do with the terminal pane and tab, after the command was started:
 25    // * `always` — always show the task's pane, and focus the corresponding tab in it (default)
 26    // * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
 27    // * `never` — do not alter focus, but still add/reuse the task's tab in its pane
 28    "reveal": "always",
 29    // What to do with the terminal pane and tab, after the command has finished:
 30    // * `never` — Do nothing when the command finishes (default)
 31    // * `always` — always hide the terminal tab, hide the pane also if it was the last tab in it
 32    // * `on_success` — hide the terminal tab on task success only, otherwise behaves similar to `always`
 33    "hide": "never",
 34    // Which shell to use when running a task inside the terminal.
 35    // May take 3 values:
 36    // 1. (default) Use the system's default terminal configuration in /etc/passwd
 37    //      "shell": "system"
 38    // 2. A program:
 39    //      "shell": {
 40    //        "program": "sh"
 41    //      }
 42    // 3. A program with arguments:
 43    //     "shell": {
 44    //         "with_arguments": {
 45    //           "program": "/bin/bash",
 46    //           "args": ["--login"]
 47    //         }
 48    //     }
 49    "shell": "system",
 50    // Whether to show the task line in the output of the spawned task, defaults to `true`.
 51    "show_summary": true,
 52    // Whether to show the command line in the output of the spawned task, defaults to `true`.
 53    "show_command": true,
 54    // Which edited buffers to save before running the task:
 55    // * `all` — save all edited buffers
 56    // * `current` — save currently active buffer only
 57    // * `none` — don't save any buffers
 58    "save": "none"
 59    // Represents the tags for inline runnable indicators, or spawning multiple tasks at once.
 60    // "tags": []
 61  }
 62]
 63```
 64
 65There are two actions that drive the workflow of using tasks: `task: spawn` and `task: rerun`.
 66`task: spawn` opens a modal with all available tasks in the current file.
 67`task: rerun` reruns the most recently spawned task. You can also rerun tasks from the task modal.
 68
 69By default, rerunning tasks reuses the same terminal (due to the `"use_new_terminal": false` default) but waits for the previous task to finish before starting (due to the `"allow_concurrent_runs": false` default).
 70
 71Keep `"use_new_terminal": false` and set `"allow_concurrent_runs": true` to allow cancelling previous tasks on rerun.
 72
 73## Task templates
 74
 75Tasks can be defined:
 76
 77- in the global `tasks.json` file; such tasks are available in all Zed projects you work on. This file is usually located in `~/.config/zed/tasks.json`. You can edit them by using the `zed: open tasks` action.
 78- in the worktree-specific (local) `.zed/tasks.json` file; such tasks are available only when working on a project with that worktree included. You can edit worktree-specific tasks by using the `zed: open project tasks` action.
 79- on the fly with [oneshot tasks](#oneshot-tasks). These tasks are project-specific and do not persist across sessions.
 80- by language extension.
 81
 82## Variables
 83
 84Zed tasks act just like your shell; that also means that you can reference environmental variables via sh-esque `$VAR_NAME` syntax. A couple of additional environmental variables are set for your convenience.
 85These variables allow you to pull information from the current editor and use it in your tasks. The following variables are available:
 86
 87- `ZED_COLUMN`: current line column
 88- `ZED_ROW`: current line row
 89- `ZED_FILE`: absolute path of the currently opened file (e.g. `/Users/my-user/path/to/project/src/main.rs`)
 90- `ZED_FILENAME`: filename of the currently opened file (e.g. `main.rs`)
 91- `ZED_DIRNAME`: absolute path of the currently opened file with file name stripped (e.g. `/Users/my-user/path/to/project/src`)
 92- `ZED_RELATIVE_FILE`: path of the currently opened file, relative to `ZED_WORKTREE_ROOT` (e.g. `src/main.rs`)
 93- `ZED_RELATIVE_DIR`: path of the currently opened file's directory, relative to `ZED_WORKTREE_ROOT` (e.g. `src`)
 94- `ZED_STEM`: stem (filename without extension) of the currently opened file (e.g. `main`)
 95- `ZED_SYMBOL`: currently selected symbol; should match the last symbol shown in a symbol breadcrumb (e.g. `mod tests > fn test_task_contexts`)
 96- `ZED_SELECTED_TEXT`: currently selected text
 97- `ZED_LANGUAGE`: language of the currently opened buffer (e.g. `Rust`, `Python`, `Shell Script`)
 98- `ZED_WORKTREE_ROOT`: absolute path to the root of the current worktree. (e.g. `/Users/my-user/path/to/project`)
 99- `ZED_CUSTOM_RUST_PACKAGE`: (Rust-specific) name of the parent package of $ZED_FILE source file.
100
101To use a variable in a task, prefix it with a dollar sign (`$`):
102
103```json [tasks]
104{
105  "label": "echo current file's path",
106  "command": "echo $ZED_FILE"
107}
108```
109
110You can also use verbose syntax that allows specifying a default if a given variable is not available: `${ZED_FILE:default_value}`
111
112These environmental variables can also be used in tasks' `cwd`, `args`, and `label` fields.
113
114### Variable Quoting
115
116When working with paths containing spaces or other special characters, please ensure variables are properly escaped.
117
118For example, instead of this (which will fail if the path has a space):
119
120```json [tasks]
121{
122  "label": "stat current file",
123  "command": "stat $ZED_FILE"
124}
125```
126
127Provide the following:
128
129```json [tasks]
130{
131  "label": "stat current file",
132  "command": "stat",
133  "args": ["$ZED_FILE"]
134}
135```
136
137Or explicitly include escaped quotes like so:
138
139```json [tasks]
140{
141  "label": "stat current file",
142  "command": "stat \"$ZED_FILE\""
143}
144```
145
146### Task filtering based on variables
147
148Task definitions with variables which are not present at the moment the task list is determined are filtered out.
149For example, the following task will appear in the spawn modal only if there is a text selection:
150
151```json [tasks]
152{
153  "label": "selected text",
154  "command": "echo \"$ZED_SELECTED_TEXT\""
155}
156```
157
158Set default values to such variables to have such tasks always displayed:
159
160```json [tasks]
161{
162  "label": "selected text with default",
163  "command": "echo \"${ZED_SELECTED_TEXT:no text selected}\""
164}
165```
166
167## Oneshot tasks
168
169The same task modal opened via `task: spawn` supports arbitrary bash-like command execution: type a command inside the modal text field, and use `opt-enter` to spawn it.
170
171The task modal persists these ad-hoc commands for the duration of the session, `task: rerun` will also rerun such tasks if they were the last ones spawned.
172
173You can also adjust the currently selected task in a modal (`tab` is the default key binding). Doing so will put its command into a prompt that can then be edited & spawned as a oneshot task.
174
175### Ephemeral tasks
176
177You can use the `cmd` modifier when spawning a task via a modal; tasks spawned this way will not have their usage count increased (thus, they will not be respawned with `task: rerun` and they won't have a high rank in the task modal).
178The intended use of ephemeral tasks is to stay in the flow with continuous `task: rerun` usage.
179
180### More task rerun control
181
182By default, tasks capture their variables into a context once, and this "resolved task" is being rerun always.
183
184This can be controlled with the `"reevaluate_context"` argument to the task: setting it to `true` will force the task to be reevaluated before each run.
185
186```json [keymap]
187{
188  "context": "Workspace",
189  "bindings": {
190    "alt-t": ["task::Rerun", { "reevaluate_context": true }]
191  }
192}
193```
194
195## Custom keybindings for tasks
196
197You can define your own keybindings for your tasks via an additional argument to `task::Spawn`. If you wanted to bind the aforementioned `echo current file's path` task to `alt-g`, you would add the following snippet in your [`keymap.json`](./key-bindings.md) file:
198
199```json [keymap]
200{
201  "context": "Workspace",
202  "bindings": {
203    "alt-g": ["task::Spawn", { "task_name": "echo current file's path" }]
204  }
205}
206```
207
208Note that these tasks can also have a 'target' specified to control where the spawned task should show up.
209This could be useful for launching a terminal application that you want to use in the center area:
210
211```json [tasks]
212// In tasks.json
213{
214  "label": "start lazygit",
215  "command": "lazygit -p $ZED_WORKTREE_ROOT"
216}
217```
218
219```json [keymap]
220// In keymap.json
221{
222  "context": "Workspace",
223  "bindings": {
224    "alt-g": [
225      "task::Spawn",
226      { "task_name": "start lazygit", "reveal_target": "center" }
227    ]
228  }
229}
230```
231
232## VS Code Task Format
233
234When importing VS Code tasks from `.vscode/tasks.json`, you can omit the `label` field. Zed automatically generates labels based on the task type:
235
236- **npm tasks**: `npm: <script>` (e.g., `npm: start`)
237- **gulp tasks**: `gulp: <task>` (e.g., `gulp: build`)
238- **shell tasks**: Uses the `command` string directly (e.g., `echo hello`), or `shell` if the command is empty
239- **Tasks without type**: `Untitled Task`
240
241Example task file with auto-generated labels:
242
243```json
244{
245  "version": "2.0.0",
246  "tasks": [
247    {
248      "type": "npm",
249      "script": "start"
250    },
251    {
252      "type": "shell",
253      "command": "cargo build --release"
254    }
255  ]
256}
257```
258
259These tasks appear in the task picker as "npm: start" and "cargo build --release". You can override the generated label by providing an explicit `label` field.
260
261## Binding runnable tags to task templates
262
263Zed supports overriding the default action for inline runnable indicators via workspace-local and global `tasks.json` file with the following precedence hierarchy:
264
2651. Workspace `tasks.json`
2662. Global `tasks.json`
2673. Language-provided tag bindings (default).
268
269To tag a task, add the runnable tag name to the `tags` field on the task template:
270
271```json [tasks]
272{
273  "label": "echo current file's path",
274  "command": "echo $ZED_FILE",
275  "tags": ["rust-test"]
276}
277```
278
279In doing so, you can change which task is shown in the runnables indicator.
280
281## Keybindings to run tasks bound to runnables
282
283When you have a task definition that is bound to the runnable, you can quickly run it using [Code Actions](https://zed.dev/docs/configuring-languages?#code-actions) that you can trigger either via `editor: Toggle Code Actions` command or by the `cmd-.`/`ctrl-.` shortcut. Your task will be the first in the dropdown. The task will run immediately if there are no additional Code Actions for this line.
284
285## Running Bash Scripts
286
287You can run bash scripts directly from Zed. When you open a `.sh` or `.bash` file, Zed automatically detects the script as runnable and makes it available in the task picker.
288
289To run a bash script:
290
2911. Open the command palette with {#kb command_palette::Toggle}
2922. Search for "task" and select **task: spawn**
2933. Select the script from the list
294
295Bash scripts are tagged with `bash-script`, allowing you to filter or reference them in task configurations.
296
297If you need to pass arguments or customize the execution environment, add a task configuration in your `.zed/tasks.json`:
298
299```json
300[
301  {
302    "label": "run my-script.sh with args",
303    "command": "./my-script.sh",
304    "args": ["--verbose", "--output=results.txt"],
305    "tags": ["bash-script"]
306  }
307]
308```
309
310## Shell Initialization
311
312When Zed runs a task, it launches the command in a login shell. This ensures your shell's initialization files (`.bash_profile`, `.zshrc`, etc.) are sourced before the task executes.
313
314This behavior gives tasks access to the same environment variables, aliases, and PATH modifications you've configured in your shell profile. If a task fails to find a command that works in your terminal, verify your shell configuration files are properly set up.
315
316To override the shell used for tasks, configure the `terminal.shell` setting:
317
318```json
319{
320  "terminal": {
321    "shell": {
322      "program": "/bin/zsh"
323    }
324  }
325}
326```
327
328See [Terminal configuration](./terminal.md) for complete shell options.