A VSCode extension for managing multiple projects with unified Git operations, per-project command batching (ProjectsCmd), one-click workspace-root quick commands (ShortCutCmd), Python text transforms (Pyt), lightweight command group runs (Batch) and a visual workflow engine (Flow).

Features
- Auto-scan workspace to discover Git repositories (configurable depth)
- Batch Git operations across multiple projects at once (Pull / Commit / Branch / Push)
- ProjectsCmd — run custom shell commands against every selected Git project, in each project's own directory
- Project row quick actions — configurable buttons on the right side of each project row (Git / ProjectsCmd) that run a command in that project's directory, e.g. open the folder in Explorer or open the project's GitHub page
- ShortCutCmd — one-click quick commands that run once in the workspace root directory, ideal for frequently used scripts
- Command cancel + running indicator — every command row (ProjectsCmd / ShortCutCmd / Pyt) has a cancel button that terminates the running process tree; while executing, the whole row background pulses with a translucent blue tint (text stays high-contrast via text shadow) and returns to normal when the run finishes or is cancelled
- Shell-typed commands — every command is stored with its shell type (Git Bash / CMD / PowerShell / WSL); the shell selector filters the command list by type, and newly created commands are stamped with the currently selected type. Commands created before shell typing exist are treated as Git Bash
- Flow (visual workflows) — build, run and monitor node-based workflows (commands, conditions, forks, manual confirm, notifications) in a dedicated main-editor Flow Editor panel; command / condition / notify nodes carry a per-node Shell property persisted with the workflow
- Batch command groups — lightweight editable command lists (inline edit, drag-to-reorder, serial/parallel mode) that run through the same workflow engine; groups and canvas flows share one storage domain
- Multi-line script support with shared context variables across lines
- Per-line execution log in
$ command => executed result: output format
- Project list collapse/expand to maximize working area
- i18n (English / 中文)
Prerequisites
General
- VSCode
^1.120.0
- A workspace folder containing multiple project subdirectories
Git Tab (Batch Git Operations)
Git operations rely on the local git CLI:
- Install Git for your OS:
- Windows: git-scm.com (includes Git Bash)
- macOS:
brew install git
- Linux:
sudo apt install git / sudo dnf install git
- Add to PATH — verify in an integrated terminal:
git --version
- Add
bash.exe to PATH (Windows) — Git Tab internally invokes bash. With Git for Windows installed, ensure this path is on your system PATH:
C:\Program Files\Git\bin
Verify:
bash --version
- Configure SSH key — all Git operations use SSH remotes. Set up an SSH key for your Git host (GitHub / GitLab / Gitea / self-hosted):
# Generate a key (no passphrase for automation, or use ssh-agent)
ssh-keygen -t ed25519 -C "your_email@example.com"
# Start ssh-agent and add the key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# Copy the public key and add it to your Git host
cat ~/.ssh/id_ed25519.pub
Verify the SSH connection works for your host:
ssh -T git@github.com # GitHub
ssh -T git@gitlab.com # GitLab
Your project remote URLs must use the SSH form (e.g. git@github.com:owner/repo.git), not HTTPS.
ProjectsCmd Tab
Custom commands run through your selected shell:
- Git Bash (default): requires
bash.exe on PATH (same as Git Tab above)
- CMD: built-in on Windows
- PowerShell: built-in on Windows
- WSL: requires WSL installed on Windows
ShortCutCmd uses the same shells with the same requirements.
Python Text Transform (Pyt Tab)
The Python text-transformation feature requires Python 3:
- Install Python — python.org or
winget install Python.Python.3
- Add to PATH — verify:
python --version
- Custom Python text-transformation scripts will be invoked via the
python command.
Tabs
Git Tab
Batch Git operations across selected projects.
| Button |
Action |
| 📥 Pull |
git pull on each selected project |
| ✓ Commit |
Prompt for commit message, then git add . && git commit -m "..." |
| 📊 Change |
Show working-tree change count per project |
| 🌿 Branch |
Switch to an existing branch, or create a new branch across all selected projects |
| 📤 Push |
git push on each selected project |
- Select All checkbox — bulk select/deselect all Git projects
- Selected N counter — shows the number of currently selected projects
- ▼/▶ button — collapse or expand the project list
- Each project row shows: checkbox, name, current branch, change count
- Quick-action buttons on the right of each project row (shared with ProjectsCmd, see Project Row Quick Actions) — click to run a configured command (open folder, open GitHub page, ...) directly on that project
ProjectsCmd Tab
Run custom shell commands against multiple Git projects at once. The command runs once per selected project, inside that project's own directory.
Project Row Quick Actions
The shared project list on the Git and ProjectsCmd tabs renders configurable action buttons on the right side of every project row. Each button runs its configured command in that project's own directory — the same button on different rows targets different projects (e.g. the "GitHub" button on the backend row opens the backend repo, on the frontend row the frontend repo).
- Default commands (seeded automatically on first run, fully editable/removable afterwards):
- Open Folder —
explorer "${projectPath}": opens the project directory in Windows Explorer
- GitHub —
start ${projectRemoteUrl}: opens the project's GitHub repository page in the default browser. The origin remote URL is read with git remote get-url origin and normalized from SSH/scp form (git@github.com:owner/repo.git) to an https:// browse URL
- Manage in the Set tab — the Project Row Commands editor lists every command with its Alias (button text), Command content and Tip (hover description). Add, edit or delete entries; every change is saved immediately and the buttons on all project rows refresh at once. Buttons are rendered in insertion order (no sorting)
- Hover tips — hovering a row button shows
alias — tip, e.g. GitHub — Open this project GitHub repository page in browser
- Placeholders — substituted per project before execution:
${projectPath}, ${projectName}, ${projectBranch} and ${projectRemoteUrl}; global ${var} parameters from the JSON tab are also supported
- Execution — runs through the shell currently selected on the ProjectsCmd tab; clicking a button executes immediately (no confirmation dialog, no cancel) and waits for the result. All command output and the final status are written to the Logs panel, tagged with the project name
- Stored under
settings.projectRowCommands in .multi-project-tool/config.json
ShortCutCmd Tab
One-click quick commands that run once, in the workspace root directory (the first workspace folder). Designed for frequently used scripts that are not tied to a specific Git project — cache cleanup, environment checks, one-off maintenance scripts, etc.
- No project selection — click ▶ on a command and it runs immediately; there is no project list on this tab
- Fixed working directory — always the workspace root. If a command needs another directory,
cd inside the script itself
- Shell selector (type filter) — works exactly like ProjectsCmd, but keeps its own independent selection; commands are stamped with the type selected at creation time
- Same tree layout — categories, commands, drag & drop, rename, delete — shared with ProjectsCmd
- Editor Run button — try the editor content directly without saving first
- Cancel running command — same blinking row + ■ cancel button as ProjectsCmd; terminates the workspace-root execution immediately
- Same per-line log format as the other tabs
ProjectsCmd vs ShortCutCmd
|
ProjectsCmd |
ShortCutCmd |
| Execution target |
Every selected Git project, in each project's own directory |
Fixed workspace root directory, executed once |
| Typical use |
Build / test / deploy scripts repeated across many repos |
Frequently used quick scripts not tied to any project |
| Project selection |
Required (Select All / per-project checkboxes) |
Not applicable — no project list |
| Shell type selection |
Independent, persisted per tab |
Independent, persisted per tab |
| Command data |
customCommandTree in .multi-project-tool/config.json |
.multi-project-tool/shortcutCommands.json |
| Data compatibility |
The two command sets are separate and do not mix |
— |
Rule of thumb: if the command must run per project → ProjectsCmd; if it runs once for the workspace → ShortCutCmd.
JSON Tab
Manage global parameters and tab visibility.
- Edit JSON parameters used for
${var} substitution in custom commands
- Show/hide individual tabs (Git / Cmd / Pyt / JSON)
- Reset to defaults
Pyt Tab
Python-based text transformation utilities. Requires python on PATH (see Prerequisites).
- Command rows support the same run/cancel + executing blink interaction as the other tabs; cancelling kills the
python child process
- Transform logs (success / failure / cancel) are kept host-side and restored after webview reload
Batch Tab
Lightweight command-group runner for "just a list of commands" scenarios — no canvas, no node wiring. Every group is a list-style workflow stored in the same domain as Flow workflows (kind: 'batch' in workbench.json); legacy standalone batch-group data is migrated automatically on first load.
- Group management — group dropdown to switch, rename inline, add via input modal, delete with confirmation (all groups can be deleted; an empty state is shown). Two starter groups (Java Build, Quick Check) are seeded for new workspaces
- List editing — inline command inputs, drag & drop reordering, add/remove rows; every edit rebuilds the underlying node graph (chain for serial, fork/join for parallel) and persists immediately through the same save path as Flow
- Mode switch — Serial runs commands one after another; Parallel runs them concurrently (fork/join), switchable at any time
- Run feedback in place — each row shows a live status pill (⏳ pending / ↻ running / ✓ success / ✗ failed / ↓ skipped) and per-row duration, plus a real-time execution log below; no need to open the Flow Editor
- Run-level shell — the panel's shell selector (Git Bash / CMD / PowerShell / WSL) applies to all commands in the group
- Convert to Flow — one click sends the group's node graph to the Flow Editor canvas for advanced editing (branches, conditions, notifications...); batch runs and Flow runs share the same history
Flow Tab (Workflow Editor)
Visual workflow canvas opened in a dedicated main-editor panel (the sidebar Flow tab keeps only the list and entry buttons).
- Node palette — start (scheduled), command (shell), condition, fork/join (parallel branches), confirm (manual approval), notify, ref (reference saved commands from ProjectsCmd / ShortCutCmd / Pyt / Git), vscode (execute any VSCode command registered by other extensions)
- Per-node shell — command, condition and notify(command) nodes expose a Shell selector in their properties panel (Git Bash / CMD / PowerShell / WSL, default = inherit the run-level shell). The choice is persisted with the workflow, so a node set to PowerShell today still runs under PowerShell after reopening. Nodes without an explicit shell inherit: Flow runs use the global default shell (Set tab), Batch runs use the batch panel's selector
- Run monitoring — live node states, logs with filter, failed/skipped counters, duration; run detail is a read-only replay
- Background runs — switching to another flow while a run is active does not stop it: running and paused runs stay in the RUNNING group, and the canvas remains fully editable for other flows. Clicking the run in the RUNNING group returns to its monitor view
- Node actions bar — floats above the target node: confirm nodes offer continue/cancel/pause; failed-paused nodes offer resume (with command editing before retry) or cancel
- Log export — the monitor's export button opens the full run log in a new editor
- History — every finished run is archived (result, duration, per-node outcomes); entries can be deleted individually or cleared
Recent Updates
Summary of the most recent changes:
- Batch tab rebuilt on the workflow data domain — batch groups are no longer a separate data structure: each group is stored as a
kind: 'batch' workflow in workbench.json, right alongside canvas workflows (legacy batchGroups data is migrated automatically on first load and the old field is dropped). All group edits — add/reorder commands, rename, serial↔parallel switch — rebuild the underlying node graph and save through the exact same path as the Flow Editor; batch runs, the run engine and history are unchanged and shared with Flow. The Flow sidebar list hides batch workflows (they belong to the Batch panel), and the Quick Launcher still lists them. Also fixed: the + group button never worked because native prompt() is blocked inside webviews — replaced with a custom input modal (Enter/Esc supported); deleting a group now asks for confirmation, and deleting the last group is allowed
- Per-node shell for Flow — the Flow Editor toolbar's run-level shell dropdown has been removed; command / condition / notify(command) nodes now carry their own Shell property in the properties panel (Git Bash / CMD / PowerShell / WSL, default = inherit run-level), persisted with the workflow. This also fixes a hidden defect: the old toolbar choice was never saved, so a workflow run with PowerShell today silently fell back to the default shell after reopening the panel. Nodes without an explicit shell fall back to the global default shell (Flow runs) or the batch panel's selector (Batch runs); existing workflows need no migration
- Project row quick actions (new) — every project row on the Git / ProjectsCmd tabs now has configurable buttons on its right side that run a command in that project's directory. Two defaults are seeded on first run: Open Folder (Windows Explorer) and GitHub (opens the project's
origin remote, normalized to an https:// browse URL, in the browser). Manage the list in the Set tab's Project Row Commands editor — alias / command / hover tip per entry, add-edit-delete with immediate persistence and instant button refresh, insertion order preserved. Placeholders ${projectPath}, ${projectName}, ${projectBranch}, ${projectRemoteUrl} plus global ${var} parameters are substituted per project; execution output and result go to the Logs panel
- VSCode command node (new) — the Flow node palette gains a VSCode Command node type that invokes any command registered by other extensions via
vscode.commands.executeCommand, so workflows can drive other plugins' features (run task providers, format documents, trigger testing tools, open views, etc.). The node's Command ID field offers autocomplete from all currently registered command IDs; arguments accept a JSON array (spread as multiple parameters, e.g. ["src/main.ts", true]) or plain text (single string parameter), with ${var} substitution from common parameters. A missing/throwing command fails the node and honors the node's fail policy (stop / skip / retry once); command return values are serialized into the workflow log
- Enhanced executing blink — the executing indicator now pulses the entire row background with a ~1/3-opacity translucent blue tint (previously only a barely-visible edge tint), so it is clearly noticeable. Text readability is preserved during the pulse: the alias and preview text switch to the high-contrast text color with a dark text shadow, and the row border glows in sync. The style restores automatically on completion or cancellation
- Merged with main (multi-run workflows + cancel coexistence) — the command cancel/blink feature was re-integrated on top of main's multi-run architecture:
executeShellCommand regained its runKey tracking parameter (register/unregister cancel handles, cleanup on close/error, process-tree kill on timeout), cancelled runs return a cancelled result that aborts the remaining projects, and the webview restores blink/cancel state via cmdRunStateSync after reloads — while main's multi paused-run workflow engine (_activeRun / _pausedRuns) remains fully intact
- Command cancel + executing blink — all command rows in ProjectsCmd, ShortCutCmd and Pyt show a ■ cancel button while executing; the host tracks every active run (
tab:commandId) and terminates the whole process tree on cancel (Windows taskkill /T /F, POSIX SIGTERM). Re-running the same command while it is executing is blocked
- Flow switching during active runs — running/paused workflows no longer lock the whole Flow tab. Runs continue in the background and stay listed in the RUNNING group; you can freely switch to, edit and run other flows, and even start a new run when a previous one is failed-paused (the old instance is archived to history as
failed)
- Templates merged into workflows — the separate TEMPLATES group is gone; templates are regular workflows, editable in place and deletable with a confirmation modal (built-ins can be hidden)
- Node actions bar — manual confirm (continue/cancel/pause) and failed-paused resume/cancel, including editing a failed node's command before retrying; paused confirm runs stay in the RUNNING list and restore their actions when reopened
- Fork parallelism — fork branches now execute truly concurrently, with
maxParallel decoupled from batch concurrency
- Flow Editor panel — the flow canvas moved from the sidebar to a main-editor WebviewPanel; the sidebar keeps the list and entry buttons
- Log export & history management — monitor log export button; history delete/clear-all now use a custom confirm modal (works inside webviews)
Configuration
All settings live under the multi-project-tool.* namespace in VSCode Settings:
| Key |
Default |
Description |
showJsonTab |
true |
Show JSON Tab |
showGitTab |
true |
Show Git Tab |
gitDefaultBranch |
main |
Default branch name |
projectScanDepth |
3 |
Max depth to scan for Git projects |
defaultShell |
git-bash |
Shell for custom commands (git-bash / cmd / powershell / wsl) |
autoRefresh |
true |
Auto-refresh project list on filesystem changes |
logRetention |
50 |
Max log entries kept |
concurrency |
1 |
Number of projects to execute commands concurrently (1-10) |
commandTimeout |
300 |
Command execution timeout in seconds |
customCommands |
[] |
Saved custom commands (legacy, migrated automatically) |
envVariables |
[] |
Environment variables injected during command execution |
commonParameters |
{} |
Global JSON parameters for command variable substitution |
Workspace-level data (per workspace folder, under .multi-project-tool/):
| File |
Content |
config.json |
Settings, ProjectsCmd command tree, project row quick actions, environment variables |
shortcutCommands.json |
ShortCutCmd command tree |
customPythonTxt.json |
Python text-transform command tree |
workbench.json |
Workbench data: Flow workflows and Batch groups (kind: 'batch', auto-migrated from the legacy batchGroups field), templates, run history, checklist, hidden tabs |
Usage Example
- Open a workspace folder containing several Git projects:
my-workspace/
├── backend/ (.git)
├── frontend/ (.git)
└── docs/ (.git)
- Click the Multi-Project Tool icon in the Activity Bar.
- Git Tab → check the projects you want to update → click 📥 Pull. All selected repos pull in one action.
- ProjectsCmd Tab → pick the shell type (e.g. Git Bash) → + Add → alias
deploy-all, content:
npm run build
npm run deploy
Save → the command is stored as a Git Bash command → select target projects → click ▶. Each selected project runs the script in its own directory, with shared context across lines.
- ShortCutCmd Tab → + Add → alias
clean-all-cache, content:
npm cache clean --force
rm -rf node_modules/.cache
Save → click ▶. The script runs once in my-workspace/ (the workspace root) — no project selection needed.
- Project row buttons — every project row has quick-action buttons on its right (defaults: Open Folder, GitHub). Hover a button to see its tip (e.g.
GitHub — Open this project GitHub repository page in browser); click it and the command runs in that project's directory — e.g. the GitHub button on the backend row opens https://github.com/your-org/backend. Add your own buttons in the Set tab → Project Row Commands editor.
- Batch Tab — pick the Quick Check group → edit commands inline (or drag to reorder) → switch mode to Parallel → click ▶. Each row gets a live status pill and duration while the log streams below; click To Flow afterwards to keep editing the group as a canvas workflow.
Troubleshooting
| Symptom |
Fix |
[bash.exe] command not found |
Add C:\Program Files\Git\bin to system PATH, then restart VSCode |
| Git operations fail with permission denied |
Configure SSH key for your Git host and use SSH remote URLs |
| Projects not listed |
Check projectScanDepth and that subfolders are Git repos |
| Custom commands silently fail |
Switch to the selected shell and run the script manually; check the per-line log |
python commands fail |
Install Python 3 and ensure python --version works in an integrated terminal |
| Config changes don't take effect |
Reload the VSCode window (Ctrl+R / Cmd+R) |
| Command list looks empty after switching shell type |
The shell selector is a type filter — commands of other types are hidden, not deleted. Switch back to their type to see them |
| Old commands all appear under Git Bash |
Commands created before shell typing were migrated to the Git Bash type; edit and recreate them under another type if needed |
| ShortCutCmd runs in the wrong directory |
It always runs in the workspace root; add cd /your/path as the first line of the script |
| GitHub row button fails with No git remote origin URL |
The project has no origin remote. Add one (git remote add origin <url>) or edit/remove the button in the Set tab → Project Row Commands |
Development
npm install
npm run compile # build TypeScript
npm run watch # watch mode
npm test # run the unit/integration test suites
Press F5 in VSCode to launch an Extension Development Host with the extension loaded.
Package & Publish
# Local package
vsce package --no-git-tag-version -o multi-project-tool-1.0.7.vsix
# Publish to Marketplace (requires PAT)
vsce login ghema
vsce publish
CI builds run automatically via GitHub Actions — push a v* tag to create a Release with the built VSIX attached.
License
MIT
| |