Hierarchical task menu for VS Code - execute terminal commands, VS Code commands, and tasks from YAML configuration.
- Hierarchical Menu: Organize commands in a tree structure with unlimited depth
- Quick Pick UI: Fast keyboard-driven interface
- Multiple Action Types:
- Terminal commands (with named terminals)
- VS Code commands (with arguments)
- tasks.json tasks
- Remote actions (Dev Container, SSH)
- YAML Configuration: Easy-to-edit configuration file
- Command Reuse: Define commands once, reference from multiple menus (
reffeature) - Auto Reload: Configuration changes are automatically detected
- Open VS Code
- Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)
- Search for "TaskPilot"
- Click Install
- Download the
.vsixfile from Releases - In VS Code, open Command Palette (Ctrl+Shift+P / Cmd+Shift+P)
- Run "Extensions: Install from VSIX..."
- Select the downloaded
.vsixfile
- Create
.vscode/task-menu.yamlin your workspace:
version: "1.0"
menu:
- label: Build
icon: "$(tools)"
type: terminal
command: npm run build
- label: Development
icon: "$(rocket)"
children:
- label: Start Server
icon: "$(play)"
type: terminal
terminal: dev
command: npm run dev
- label: Run Tests
icon: "$(beaker)"
type: terminal
command: npm test- Press
Cmd+Shift+T(Mac) orCtrl+Shift+T(Windows/Linux) - Select a menu item to execute
| Setting | Description | Default |
|---|---|---|
taskPilot.configPath |
Path to YAML config file | .vscode/task-menu.yaml |
taskPilot.globalMenu |
Global menu items merged after workspace menu | [] |
An absolute taskPilot.configPath is used as-is when readable. If it is not readable from the current workspace — typical in Dev Container / remote workspaces where the local path does not exist — and the workspace has a .vscode/task-menu.yaml, TaskPilot falls back to that workspace default instead of showing no menu. A readable custom absolute path always stays preferred, and relative paths are resolved against the workspace root as before.
Menus are layered with workspace priority:
- Workspace menu (
taskPilot.configPath, default.vscode/task-menu.yaml) taskPilot.globalMenuin user settings
Items with the same label are taken from the higher-priority layer; colliding categories merge their children recursively with the same priority. The sidebar footer always shows which config file the workspace menu was loaded from.
In v0.7.0 a
task-menu.yamlin the VS Code User directory was loaded as an additional user-level layer. That layer has since been removed: it lived on the extension host, so in Remote-SSH / Dev Container sessions it resolved to a per-host file instead of one shared menu, and it was not covered by Settings Sync.taskPilot.globalMenuhas neither problem. A leftover User-directorytask-menu.yamlis simply ignored.
taskPilot.globalMenu is the single global layer: menu items defined in user settings and merged into every workspace. Because it lives in user settings it is synced by Settings Sync and applies in remote sessions too.
- It supports the same inline action shapes as
MenuItem, includingchildren,actions,parallel,args, andcontinueOnError refis not supported intaskPilot.globalMenubecause user settings do not have acommandssection — shared menus must inline their commands. This is enforced at every level: top-level items, nested children, and entries insideactions/parallelarrays. The settings schema also rejectsrefso Settings UI cannot persist invalid objects.- When a
labelcollides with a workspace menu item, TaskPilot keeps the workspace item - If both colliding items are categories with
children, TaskPilot recursively merges their children with workspace priority
Example:
"taskPilot.globalMenu": [
{
"label": "Utilities",
"children": [
{
"label": "Open Extensions",
"type": "vscodeCommand",
"command": "workbench.view.extensions"
},
{
"label": "Prep + Test",
"actions": [
{
"type": "shellCommand",
"command": "./scripts/prepare.sh"
},
{
"type": "terminal",
"command": "npm test",
"terminal": "TaskPilot Tests"
}
]
}
]
}
]Use TaskPilot: Export Workspace Menu to Global Menu (User Settings) to share workspace menu items across all workspaces.
- A QuickPick lists the exportable top-level items (all pre-selected); pick the ones to share
- Items whose label already exists in
taskPilot.globalMenuare marked and replace the existing global item; new labels are appended. Replacement is whole-item: a category replaces the previous global entry including its entirechildrenlist (children that only existed in the old global entry are not merged back) - The selection is written directly into
taskPilot.globalMenuin your User settings — no copy/paste step - The command never touches
taskPilot.configPathor any file on disk - When invoked from the Config Editor's "Export Global Menu" button, the export uses the editor's current (possibly unsaved) state
- Top-level items whose subtree contains
refare skipped (refneeds the workspacecommandssection); the skipped count is reported
Right-click a menu item in the TaskPilot sidebar:
- Promote to Global Menu writes that item into
taskPilot.globalMenuas a top-level entry (replacing a same-label entry if one exists). The item is captured exactly as displayed — for a merged category that includes the global-side children too. Items containingrefcannot be promoted. The sidebar re-renders immediately. - Remove from Global Menu (shown only for top-level items that exist in
taskPilot.globalMenu) deletes the same-label entry from your User settings.
This is the quickest way to iterate: test an item in the workspace .vscode/task-menu.yaml, then promote it once it works — no manual merging.
version: "1.0"
# Reusable command definitions
commands:
command_id:
type: terminal | shellCommand | vscodeCommand | task
command: string # Command to execute
terminal: string # Terminal name (for type: terminal)
args: array # Command arguments
cwd: string # Working directory
description: string # Description
# Menu structure
menu:
- label: string # Display name (required)
icon: string # Icon (emoji or codicon)
description: string # Description text
children: [] # Sub-menu items (for categories)
# Action (one of the following)
ref: string # Reference to commands section
type: terminal | shellCommand | vscodeCommand | task
command: stringversion: "1.0"
commands:
start_server:
type: terminal
terminal: Server
command: npm run dev
description: Start development server
rebuild_container:
type: vscodeCommand
command: remote-containers.rebuildContainer
description: Rebuild dev container
menu:
- label: Development
icon: "$(rocket)"
children:
- label: Start Server
icon: "$(play)"
ref: start_server
- label: Run Tests
icon: "$(beaker)"
type: terminal
command: npm test
- label: Container
icon: "$(package)"
children:
- label: Rebuild
icon: "$(refresh)"
ref: rebuild_container
- label: Troubleshooting
icon: "$(tools)"
children:
- label: Server Issues
children:
- label: Restart Server
ref: start_server # Same command, different context| Command | Description | Shortcut |
|---|---|---|
TaskPilot: Show Menu |
Open the task menu | Cmd+Shift+T / Ctrl+Shift+T |
TaskPilot: Reload Configuration |
Reload YAML config | - |
Execute commands in VS Code's integrated terminal:
- label: Build Project
type: terminal
command: npm run build
terminal: Build # Optional: named terminal
cwd: ./packages/app # Optional: working directoryExecute shell commands inside TaskPilot and wait for completion before the next action:
- label: Prepare
type: shellCommand
command: ./scripts/prepare.sh
cwd: ./packages/app # Optional: working directoryExecute VS Code commands:
- label: Format Document
type: vscodeCommand
command: editor.action.formatDocument
- label: Open Folder
type: vscodeCommand
command: vscode.openFolder
args:
- /path/to/folderExecute tasks defined in tasks.json:
- label: Run Build Task
type: task
command: build # Task name from tasks.jsonOpen a folder in Dev Container (requires Remote - Containers extension):
- label: Open in Container
type: openInDevContainer
path: /home/user/project # フルパス推奨(~は非推奨)、.devcontainerを含むディレクトリを指定Open a folder via SSH (requires Remote - SSH extension):
- label: Open Remote Project
type: openRemoteSSH
path: /home/user/project
host: my-server # Host from ~/.ssh/configOpen a folder via Remote Tunnel (requires Remote - Tunnels extension):
- label: Connect to Win11
type: openRemoteTunnel
path: /home/user/project # フルパス推奨(~は非推奨)
tunnelName: my-tunnel # GitHub認証済みのトンネル名- VS Code 1.85.0 or higher
- Node.js 18.x or higher (for development)
MIT License - see LICENSE for details.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request