SoyaOS

CLI v0 reference

Every verb the soyaos binary exposes in v0, with example output.

The soyaos binary exposes the verbs below in v0. Each verb is stable within v0 — flags may be added, never removed. Exit codes are stable too (see the table at the end).

Global flags

--config <path>      Override config file (default: ~/.config/soyaos/config.yaml)
--log-level <level>  trace | debug | info | warn | error (default: info)
--json               Emit JSON-only on stdout (no progress UI)
--no-color           Disable ANSI colors
--profile <name>     Switch between named profiles in config (default: "default")

Environment variables override the config file; flags override env vars. SOYAOS_LOG_LEVEL, SOYAOS_CONFIG, SOYAOS_PROFILE are the most commonly used ones.

soyaos version

Print version, commit, build date, and the SoyaPack-v0 schema version.

$ soyaos version
soyaos 0.1.0 (commit 4a9b2c7, built 2026-05-14)
  schema: soyapack v0.1.0
  runtime: linux/amd64

JSON mode (handy in CI):

$ soyaos --json version
{"version":"0.1.0","commit":"4a9b2c7","built":"2026-05-14T08:11:43Z","schema":"v0.1.0","runtime":"linux/amd64"}

soyaos pack

Create, validate and run SoyaPack bundles locally.

SubcommandPurpose
pack init <name>Scaffold a new SoyaPack from a built-in template (--template <name>).
pack validate .Validate soyapack.yaml against the v0 schema.
pack lint .Stricter checks — style, examples coverage, capability narrowing.
pack push <name>Publish to the Moon configured in the current profile.
pack listList installed / published packs.
pack rm <name>Remove a pack locally (cannot remove a pack referenced by a live run).

Example: scaffold + validate + run:

$ soyaos pack init hello --template echo
 wrote hello/soyapack.yaml
 wrote hello/prompts/reply.md
 wrote hello/examples/hello.json

$ soyaos pack validate hello
 apiVersion ok
 kind=Agent ok
 capabilities.egress empty (declaring `egress: []` makes intent explicit)
 inputs schema valid
 outputs map valid
 prompts.reply: file exists
ok · 0 errors, 0 warnings

pack lint is stricter — it’ll warn on things like missing examples for declared input fields, or capabilities wider than the example coverage justifies:

$ soyaos pack lint hello
warn  examples cover 1 of 2 input variants add a fixture for `topic=null`
warn  capabilities.egress lists `api.openai.com` but no example exercises it
2 warnings · use --strict to fail on warnings

soyaos run

soyaos run <pack-dir> --input <json|@file>

Runs a SoyaPack in a local Comet sandbox. Streams Scope events to stdout when --json is set, otherwise renders a compact progress UI.

$ soyaos run hello --input '{"text":"hi"}'
 hello @0.1.0 · 1 stage · capabilities: none
  reply  ████████████  0.8s
 run_018f3a · ok in 0.81s
{ "reply": "hi" }

JSON mode emits a stream of Scope events, one per line, ending in run_completed:

$ soyaos --json run hello --input '{"text":"hi"}'
{"kind":"run_started","run_id":"run_018f3a","pack":"[email protected]","ts":"…"}
{"kind":"stage_started","stage":"reply","ts":"…"}
{"kind":"stage_completed","stage":"reply","artifacts":["reply.v1"],"ts":"…"}
{"kind":"run_completed","ok":true,"ts":"…"}

Useful flags:

  • --input @path/to/input.json — read input from file.
  • --timeout 30s — kill the run after 30s.
  • --cache-mode <off|read|write|rw> — override the Comet’s cache for this run.

soyaos serve

soyaos serve --role <comet|moon|planet>

Starts a long-lived node in the given role. Multiple --role flags are allowed — --role moon --role comet is the default for the cluster edition. serve is mostly used implicitly via soyaos start --edition <name>; reach for it directly only when you want a non-standard role mix.

$ soyaos serve --role moon --bind 0.0.0.0:8443 --state postgres://…
 Moon listening on 0.0.0.0:8443
 Registry backend: s3://soya-packs/
 Scope broker: ws://0.0.0.0:8444
 ready in 312ms

soyaos start

Convenience wrapper around serve that picks the right --role set for the given edition.

soyaos start --edition <solo|cluster|cloud|hybrid|ent-cloud|ent-private>
$ soyaos start --edition solo
 solo: planet+moon+comet collapsed into one process
 Listening on 127.0.0.1:7474 (set --bind to change)
 Web UI: http://127.0.0.1:7474/
ready · paste 127.0.0.1:7474/v1 into any OpenAI-compatible client

soyaos auth

SubcommandPurpose
auth loginBrowser-based login to a Moon.
auth logoutDrop cached credentials for the current Moon.
auth whoamiPrint the currently-authenticated user + Moon.
auth keys createMint a new API key.
auth keys listList API keys (truncated; show full with --reveal).
auth keys revoke <id>Revoke an API key.
$ soyaos auth whoami
[email protected] · moon.example.com · role=admin · 2 keys

soyaos join

Join an existing Moon as a Comet:

$ soyaos join --moon https://moon.example.com --token <invite>
 Verified Moon identity (planet=planet.soyaos.ai)
 Registered as comet cmt-a3f1 · pool=default
 Capabilities accepted: egress[api.openai.com:443], fs.read[/workdir], fs.write[/workdir/out]
ready · awaiting work

The invite token is single-use and expires after 15 minutes. You can mint one with auth keys create --kind comet-invite on the Moon.

soyaos pull / soyaos push

Mirror SoyaPacks between Moons (useful when promoting from staging to prod):

$ soyaos pull --moon https://stage.example.com soya:[email protected]
$ soyaos push --moon https://prod.example.com  soya:[email protected]

soyaos config

Print and edit the current effective config:

$ soyaos config get default.moon
moon: https://moon.example.com

$ soyaos config set default.moon https://newmoon.example.com

Exit codes

CodeMeaning
0Success
1Generic error
2Validation error (manifest, input, etc.)
3Sandbox / capability violation
4Auth error
5Upstream / network error
6Timeout
124(Reserved for timeout(1)-style wrappers)

Exit codes are stable across the v0 series — you can script against them safely.

Common workflows

Test a pack locally then push to staging:

soyaos pack validate .
soyaos pack lint . --strict
soyaos run . --input @examples/hello.json
soyaos pack push hello --moon https://stage.example.com

Roll out a new pack version to prod:

soyaos pull --moon https://stage.example.com soya:[email protected]
soyaos push --moon https://prod.example.com  soya:[email protected]
soyaos auth keys list --moon https://prod.example.com    # sanity-check existing keys still work

Investigate a failing run:

soyaos run . --input @failed-input.json --log-level debug --json | tee run.log
soyaos --json run . --input @failed-input.json | jq 'select(.kind == "tool_called")'

Edit this page on GitHub