Runyard Docs
Guides

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 | bash

It 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 status

Environment 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 remote

runyard run options:

OptionMeaning
-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
--negotiatePreflight 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
--followAttach to the run's live event stream and exit with its terminal status
--stream-logsAlias 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 it

tail 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: message line per event, then a terminal summary. With the global --json flag, stdout carries exactly one NDJSON envelope per line and nothing else: {"kind":"run-created",…} (from run --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-C detaches and exits 130 without cancelling the remote run — reattach later with runyard 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 workflow

Concrete 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.json

Tokens, 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 log

Reads 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 local

Then 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 local

For 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 tag

Options: --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).

On this page