Skip to content

runy

Kubernetes-style config for your dev environment

Declare what a workspace needs in YAML: dev servers, ports, worktrees, watchers. The runy daemon brings them to the state you declared and keeps them there.

Get startedInstall

⌄acme
›api3
api
api
worker
›db2
data
postgres
›preview1
preview
⌄web2
web
web
OutputOverview@stdout, @stderr, field: value
17:37:30Reloading workspace
17:37:31web/port/web: Resolved · 3010 → http://web.localhost
17:37:32web/process/web: starting · pid 48213
17:37:34web/process/web: running healthy

Switch a namespace on and its resources come up. preview checks out a worktree, runs its hook and loads the workspace inside it, nested under acme.

A workspace, run like a cluster

A cluster declares what should run and a controller makes it so. runy borrows that shape for the dev environment: resources in YAML documents, a daemon that reconciles them, status you can read.

Declare

A .runy/ folder is a namespace. Each YAML document in it is a resource: a kind, a name and a spec. A spec can read what another resource has published.

kind: process
name: web
spec:
  cmd: pnpm
  args:
    - dev
    - --port
    - ${ port.web.status.value }
  restart: { on: failure }

Reconcile

The daemon renders every document, holds one back until what it reads exists, starts what is missing and restarts what fails its health check.

port/webResolved3010
process/webPendingneeds port.web
process/webResolvedrunning healthy

Observe

Every resource publishes a condition and a status. runy ps lists them, the console shows the tree, and each line of output is kept in a journal.

{
  "state": "running",
  "pid": 48213,
  "healthy": true,
  "restarts": 0
}

Every line of output is kept

A process's output goes to a SQLite journal the console streams. The same query filters what is stored and what arrives next.

How journals work
OutputOverview@stdout, @stderr, field: value
17:37:32Starting process: pnpm dev --port 3010
17:37:32VITE v7.3.1 ready in 412 ms
17:37:32Local: http://localhost:3010/
17:37:33[vite] hmr invalidate /src/App.tsx Could not Fast Refresh
17:37:33page reload src/config.ts
17:37:34Health check `web` passes
17:41:18hmr update /src/routes/home.tsx
17:41:18hmr update /src/styles/app.css
17:42:50hmr update /src/components/Menu.tsx
17:42:50hmr update /src/components/Menu.tsx (x2)
17:55:10TS2322: Type 'string' is not assignable to type 'number'.
17:55:10[vite] Internal server error: Transform failed with 1 error
17:55:41hmr update /src/components/Menu.tsx
17:55:41page reload src/config.ts
17:56:02Health check `web` passes

Tick @stderr, or type a word.

Up in a minute

The guide writes a first .runy/ folder, activates it and opens the console.

$curl -fsSL https://setup.runy.dev | sh
runy 0.7.0 installed to ~/.local/bin
$cd products/ && runy ns up
web: up
$runy ps
web/port/webResolved3010 → http://web.localhost
web/process/webResolvedrunning healthy

Get startedGitHub