A process orchestrator that runs multiple jobs, manages their dependencies, and streams live output to a native webview terminal UI.
Vortex lets you define a set of tasks (called jobs) in a simple YAML file and run them all at once. Each job gets its own live terminal panel in a desktop window, so you can watch logs, errors, and output in real time.
Use it when you need to:
- Start multiple services during development (API server, frontend, database, etc.)
- Run build steps in order (lint → build → test → deploy)
- Automate multi-step workflows with real-time visibility
Vortex config files use the .vortex extension with YAML syntax:
# dev.vortex
name: dev
jobs:
- id: server
label: API Server
command: go run ./cmd/server
- id: frontend
label: Frontend
command: npm run dev
- id: test
label: Tests
command: go test ./...
needs: [server]vortex run dev.vortexThat's it. Vortex opens a native window with a terminal panel for each job, streaming output in real time.
Shorthand: you can omit the .vortex extension
vortex run devVortex looks for dev.vortex in the current directory.
vortex init
vortex init my-appThis creates a .vortex file with a schema comment for editor autocompletion.
- Dependency-aware execution — jobs declare what they
needs, and Vortex runs them in the right order - Live terminal output — each job gets its own terminal panel with real-time stdout/stderr
- Clickable links — URLs open in your browser, file paths open in your editor
- Native desktop window — runs as a standalone app (not in the browser)
- Job groups — organize related jobs under collapsible headings
- Named instances — multiple configs can run side by side without conflicts
- Persistent jobs — long-running services survive config reloads with
restart: false
How clickable links work
When you click an http:// or https:// link in the terminal, Vortex opens it in a browser. The browser is resolved in this order:
VORTEX_BROWSERenvironment variablevortex config set browser "firefox"settingBROWSERenvironment variable- OS default browser
When you click a file path, Vortex opens it in an editor:
VORTEX_EDITORenvironment variablevortex config set editor "code"settingVISUALenvironment variableEDITORenvironment variable- OS default file opener
Every .vortex file has two required fields: name and jobs.
name: my-project # identifies this running instance
jobs: # list of tasks to run
- id: build
command: go build ./...| Field | Required | Description |
|---|---|---|
id |
Yes | Unique name for this job. Used in needs references. |
command |
Yes | What to run. A direct command, or script text when shell is set. |
label |
No | Display name in the UI. Defaults to id. |
shell |
No | Interpreter for the command (e.g. bash, node, python). |
use |
No | Connect to a shared runtime (node, bun, deno, csharp, go). |
group |
No | Visual grouping in the UI. Jobs with the same group appear together. |
needs |
No | List of job IDs that must finish before this job starts. |
if |
No | When to run: success (default), failure, or always. |
restart |
No | Set to false to keep long-running jobs alive across config reloads. |
When shell is omitted, Vortex splits command into words and runs it directly.
When shell is set, Vortex passes command as a script to that interpreter.
Supported shells: bash, sh, zsh, fish, cmd, powershell, pwsh, python, python3, node, bun, deno, csharp, go
OS-specific commands and shells
Both shell and command can be objects with OS-specific values:
jobs:
- id: cross-platform
shell:
default: bash
windows: pwsh
command:
default: echo hello from vortex
windows: Write-Host hello from vortexSupported keys: darwin, linux, windows, default
Use needs to control execution order:
jobs:
- id: build
command: go build ./...
- id: test
command: go test ./...
needs: [build] # waits for build to finish
- id: deploy
command: ./deploy.sh
needs: [test] # waits for test to finish
if: success # only runs if test succeededThe if field controls when a dependent job runs:
success(default) — run only if all dependencies succeededfailure— run only if any dependency failedalways— run regardless of dependency outcome
Organize related jobs visually:
jobs:
- id: build
command: go build ./...
group: ci
- id: test
command: go test ./...
group: ci
- id: server
command: go run ./cmd/server
group: services| Field | Type | Description |
|---|---|---|
name |
string |
Required. Unique instance name. |
node |
object |
Shared Node.js runtime. See JavaScript Runtimes Guide. |
bun |
object |
Shared Bun runtime. See JavaScript Runtimes Guide. |
deno |
object |
Shared Deno runtime. See JavaScript Runtimes Guide. |
csharp |
object |
Shared C# runtime. See C# Runtime Guide. |
go |
object |
Shared Go runtime. See Go Runtime Guide. |
jobs |
Job[] |
Required. List of jobs to run. |
Shared runtimes let you define imports, variables, and helper functions once and reuse them across multiple jobs. This avoids repeating setup code in every job.
Vortex supports five runtime environments:
| Runtime | Guide | TypeScript |
|---|---|---|
| Node | JavaScript Runtimes Guide | Yes (via esbuild) |
| Bun | JavaScript Runtimes Guide | Yes (native) |
| Deno | JavaScript Runtimes Guide | Yes (native) |
| C# | C# Runtime Guide | — |
| Go | Go Runtime Guide | — |
name: dev
node:
vars:
apiBase: http://localhost:3000
functions:
logBanner: |
export function logBanner(text) {
console.log(`== ${text} ==`)
}
jobs:
- id: check-api
shell: node
use: node
command: |
logBanner(`Checking ${apiBase}`)
const resp = await fetch(apiBase)
console.log(resp.status)Both logBanner and apiBase are available in every job that has use: node.
How shared runtimes work under the hood
When a job uses a shared runtime, Vortex generates wrapper files in ~/.cache/vortex/{runtime}-runtime/:
- JavaScript (Node/Bun/Deno): generates ESM
.mjs(or.mtsfor TypeScript) modules that re-export all shared code, then runs the wrapper with the appropriate runtime binary. - C#: generates a .NET project with a
Shared.csclass and aProgram.csper job, then runs viadotnet run. - Go: generates a Go project with
shared.goandmain.goper job, then runs viago run ..
If you change a runtime block and reload the config, all opted-in jobs restart automatically to pick up the changes — even persistent jobs with restart: false.
For full documentation on each runtime, see the linked guides above.
vortex run dev.vortex # run a config file
vortex run dev # shorthand (finds dev.vortex)
vortex run --headless dev # run without opening a windowvortex init # create a template .vortex file
vortex init my-app # create my-app.vortex
vortex init --force # overwrite existing filevortex instance list # show running instances
vortex instance quit dev # stop an instance
vortex instance kill dev # kill child processes only
vortex instance rerun dev build # rerun a job and its dependents
vortex instance show dev # open the native window
vortex instance hide dev # close the window (keep running)vortex config list # show all settings
vortex config set browser firefox
vortex config set editor code
vortex config get editor
vortex config unset browservortex docs # open built-in documentation
vortex docs --force # regenerate docs
vortex upgrade # upgrade to latest release
vortex upgrade --check # check for updates without installing
vortex version # print version
vortex help # show helpAll CLI flags
| Flag | Applies To | Description |
|---|---|---|
--config |
run, instance quit/kill/show/hide |
Path to a .vortex config file |
--cwd |
run |
Working directory for all jobs (defaults to config file directory) |
--force |
init, docs |
Overwrite existing files |
--port |
run |
Override the HTTP port |
--headless |
run |
Run without opening a native window |
--dev |
run |
Development mode: skip webview, use browser at localhost |
--json |
instance list |
Output as JSON |
--prune |
instance list |
Remove stale instances |
--no-open |
docs |
Generate docs without opening browser |
Instance management details
Restarting: running vortex run with a config that has the same name as an already-running instance restarts it in place.
Ports: Vortex derives both the handoff port and UI port from the config name, so different named configs run simultaneously without port conflicts.
instance list output includes:
mode:dev,headless, orwindowedui:open,hidden, ornonestarted/updated/last_controltimestampsgeneration: orchestrator restart countreachable(in--json): whether the instance API responded
instance list --prune: removes stale registry entries and makes a best-effort attempt to terminate orphaned processes.
show / hide: show surfaces the native webview for headless instances. hide closes the window without stopping jobs. These only apply to non---dev instances.
Upgrading details
vortex upgrade downloads the latest GitHub release for your OS/architecture and installs it to:
- macOS/Linux:
~/.local/bin/vortex - Windows:
%LOCALAPPDATA%\Programs\Vortex\vortex.exe
The upgrade process:
- Downloads the release binary and verifies its SHA-256 checksum
- Stops a running instance before replacing the binary
- On macOS: sets executable permissions and removes the quarantine attribute
- Attempts to add the install directory to your PATH
After upgrading, open a new terminal session so the updated PATH takes effect.
For autocompletion in .vortex files, add this to your VS Code settings:
{
"files.associations": {
"*.vortex": "yaml"
},
"yaml.schemas": {
"https://raw.githubusercontent.com/arcmantle/vortex/master/schemas/vortex.schema.json": [
"*.vortex"
]
}
}Pinning to a specific version
To avoid breaking changes from schema updates, pin to a release tag:
{
"yaml.schemas": {
"https://raw.githubusercontent.com/arcmantle/vortex/v1.0.10/schemas/vortex.schema.json": [
"*.vortex"
]
}
}For SchemaStore submission, a ready-to-submit catalog entry is at schemas/vortex.schemastore-entry.json.
Prerequisites
- Go 1.24+
- Node.js 20+ / pnpm
- C compiler (CGo is required for the webview binding)
- Windows: MSVC or MinGW — WebView2 headers are bundled
- macOS: Xcode command-line tools
- Linux:
libwebkit2gtk-4.1-dev
# Start the Go server + Vite dev server
go run ./cmd/vortex --dev --config mock/dev.vortex &
cd cmd/vortex-ui/web && pnpm install && pnpm devThe Vite dev server proxies API calls to the Go backend. Use --dev to skip the native window and work in the browser at http://localhost:5173.
# Build the frontend
cd cmd/vortex-ui/web && pnpm install && pnpm build && cd ../../..
# Build the Go binary with embedded UI
go build -tags embed_ui -o vortex ./cmd/vortexWindows and macOS notes
On Windows, add -ldflags "-H=windowsgui" to build a GUI binary that doesn't keep a console window open:
go build -tags embed_ui -ldflags "-H=windowsgui" -o vortex.exe ./cmd/vortexCLI commands (help, version, config, etc.) still work from the terminal — Vortex reattaches to the parent console when needed.
If you download the macOS release binary from GitHub, make it executable and remove the quarantine attribute:
chmod +x ./vortex-darwin-arm64
xattr -d com.apple.quarantine ./vortex-darwin-arm64 2>/dev/null || trueThe embed_ui build tag embeds the compiled frontend into the binary. Without it, the UI is not served (useful for dev mode).
Project structure and data flow
cmd/vortex/ CLI entry point, UI embedding
cmd/vortex-ui/web/ Lit + TypeScript frontend (xterm.js terminals)
internal/
config/ Config loading, validation, runtime code generation
instance/ Named-instance lock, port derivation, handoff registry
orchestrator/ Dependency-aware job graph execution
terminal/ Process lifecycle, output buffering, ring buffer
server/ HTTP API, SSE streaming, static file serving
webview/ Platform-specific native webview wrappers
Data flow: Orchestrator → Terminal (captures stdout/stderr into ring buffer) → SSE endpoint → xterm.js in the webview.
MIT