- Go 97%
- Shell 2.6%
- Makefile 0.3%
Main keeps its stable floating tag; feat and feature branches get independent latest and fixed tags with an explicit branch-scoped builder. Validation: shell syntax and publish-scope regressions. Actual registry publishing remains for CI. |
||
|---|---|---|
| cmd/yuvu | ||
| deployments/docker/yuvu-cli | ||
| internal | ||
| scripts | ||
| vendor | ||
| .dockerignore | ||
| .gitignore | ||
| .woodpecker.yml | ||
| go.mod | ||
| go.sum | ||
| Makefile | ||
| README.md | ||
yuvuCli
Agent-friendly CLI for Yuvu's Protobuf/Connect API.
Task files are editable YAML or JSON representations of
yuvu.task.v1.InvokeTaskRequest. Stable platform fields are validated against
the Protobuf contract before a request is sent; dynamic capability inputs
remain flexible and are validated by Yuvu Core.
Installation
Woodpecker builds Linux amd64/arm64 binaries and publishes the same binaries in the multi-architecture image:
docker.lib.zuixue.site/yuvu/cli:latest
docker.lib.zuixue.site/yuvu/cli:<YYYYMMDD-short-sha>
Run the image directly:
docker run --rm \
-e YUVU_BASE_URL=http://core.yuvu.zuixue.site \
docker.lib.zuixue.site/yuvu/cli:latest \
task list --limit 10
For task/workflow files, mount the current directory:
docker run --rm -i \
-e YUVU_BASE_URL \
-e YUVU_TOKEN \
-v "$PWD:/work" -w /work \
docker.lib.zuixue.site/yuvu/cli:latest \
workflow apply daily.yaml --output workflow-id
The image is also a durable binary distribution source:
container="$(docker create docker.lib.zuixue.site/yuvu/cli:latest)"
docker cp "$container:/usr/local/bin/yuvu" ./yuvu
docker rm "$container"
chmod +x ./yuvu
For a local source build, run make build. make dist creates amd64/arm64
tarballs and SHA256SUMS; make image creates yuvu/cli:dev from them.
export YUVU_BASE_URL=http://core.yuvu.zuixue.site
yuvu capability list --output names
yuvu capability get maa.run
yuvu capability definition CAPABILITY_ID
yuvu capability traits CAPABILITY_ID
yuvu capability windows --capability maa.run
yuvu capability windows --format json
yuvu task init openwrt.artifacts.bundle > task.yaml
yuvu task validate task.yaml
yuvu task render task.yaml --format json
yuvu task run task.yaml
yuvu task run task.yaml --set max_attempts=3 --set inputs.jobs=8
yuvu task run - < task.yaml
yuvu task run task.yaml --wait --output status
yuvu task run --async --input jobs=8 --input 'profile="x86_64"' openwrt.build.run
yuvu task get TASK_ID
yuvu task wait --timeout 30m --output status TASK_ID
yuvu task cancel --output id TASK_ID
yuvu task list --status running
yuvu task list --caller-type workflow --caller-id WORKFLOW_ID
yuvu task events TASK_ID
yuvu task attempts TASK_ID
yuvu task summary ROOT_TASK_ID
yuvu task dependencies TASK_ID
yuvu task dependents TASK_ID
yuvu task events --follow TASK_ID
yuvu task logs --follow --stream stderr --timestamps TASK_ID
yuvu task watch --exit-code TASK_ID
yuvu task graph TASK_ID
yuvu task inputs TASK_ID
yuvu task outputs TASK_ID
yuvu task output TASK_ID OUTPUT_NAME
yuvu task output download TASK_ID OUTPUT_NAME --file ./output.bin
yuvu task output download --all --dir ./outputs TASK_ID
yuvu task export --dir ./task-archive TASK_ID
yuvu task rerun --output id TASK_ID
yuvu task retry --force --wait --output status TASK_ID
yuvu task dependency add --output id TASK_ID DEPENDS_ON_TASK_ID
yuvu task dependency remove --output status TASK_ID DEPENDS_ON_TASK_ID
yuvu task dependency edit --add DEPENDS_ON_TASK_ID --remove OLD_DEPENDS_ON_TASK_ID TASK_ID
yuvu task export-python task.yaml > task.py
Allocations and concurrency windows
Concurrency is enforced per capability (max_concurrency). yuvu capability windows shows the running occupants, the window limit, and the tasks waiting in
ready, so max_inflight_reached rejections no longer require direct database
access:
yuvu capability windows
yuvu capability windows --capability maa.run --format json
Managed resource allocations (leases) are visible without hand-written REST:
yuvu allocation list
yuvu allocation list --include-released
yuvu allocation show ALLOCATION_ID --format json
yuvu allocation renew TASK_ID
yuvu allocation release ALLOCATION_ID --operator OPERATOR --reason 'provider stopped' --force
allocation renew extends the task lease through RenewTaskLease.
allocation show scans active and released records by allocation id and exits
4 (not found) when the id is unknown.
Release requires an auditable operator and reason. Use --force only after
confirming the provider process has stopped; a lease timeout alone is not
stop confirmation.
Provider inspection and managed operations use the Core API:
yuvu provider list CAPABILITY_ID
yuvu provider get PROVIDER_ID
yuvu provider pin PROVIDER_ID https://node.example.test:9083
yuvu provider unpin PROVIDER_ID
yuvu provider restart PROVIDER_ID
provider list is scoped to one capability. Restart is available only for
agent-managed instances; it does not restart arbitrary external providers.
Public resources and templates
yuvuCli reads reusable task and workflow templates from the public
yuvuResources manifest. Every downloaded file is verified by SHA-256 and
stored as a last-known-good cache, so an already used template remains
available during a temporary repository outage.
yuvu resources status
yuvu resources refresh
yuvu template list
yuvu template show maa/daily
yuvu template validate maa/daily
yuvu template render maa/daily --set tasks.fight.inputs.stage=CE-6
yuvu template run maa/daily --set tasks.fight.inputs.stage=CE-6 --wait
Templates define an explicit allow_overrides list. The CLI rejects any
override outside that list before contacting Core. Runtime secrets, node
permissions, mount roots, and Docker grants are not resource-template fields.
Use YUVU_RESOURCE_MANIFEST_URL to select another reviewed manifest and
YUVU_RESOURCE_CACHE to select the local cache directory. Set
YUVU_RESOURCE_REVISION to pin an exact content revision for production or
rollback. Add --offline to template commands to require cached resources
only. A downloaded template is promoted to last-known-good only after the CLI
has parsed and validated its task or workflow document.
Node deployment control uses the same Protobuf/Connect contract. It is meant for operator-side upgrades and smoke checks, replacing hand-written control HTTP requests:
export YUVU_NODE_TARGETS='{"nas123":{"url":"http://192.168.99.123:39110","controller_id":"yuvu-core","secret_env":"YUVU_NODE_123_SECRET"}}'
export YUVU_NODE_DEFAULT=nas123
export YUVU_NODE_123_SECRET=...
yuvu node targets
yuvu node facts
yuvu node runtime report
yuvu node runtime report --all-nodes --format json
yuvu node runtime exec RUNTIME_SESSION_ID -- nvidia-smi
yuvu node deployments list --check-update
yuvu node adapter validate --instance restic --image registry/restic:latest --port 0:18115 --mount /config/restic:/config --mount /data/restic:/data
yuvu node adapter deploy --instance restic --image registry/restic:latest --port 0:18115 --mount /config/restic:/config --mount /data/restic:/data --core-url http://core:8080
yuvu node deployment show core --compose
yuvu node deployment show --deployment core --format json
yuvu node bootstrap show core --compose
yuvu node bootstrap plan core --tag latest
yuvu node bootstrap upgrade core --tag latest --apply
yuvu node check-update core notify rclone-adapter
yuvu node update core notify
yuvu node status core
yuvu node logs rclone-adapter
yuvu node exec rclone-adapter -- rclone version
yuvu node exec --timeout 60 --max-output 1048576 openwrt-build -- git status --short
yuvu node exec --container yuvu-runtime-RUNTIME_ID -- nvidia-smi
yuvu node restart notify
yuvu node check-update yuvu-node
yuvu node update yuvu-node
node adapter validate performs a read-only policy and deployment-plan check.
node adapter deploy validates first, then carries the allocated port,
provider base URL, and deployment trace into the signed deploy request. Set
--core-url to enable provider registration without manually assembling its
environment. node check-update, node update, and lifecycle commands accept
one or more instance ids. The CLI signs every request from the complete
Protobuf control payload; the shared secret is read from the environment or
secret_env and is never written to task files. yuvu-node and yuvuNode are
the only self-upgrade aliases for yuvuNode itself.
node deployment show/export report the declared plan plus the runtime facts
from the node runtime report: resolved_image_digest, runtime_state
(state, health, running, started_at, restart_count, configuration drift), and
instances[]. When the runtime report is unavailable the command still shows
the declared plan and marks runtime_state.status as unavailable.
Instance-taking commands accept --instance and deployment-taking commands
accept --deployment as alternatives to the positional id, so an instance id
and a deployment id are no longer confused. Passing both forms is rejected.
Credential and target errors name the exact missing environment variable and
list the configured node targets.
node exec is a bounded, non-interactive diagnostic command for one managed
container. Pass the node instance id positionally, or pass a full managed
container name with --container yuvu-<instance> (the CLI strips the yuvu-
prefix so yuvuNode derives the exact container name; this is how runtime
containers are addressed). The two forms are mutually exclusive. Options must
precede the instance id. Arguments after -- are sent
as an argv array without implicit shell parsing, TTY, or stdin. Use an explicit
-- sh -lc '...' only when shell syntax is genuinely required. Remote stdout
and stderr are printed directly in the default text format; JSON and YAML keep
the typed execution result.
node runtime exec addresses a model runtime container directly by session id.
Pass the bare session id, the runtime instance id (runtime-<session>), or the
full managed container name (yuvu-runtime-<session>); the CLI normalizes the
reference to the runtime-<session> instance id that yuvuCore derives and the
node expands to yuvu-runtime-<session>. It shares node exec's argv, timeout,
max-output, and output-format contract.
task run accepts either a YAML/JSON task file, stdin (-), or a capability
name for quick mode. Repeat --input key=value to build dynamic inputs. Repeat
--set path=value to override any task field in file, stdin, or quick mode.
Values are parsed as JSON when possible and otherwise remain strings.
task logs prints human-readable log text by default. It supports
--stream stdout|stderr|log, --since 10m, and --timestamps; use
--format json|yaml for the underlying structured events. task watch prints
status and progress changes, and --exit-code fails when the Task does not
succeed.
task output download --all downloads every artifact and bundle output using
safe output names and refuses to overwrite files unless --overwrite is set.
task export creates a portable directory containing task metadata, inputs,
outputs, graph, events, text logs, and downloadable outputs.
task rerun creates a new independent TaskInvocation from the original request
snapshot. It clears the original idempotency key, parent, dependencies, and
schedule. Workflow output references are materialized from their source task
before the new task is created.
task retry schedules another attempt on the same failed, expired, or blocked
TaskInvocation. By default it respects retryability and the configured attempt
budget; --force permits a non-retryable task and extends the budget by one
attempt when needed.
For scripts and agents, use --fields id or --fields status to keep stdout
to a single stable value; --output remains as a legacy alias. Status values
are lowercase (succeeded, failed, ready) to match workflow output. Full
responses support --format json and --format yaml. Pass global --machine
before the command to emit errors as JSON on stderr with a stable exit_code.
Exit codes are 1 general failure, 2 invalid RPC argument, 4 not found,
5 timeout, 6 unavailable, and 7 cancelled.
Workflow planning
Workflow files declare a task DAG. The CLI validates every task against
yuvu.task.v1.InvokeTaskRequest, rejects missing dependencies and cycles, and
produces a deterministic topological plan.
api_version: yuvu/v1
kind: Workflow
metadata:
name: build-and-deploy
idempotency_key: release-2026-06-12
retry_policy: partial_allowed
tasks:
build:
capability: openwrt.build.run
execution_mode: async
inputs:
profile: x86_64
deploy:
capability: firmware.deploy
execution_mode: async
depends_on: [build]
yuvu workflow validate workflow.yaml
yuvu workflow validate --remote=false workflow.yaml
yuvu workflow plan workflow.yaml
yuvu workflow plan workflow.yaml --format json
yuvu workflow apply workflow.yaml
yuvu workflow apply --output workflow-id workflow.yaml
yuvu workflow get WORKFLOW_ID
yuvu workflow wait --output status WORKFLOW_ID
yuvu workflow cancel WORKFLOW_ID
yuvu workflow retry --output workflow-id WORKFLOW_ID
yuvu workflow retry --mode failed_branch WORKFLOW_ID
yuvu workflow retry --mode from_tasks --task build WORKFLOW_ID
yuvu workflow history WORKFLOW_ID
workflow apply submits the complete DAG through the atomic Protobuf
WorkflowService. Workflow lifecycle operations and capability validation also
use Protobuf RPCs; the CLI does not depend on Core's HTTP JSON endpoints.
Task ordering is always defined by depends_on. Workflows default to
retry_policy: full_only; set partial_allowed to permit failed_branch or
from_tasks retries. Partial retries preserve dependencies inside the selected
subgraph and include every downstream task.
Downstream task inputs can reference outputs from a declared dependency:
deploy:
depends_on: [build]
capability: firmware.deploy
inputs:
firmware: ${tasks.build.outputs.firmware}
Output references are resolved immediately before execution. Partial retries
reuse outputs from successful tasks that were not retried. workflow history
shows workflow and task retry lineage.