ORCHD

The orchd CLI

There is a second, much smaller way to use orchd.json: a standalone npm package that reads the manifest and runs the workloads directly, with no control plane, no daemon and no Docker.

npx orchd up          # or: npm install -g orchd

It exists because the manifest travels with the project — inside a repo, a tarball, a snapshot or a container image — so whatever boots the project can read one file instead of being handed a command line. The orchestrator reads it to provision a hosted project; the CLI reads it to run the same project on your machine.

The CLI is published from a separate repository today and may move into this one. It is versioned independently of the daemon.

Commands

orchd list                            list workloads in the manifest
orchd resolve [options]               print the resolved command line
orchd run [options]                   resolve, then run it
orchd up [options]                    start every workload, each on its own port

  -w, --workload <name>   workload to act on (default: the only one, if unambiguous)
  -p, --port <n>          port to bind; substituted for $PORT (default: $PORT env)
      --profile <name>    profile to merge (default: none on a host)
  -c, --config <path>     manifest path (default: ./orchd.json, then /orchd.json)
      --all               (resolve) the whole project, not one workload
      --json              (resolve) emit {cwd, argv, env, install} instead of a line
      --port-base <n>     first port to assign (default: 8080)
      --no-install        skip the install step even if node_modules is missing

up — the whole project at once

On a host, up supervises every workload in the foreground the way docker compose up does: interleaved output under a per-workload prefix, and Ctrl-C stops the set. If any one workload exits, the rest are brought down and up exits with that workload's code — a half-booted project is not a useful state to be left in.

$ npx orchd up
orchd: api -> PORT=3000 npm run dev (cwd /work/demo/api)
orchd: web -> API_URL=http://localhost:3000 PORT=3001 npm run dev (cwd /work/demo/web)
api | api dev server on 3000
web | web dev server on 3001
^C
orchd: stopping…

Each workload gets its declared port, or one counting up from --port-base.

Cross-workload addressing

Workloads refer to each other by name, and the port is filled in at resolve time:

{
  "name": "mobile",
  "env": { "EXPO_PUBLIC_API_URL": "${url:api}" }   // -> http://localhost:3000
}

${url:<name>} and ${port:<name>} are the cross-workload forms, alongside $PORT / ${PORT} for the workload's own port. In a hosted deployment those siblings are separate hostnames; on one machine everything shares localhost, so the manifest names them and the runner resolves the addresses.

Profiles

The command a workload should run depends on what is executing it. A host wants the project's real command; a browser-based sandbox may want a different bundler entirely. One manifest, one override block:

{
  "workloads": [{
    "name": "mobile",
    "kind": "node",
    "dir": "mobile",
    "install": ["npm", "install"],
    "run": ["npx", "expo", "start", "--web", "--port", "$PORT"],
    "profiles": {
      "lifo": { "run": ["browser-metro", ".", "--port", "$PORT"] }
    }
  }]
}

No profile is applied unless a runner asks for one, so the plain run is what you get on a host. run, install and dir replace wholesale when a profile overrides them; env merges key-wise, so a profile can add one variable without restating the rest.

resolve is the machine interface

For anything long-running, prefer resolve --json and run the command yourself — you keep your own streaming, logging and cancellation:

$ orchd resolve --workload mobile --port 8082 --json
{"workload":"mobile","cwd":"/mobile","argv":["npx","expo","start","--web","--port","8082"],
 "env":{},"install":["npm","install"]}

resolve --all --json gives the whole project. run is a convenience for interactive and one-shot use.

Two runners, one resolution layer

The package ships the orchd bin for hosts and CI, plus a command that registers inside a Lifo sandbox, where a workload becomes a shell job instead of a child process. Both sit on the same pure resolution layer, so resolve answers identically in either place — only execution differs.

How it relates to the daemon

orchd CLIORCHD daemon
Reads orchd.jsonyesyes
Runs workloadsas child processes / sandbox jobsvia a runtime driver
Multi-tenantnoyes
Routing, TLS, wake, backups, keysnoyes
Needs a servernoyes

Same manifest, two consumers. Note that the CLI understands profiles and the ${url:…}/${port:…} forms; the daemon's manifest reader supports the core fields documented under Templates, so keep profile-only behaviour out of what the hosted path depends on.

from the same team

Related projects

ORCHD is built by the makers of these open-source tools and products.