CLI
Install the runyard CLI, connect it to a Hub, and drive workflows, runs, approvals, and runners from the terminal.
The runyard CLI is a thin client of the Hub's HTTP API. It talks
to one or more Hubs ("remotes"), starts and tails workflow runs, resolves
approvals, and can set up and start a runner on the local machine.
Install
The fastest path is the install script served by your own Hub, which downloads
the CLI tarball from the same instance (/cli.tgz), installs runyard and
runyard-mcp into ~/.local/bin, and logs you in:
curl -fsSL https://hub.example.com/install.sh | bashIt prompts for an access token (Web Hub ā Tokens) and a name for the
connection. Alternatively, run the CLI from a source checkout of the
repository with pnpm cli -- <command> (the checkout exposes the runyard,
runyard-mcp, and runyard-runner binaries under bin/).
Connecting to a Hub
The CLI stores named remotes (Hub URL + token) in ~/.runyard/config.json
(mode 0600). Every command accepts global options --url, --token,
--remote <name>, and --json (machine-readable output).
# Authenticate and save as a remote (prompts for URL/token if omitted)
runyard login --remote default --url https://hub.example.com
# Inspect and switch remotes
runyard remotes # list (alias: runyard remote list)
runyard remote use staging
runyard remote remove old # alias: rm
runyard logout # remove the current remote (--all removes every remote)
# Who am I? (token name + scopes)
runyard statusEnvironment variables RUNYARD_HUB_URL / RUNYARD_HUB_TOKEN (and an explicit
--url / --token) take precedence over the saved remote.
Discover and run workflows
runyard menu # next-action menu, top 5 workflows (alias: discover; --all for the full catalog)
runyard workflows # list workflows (-q <query> to search)
runyard workflow describe <id> # input schema, permissions, agents, skills
# Dry-run the deterministic preflight ā nothing is created
runyard preflight my-workflow --input '{"topic": "hello"}' --where remote
# Run it
runyard run my-workflow \
--input '{"topic": "hello", "title": "Hello run"}' \
--where remoterunyard run options:
| Option | Meaning |
|---|---|
-i, --input <json> | JSON input for the run |
--where <mode> | Execution mode: local or remote (alias: --execution-mode) |
--runner-location <location> | Target a specific runner location tag |
--negotiate | Preflight first: enqueue only when ready, otherwise print the negotiation state (questions/blockers and a saved draft) without creating a run |
--chain <json> | JSON array of next workflow steps to queue after each run succeeds |
--pin <sha> | Pin the run to a specific workflow git SHA (requires workflow versioning) |
--max-tokens <n> | Hard budget: stop the run once its metered usage reaches this many tokens |
--max-cost <usd> | Hard budget: stop the run once its metered cost reaches this many US dollars |
--idempotency-key <key> | Safe retry key. If omitted, the CLI generates one and includes it in JSON output so automation can reuse it |
--follow | Attach to the run's live event stream and exit with its terminal status |
--stream-logs | Alias for --follow |
Related: runyard workflow versions <workflow> lists SHAs seen across runs and
runyard workflow rollback <workflow> <sha> re-runs pinned to a prior SHA
(--from-run <id> links it to the run being rolled back).
Watch and manage runs
runyard runs -s running # list runs (filter by status)
runyard attention # triage queue: paused / waiting approval / stopped at budget
runyard usage # fleet usage rollup per workflow (--days 7 to narrow)
runyard usage <runId> # one run's metered usage, budget, and per-call records
runyard run-status <id> # run detail (alias: run-detail)
runyard handoff <id> # bounded agent handoff pack (use --json for automation)
runyard logs <id> # print run logs (snapshot)
runyard logs <id> --follow # attach to the live event stream through terminal state
runyard tail <runId> # follow the unified timeline as NDJSON
runyard tail <runId> --once # one snapshot, then exit (--since <iso> to resume)
runyard artifacts <runId> # list a run's artifacts (omit runId to search across runs)
runyard download-artifact <artifactId> -o artifact.bin # stream artifact bytes to a file
runyard cancel <runId> -r "no longer needed"
runyard pause <runId> -r credits_exhausted # park a run; keeps its checkpoint
runyard resume <runId> # re-queue a paused run from its checkpoint
runyard resume <runId> --from-scratch # discard the checkpoint + runner pin; any runner takes ittail emits {ts, kind, source, payload} lines built from status transitions,
events, and artifacts ā pipe it into jq or downstream tooling. It rides the
run's live event stream (falling back to 2-second polling if the stream is
unavailable) and exits once the run is terminal and drained.
For parent agents, prefer runyard run ... --follow, then
runyard handoff <run-id> --json for final reporting or continuation. The
handoff response is summary-first and bounded: it includes next action,
approval state, usage/budget, output keys and safe scalar fields, top artifact
download links, diagnostic excerpts when relevant, flow state, linked work
item, and deep links without returning full logs or artifact bodies.
download-artifact streams from the Hub to the destination instead of loading
the whole artifact in memory. Binary artifacts are refused on an interactive
terminal unless --output is used or --force is passed.
Follow mode (run --follow, logs --follow)
--follow streams a run's events to stdout until the run reaches a terminal
state, then exits ā external tools can treat RunYard as an ordinary
subprocess without knowing anything about runners or the Hub's event
transport (an authenticated SSE stream with cursor resume under the hood):
runyard run my-workflow -i '{...}' --follow # create + attach + stream
runyard logs <run-id> --follow # attach to an existing run
runyard logs <run-id> --follow --after-seq 41 # resume from a saved cursor
runyard --json run my-workflow --follow | jq . # NDJSON envelopes- Text mode prints one
[timestamp] type: messageline per event, then a terminal summary. With the global--jsonflag, stdout carries exactly one NDJSON envelope per line and nothing else:{"kind":"run-created",ā¦}(fromrun --follow),{"kind":"event", runId, seq, id, type, message, createdAt, data?}, and a final{"kind":"terminal", runId, status, exitCode, error?, output?, links}. - All diagnostics (attach, reconnect/backoff, detach notices) go to stderr ā stdout stays machine-parseable.
- The stream reconnects transparently with exponential backoff and resumes from the last seen event cursor; no event is lost or duplicated.
Ctrl-Cdetaches and exits130without cancelling the remote run ā reattach later withrunyard logs <id> --follow.
Exit codes are stable: 0 run succeeded; 1 run reached any other terminal
status (failed, cancelled, timed_out, budget_exceeded, ā¦); 2 usage/input
error (unknown run, invalid cursor); 3 transport failure (could not reach
or keep a stream to the Hub); 4 authentication failure; 130 detached via
Ctrl-C.
Approvals
runyard approvals # list pending approval cards
runyard approve <id> -c "ship it"
runyard reject <id> -c "wrong repo"
runyard request-changes <id> -c "tighten the scope first"Approval decisions and work-item run link/unlink also accept
--idempotency-key; when omitted the CLI generates a UUID and includes
idempotencyKey in --json output. Reuse that key when retrying the same user
intent after a transport failure.
Boards and portable definitions
Boards are configured software-factory views over Factory Items. Preview a Ready approval with runyard factory-item preview-move <id> --status ready --board <slug> to see transition policy, destination lane, resolved workflow, synthesized input, duplicate/live-run suppression, and deterministic preflight. Moving a ticket with runyard factory-item update --status ready uses the same server PATCH path as Web/API/MCP, so configured trigger.mode: "auto" lanes launch from the Hub and return trigger metadata. Add --negotiate when you want a non-ready auto-trigger preflight saved as a run draft instead of launching. Board definitions are portable JSON documents describing a whole kanban ā lanes, guards, triggers, transition policy, and optional schedule hookups. Agents provision boards from these documents; the DB row is one instance of a definition.
runyard board list # boards on this Hub
runyard board show <slug> # lanes with counts + tickets
runyard board create --slug team-board --title ⦠# ad-hoc create
runyard board definition list # portable summaries
runyard board definition validate --file board.json
runyard board definition import --file board.json # create or update + reconcile schedules
runyard board definition export <slug> # round-trippable JSON
runyard board policy <slug> # inspect transition policy
runyard board check <slug> --from ready --to running --workflow implement-change-gated --run-origin workflowConcrete board and factory definitions are durable Hub state, not Git-shipped examples. Export an existing board and import that JSON into another Hub. YAML is a future syntax; JSON is the documented format today.
Workflow packages
Workflows move between Hubs as portable .runyard-workflow.json package files
ā exported from one Hub and imported into another (admin token required).
Imported workflows arrive disabled for review before enabling; this is the
supported way to carry workflow source around, not files on a runner.
runyard workflow-package export my-workflow -o my-workflow.runyard-workflow.json
runyard workflow-package validate my-workflow.runyard-workflow.json
runyard workflow-package preview my-workflow.runyard-workflow.json --slug new-name
runyard workflow-package import my-workflow.runyard-workflow.jsonTokens, audit, and catalog
Admin-scoped commands:
runyard token-scopes # what each scope grants + named presets
runyard token-create ci-bot --scopes api,mcp --expires-in-days 90
runyard token-list
runyard token-revoke <id>
runyard audit # recent audit logReads available to any token: runyard runners (runner pool), runyard agents,
runyard skills, runyard knowledge -q <query>, runyard hooks [--workflow <slug>], and runyard hook describe|validate <slug>. Secrets have
no CLI subcommand ā manage them in the web UI, over the
API (PUT /api/secrets/:key), or with the MCP set_secret tool.
Runner setup
Turn a machine into a runner in three steps. First scaffold a workspace
(requires bun and the smithers engine on PATH; it warns if no claude,
codex, or pi agent CLI is found):
runyard runner setup --workspace ~/runyard-workspace --location localThen start the runner against the current remote (it inherits the remote's URL
and token, or RUNYARD_HUB_URL / RUNYARD_HUB_TOKEN):
runyard runner start --workspace ~/runyard-workspace --location local--location is local or vps and drives run routing (--where local runs
land on local-tagged runners). You can also register a machine explicitly:
runyard runner register --name my-laptop --tags linux,node,git,shell,web,smithers --location localFor an always-on runner use the systemd unit instead ā see Installation.
MCP helpers
runyard mcp install --all # configure detected AI clients to use this Hub
runyard mcp config # print the MCP config snippet (alias: runyard mcp-config)See the MCP guide for clients and options.
Updating a host install
On a host that runs the Hub from a full checkout (not the thin CLI bundle),
runyard update [tag] applies a release on that host: it drains runners,
swaps the code, restarts the systemd units, verifies health, and rolls back
automatically on failure. It is always operator-initiated.
runyard update # latest release (asks for confirmation; -y to skip)
runyard update v0.3.10 # a specific tagOptions: --units <units> (systemd units to restart, default
runyard runyard-runner) and --grace-ms <ms> (bounded drain window before
aborting ā in-flight runs are never killed).