nova-os-cli
Single static Go binary for managing LibraOS employees, agents, and jobs from the terminal.
Install
Pre-built binary (recommended)
Pre-built binaries for linux/darwin/windows × amd64/arm64 are attached to every GitHub Release:
# linux/amd64 example — adjust for your platform
TAG=v0.9.0rc2 # or whichever tag you want
curl -L "https://github.com/libraos/sdk/releases/download/$TAG/nova-os-cli_linux_amd64.tar.gz" \
| tar -xz -C /usr/local/bin nova-os-cli
nova-os-cli version
Docker
docker run --rm -it ghcr.io/meganovaai/nova-os-cli:latest version
Mount your config + data:
docker run --rm -it \
-v ~/.nova-os:/home/nonroot/.nova-os \
-v $PWD/data:/data \
-e NOVA_OS_API_KEY \
ghcr.io/meganovaai/nova-os-cli:latest sync /data/
Verify signature (cosign keyless)
Every binary archive is signed with cosign keyless. Verify:
TAG=v0.9.0rc2
cosign verify-blob \
--certificate-identity-regexp 'https://github.com/libraos/sdk/.+' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
--signature nova-os-cli_linux_amd64.tar.gz.sig \
--certificate nova-os-cli_linux_amd64.tar.gz.pem \
nova-os-cli_linux_amd64.tar.gz
From source
go install github.com/libraos/sdk/cli@latest
(Installs as cli in $GOPATH/bin; rename to nova-os-cli for clarity.)
Quick start
# One-time profile setup
nova-os-cli config set partner-prod \
--url https://nova.partner.com \
--api-key-env NOVA_PROD_KEY
nova-os-cli config default partner-prod
export NOVA_PROD_KEY=<your-bearer-token>
# Verify connection
nova-os-cli version
# Day-to-day
nova-os-cli employees list
nova-os-cli employees get frontdesk
nova-os-cli employees create -f frontdesk.json
nova-os-cli agents list --owner-employee frontdesk
nova-os-cli agents get marketing-assistant
nova-os-cli jobs list --status running
nova-os-cli jobs get job_abc123
# Validate + sync a local folder of agent/employee definitions
nova-os-cli validate ./data/
nova-os-cli sync ./data/
nova-os-cli sync --watch ./data/
nova-os-cli version --json
Profile config
Profiles are stored at ~/.nova-os/config.yaml:
default: partner-prod
profiles:
partner-prod:
url: https://nova.partner.com
api_key_env: NOVA_PROD_KEY
customer-acme:
url: https://nova.acme.example.com
api_key_env: NOVA_ACME_KEY
callback_url: https://partner.example.com/nova/acme
Manage profiles with the config subcommand:
nova-os-cli config set staging --url https://staging.example.com --api-key-env NOVA_STAGING_KEY
nova-os-cli config list
nova-os-cli config get staging
nova-os-cli config default staging
nova-os-cli config delete staging
Auth resolution order
For each command, credentials are resolved in this priority order:
--url / --api-key flags
NOVA_OS_URL / NOVA_OS_API_KEY env vars
- Profile in
~/.nova-os/config.yaml (selected by --profile flag or NOVA_OS_PROFILE env var, falls back to default:)
Global flags
| Flag |
Description |
--profile <name> |
Override active profile |
--url <url> |
LibraOS server URL |
--api-key <token> |
Bearer token |
--json |
Emit JSON output (one object per record, suitable for piping to jq) |
Subcommands
employees
nova-os-cli employees list
nova-os-cli employees get <id>
nova-os-cli employees create -f <definition.json>
nova-os-cli employees update <id> -f <patch.json>
nova-os-cli employees delete <id>
agents
nova-os-cli agents list [--owner-employee <employee-id>]
nova-os-cli agents get <id>
nova-os-cli agents create -f <definition.json>
nova-os-cli agents update <id> -f <patch.json>
nova-os-cli agents delete <id>
jobs
nova-os-cli jobs list [--status queued|running|completed|failed|cancelled] [--agent-id <id>]
nova-os-cli jobs get <job-id>
nova-os-cli jobs create -f <job.json>
nova-os-cli jobs cancel <job-id>
messages
Smoke-test path matching the shape of test-callback. One short HTTP round-trip from the same auth/profile resolution as the rest of the CLI.
nova-os-cli messages send <agent-id> <prompt> \
[--end-user <id>] [--metadata '<json>'] [--model <vendor/model>] \
[--system <prompt>] [--max-tokens <n>] [--timeout 60]
nova-os-cli messages stream <agent-id> <prompt> \
[--end-user <id>] [--metadata '<json>'] [--model <vendor/model>]
send returns the parsed MessageResponse JSON; stream opens an SSE connection and prints one event per line (pipe through jq for filtering). Both honor the same NOVA_OS_URL / NOVA_OS_API_KEY / --profile resolution as the rest of the CLI.
Quick smoke test:
nova-os-cli messages send legal-assistant "What's clause 7.3 about?" --end-user demo-user
nova-os-cli messages stream legal-assistant "Walk me through the agreement" | jq 'select(.type=="text")'
knowledge
Hybrid search + ingest against the partner's knowledge collections. Backed by /v1/managed/knowledge/*.
nova-os-cli knowledge search <query> \
[--collection <name>] [--top-k 5] [--threshold 0.0]
nova-os-cli knowledge ingest <content> \
[--title <title>] [--collection <name>]
# Or read content from disk:
nova-os-cli knowledge ingest -f document.md \
[--title <title>] [--collection <name>]
nova-os-cli knowledge collections
search returns ranked passages (each with content, score, collection, document_id). ingest indexes a single document into a collection (defaults to default). collections lists every collection accessible via the partner's API key.
Quick smoke test:
nova-os-cli knowledge ingest "Section 7.3: termination requires written notice" --title "Sample Clause" --collection case-files
nova-os-cli knowledge search "termination" --collection case-files --top-k 3
nova-os-cli knowledge collections
config
nova-os-cli config list
nova-os-cli config get <profile>
nova-os-cli config set <profile> --url <url> --api-key-env <ENV_VAR> [--callback-url <url>]
nova-os-cli config default <profile>
nova-os-cli config delete <profile>
validate (offline CI gate)
nova-os-cli validate ./data/
Walks ./data/employees/*.md and ./data/agents/*.md, runs the rule chain on each, exits non-zero if any issue is found. Use it as your CI pre-deploy gate.
Rules checked:
- Frontmatter parses cleanly
model_config.{answer,planner,skill}.primary matches <vendor>/<model> shape (e.g. Qwen/Qwen3.6-35B-A3B)
custom_tools[].input_schema recursively contains no type: array without items (catches the deterministic Vertex AI 400 class before runtime)
callback.url is HTTPS (localhost is allowed for dev)
agent.owner_employee references resolve within the validated folder
Exit 0 = green. Exit 1 = block deploy.
# Machine-readable (suitable for piping to jq)
nova-os-cli validate ./data/ --json
sync (folder → server)
# One-shot
nova-os-cli sync ./data/
# Watch mode — re-run on every change, 300ms debounce
nova-os-cli sync --watch ./data/
# Preview the plan without executing
nova-os-cli sync --dry-run ./data/
Diffs ./data/employees/ and ./data/agents/ against the server, computes a plan (create/update by default, with optional --prune for destructive sync), and executes it.
By default this is forward-only: server-side resources missing from the folder are NOT deleted. Pass --prune to also delete server-side resources whose ID is absent from the folder; pair with --dry-run first to preview the destructive set.
nova-os-cli sync ./data # forward-only
nova-os-cli sync --prune --dry-run ./data # preview destructive set
nova-os-cli sync --prune ./data # destructive — actually delete
test-callback (Mode B webhook smoke)
Forges a Nova-OS-shaped signed webhook POST to your partner endpoint. Use it to smoke-test your WebhookRouter handler before exposing it to live traffic.
export NOVA_CB_SECRET=your-shared-hmac-secret
nova-os-cli test-callback \
--target https://partner.example.com/nova/cb \
--tool fetch_invoice \
--input '{"invoice_id":"INV-9912"}'
# Same shape LibraOS's Mode B dispatcher would send. Verify your handler
# returns 200 with {"output":"...","is_error":false}.
# Test idempotency dedup — POST 3x with the same tool_use_id, your handler
# should run exactly once
nova-os-cli test-callback --target ... --tool ... --repeat 3 --tool-use-id toolu_dedupe_test
The signature scheme is t=<unix_ts>,v1=<hex(hmac_sha256(secret, ts + "." + tool_use_id + "." + body))> — matches what libraos.callbacks.WebhookRouter (Python SDK) verifies.
| Flag |
Default |
Description |
--target |
(required) |
Partner endpoint URL |
--tool |
(required) |
Tool name to send in the payload |
--input |
{} |
Tool input args as a JSON object |
--secret-env |
NOVA_CB_SECRET |
Name of the env var holding the HMAC secret |
--tool-use-id |
random |
Fixed tool_use_id (useful for idempotency tests) |
--agent-id |
test-agent |
agent_id field in the payload |
--employee-id |
(empty) |
employee_id field in the payload |
--repeat |
1 |
POST N times to test partner-side idempotency dedup |
--timeout |
30 |
Per-request timeout in seconds |
version
nova-os-cli version # human-readable
nova-os-cli version --json # machine-readable
Coming soon
- Pre-built binaries for linux/darwin/windows (amd64 + arm64)