A small, opinionated CLI to quickly start development projects composed of multiple process groups (frontend, backend, workers, etc.). vunat-cli reads a JSON-based project registry and can:
- Start groups of commands and supervise their lifecycle
- Stream stdout/stderr prefixed with the group name
- Open or create the per-user config (
~/.vunat/config.json) - Provide a simple command registry and help output
This repository contains a compact, testable Go implementation with clear separation of concerns: config manager, launcher, runner, and CLI registry.
cmd/vunat— CLI entrypointinternal/cli— registry + command implementationsinternal/config— filesystem-backed config managerinternal/projects— config loader / project registryinternal/runner— process supervision and output streaminginternal/launcher— OS-aware opener for files/URLs
- Example config:
config.example.json(in the repo root)
Example snippet:
{
"projects": {
"gradepoint": [
{
"name": "frontend",
"absolutePath": "",
"commands": ["npm run dev"]
},
{
"name": "backend",
"absolutePath": "",
"commands": [
"go run ./cmd/api/main.go",
"go run ./cmd/scheduler/main.go",
"npx prisma@6 studio -y"
]
}
]
}
}- Unix / macOS:
./build.sh- Windows:
build.batYou can also run in development mode with the Go toolchain:
go run ./cmd/vunat helpTo be able to call the tool as vunat from any shell, put the compiled binary in a small per-user bin directory and add it to your PATH. This README recommends ~/.vunat as the install directory so it
is colocated with the config.
- Build the binaries using the included scripts (or build for your OS with
go build). - Move or copy the appropriate binary into
~/.vunatand name itvunat.
Example (Linux/macOS):
# create install dir
mkdir -p "$HOME/.vunat"
# move the built binary into the install dir and make executable
mv ./bin/vunat-linux-amd64 "$HOME/.vunat/vunat"
chmod +x "$HOME/.vunat/vunat"Example (Windows PowerShell):
# create install dir (in %USERPROFILE%)
New-Item -ItemType Directory -Path "$env:USERPROFILE\.vunat" -Force
# move the built binary (example)
Move-Item .\bin\vunat-windows-amd64.exe "$env:USERPROFILE\.vunat\vunat.exe"- Add
~/.vunat(or%USERPROFILE%\.vunaton Windows) to your PATH so that the shell can findvunat.
Temporarily (current shell session) — Unix/macOS:
export PATH="$HOME/.vunat:$PATH"Persistently (add to ~/.bashrc, ~/.zshrc, or other shell rc):
echo 'export PATH
="$HOME/.vunat:$PATH"' >> ~/.bashrc
# then reload or restart your shell:
source ~/.bashrcWindows (PowerShell, persistent):
# Add to user PATH using setx (may require reopening terminals)
setx PATH "$env:USERPROFILE\.vunat;$env:PATH"After the directory is in your PATH you can run the CLI directly:
vunat help
vunat list
vunat start <project_name>
vunat config- Show help (dynamic, generated from registered commands):
vunat help- List registered projects:
vunat list- Start a project:
vunat start <project_name>- Open or create the config file:
vunat config- The per-user configuration file is
~/.vunat/config.json. - Use the provided
config.example.jsonas a template. - The config format:
- Top-level
projectsobject - Each key under
projectsis a project name that maps to an array of command groups. - A command group contains:
name— human-readable group nameabsolutePath— directory where the commands will run (empty allowed)commands— array of shell command strings
- Top-level
- If the
EDITORenvironment variable is set,vunat configwill invoke that editor and wait for it to exit. - Otherwise,
vunat configuses the platform default opener:- Windows:
cmd /c start "" <path> - macOS:
open <path> - Linux:
xdg-open <path>
- Windows:
-
CLI registry (
internal/cli)- Small
Commandinterface withName(),Run(args), andHelp(). Registryholds commands and dispatches based onos.Args.
- Small
-
Config manager (
internal/config)- Exposes a
Managerinterface andFSManagerimplementation that ensures config directory/file exist and reads/writes the JSON file.
- Exposes a
-
Projects loader (
internal/projects)- Reads
~/.vunat/config.json, unmarshals into typed structs, and exposesGetandGetAllhelpers.
- Reads
-
Runner (process supervision) (
internal/runner)- Starts groups sequentially and commands in a group concurrently.
- Streams each process' stdout/stderr prefixed with the group name.
- Cancels remaining processes on first failure and attempts to kill already-started children.
-
Launcher (
internal/launcher)- Provides
OSLauncherto open files/URLs using platform-specific commands, with an option to wait for the opener to exit.
- Provides