A process orchestrator that runs multiple jobs, manages their dependencies, and streams live output to a native webview terminal UI.
Download and run the installer for your platform from GitHub Releases:
macOS:
Download the DMG from Releases, open it, and drag Vortex to your Applications folder. On first launch, Vortex will install the required binaries automatically.
If macOS says Vortex is damaged or blocks it with a Gatekeeper warning, remove the quarantine attribute and try again:
xattr -dr com.apple.quarantine /Applications/Vortex.appWindows:
irm https://github.com/arcmantle/vortex/releases/latest/download/vortex-setup-windows-amd64.exe -OutFile vortex-setup.exe
.\vortex-setup.exeLinux:
curl -fsSL https://github.com/arcmantle/vortex/releases/latest/download/vortex-setup-linux-amd64 -o vortex-setup
chmod +x vortex-setup
./vortex-setupUpdate an existing install:
vortex upgradeVortex 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 (UI is embedded by default)
go build -o vortex-host ./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 -ldflags "-H=windowsgui" -o vortex-host.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 UI is embedded by default. To build without it (e.g. for the two-stage release process), use -tags no_embed_ui.
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