CLI reference

CLI reference

Complete listing of every sparkwing command, flag, and argument, generated from the CLI's own command registry. For the conceptual overview -- which binaries exist, the flag-naming rule, and what to reach for when -- see cli.md.

sparkwingSection anchor link

sparkwing -- CI/CD pipelines written in Go

Sparkwing is a self-hosted pipeline runner. Pipelines are Go programs in a repo's .sparkwing/ directory, triggered by git hooks, webhooks, schedules, or manual invocation. Use 'sparkwing run ' to invoke one; 'sparkwing pipeline list' / 'describe' for agent-facing discovery.

SubcommandsSection anchor link

  • info -- What is sparkwing, what's in this repo, what to run next
  • pipeline -- This repo's pipelines
  • run -- Run a pipeline (shortcut for pipeline run)
  • runs -- Inspect or manage runs
  • profile -- Show which profile sparkwing would use right now, and why
  • version -- Show + update versions
  • update -- Self-update the CLI binary
  • dashboard -- Local dashboard server
  • cluster -- Cluster ops
  • secrets -- Manage secrets
  • configure -- Laptop-local config
  • debug -- Interactive run debugging
  • docs -- Embedded user docs (offline)
  • commands -- Full CLI surface as JSON (agent self-discovery)
  • completion -- Shell completion script

ExamplesSection anchor link

# Run a pipeline (positional shortcut)
sparkwing run build-test-deploy

# First command an agent should run
sparkwing info -o json

# List every invocable (agents)
sparkwing pipeline list -o json

# Inspect one pipeline's full metadata
sparkwing pipeline describe --name release -o json

# Bootstrap + scaffold your first pipeline in a fresh repo
sparkwing pipeline new --name release

# Start the local dashboard
sparkwing dashboard start

sparkwing clusterSection anchor link

Operate and inspect the sparkwing cluster

Cluster-scoped operations and state. 'status' rolls up controller health + fleet + queue state into one report; individual verbs drill in (agents for fleet detail, users / tokens for controller-stored config, image rollout for deploys, webhooks for GitHub delivery debug).

Secrets used to live here; they're now top-level ('sparkwing secrets ...') since they straddle laptop dotenv

  • controller storage and are referenced constantly.

'worker' runs a laptop-side queue drainer against a remote cluster. 'gc' sweeps stale warm-runner PVCs.

For the laptop-local dashboard server, see 'sparkwing dashboard start'.

Profiles (via --profile) pick which cluster these commands address; set them up with 'sparkwing configure profiles'.

SubcommandsSection anchor link

  • status -- Roll-up report: controller health + fleet + queue + recent runs
  • agents -- Fleet-view detail (GET /api/v1/agents)
  • worker -- Run a laptop-side worker against a remote cluster
  • gc -- Sweep stale warm-PVC state
  • users -- Create / list / delete dashboard login users
  • tokens -- Create / list / revoke / rotate controller API tokens
  • image -- Image rollout helpers for gitops-managed deployments
  • webhooks -- Inspect / replay GitHub webhooks (wraps gh api)
  • concurrency -- Inspect a concurrency namespace: holders + queue

ExamplesSection anchor link

# Cluster health summary
sparkwing cluster status --profile prod

# List fleet agents
sparkwing cluster agents --profile prod

sparkwing cluster agentsSection anchor link

Inspect the controller's fleet view

Hits GET /api/v1/agents on the selected profile's controller. Prints one row per agent seen claiming work in the last hour (the controller infers agents from recent node claims; there is no explicit registration table yet).

SubcommandsSection anchor link

  • list -- Print agents (name, type, status, active jobs, last-seen, labels)

ExamplesSection anchor link

# List prod agents
sparkwing cluster agents list --profile prod

sparkwing cluster agents listSection anchor link

Print the controller's known agents

Fetches /api/v1/agents and renders a table of fleet members. The controller infers agents from node claims over the last hour, so idle agents without any recent claim activity won't show up -- a known limitation until we add explicit heartbeats.

Use -q to print just names, one per line, for shell piping (e.g. looping over agents with xargs).

FlagsSection anchor link

FlagDescription
--profile NAMEProfile name (required)
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
-o, --output FMTOutput format (json|table)
-q, --quietPrint just agent names, one per line

ExamplesSection anchor link

# List agents on prod
sparkwing cluster agents list --profile prod

# Just agent names for piping
sparkwing cluster agents list --profile prod -q

sparkwing cluster concurrencySection anchor link

Inspect a concurrency namespace: holders + queue

Shows who currently holds a concurrency namespace's slots and the queue of waiters behind it, each with its position (0 == next in line). Use it to tell whether a node is wedged or simply waiting its turn for a full OnLimit:Queue slot.

Hits GET /api/v1/concurrency/{namespace}/state on the selected profile's controller.

FlagsSection anchor link

FlagDescription
--namespace NAMEConcurrency namespace to inspect (required)
--profile NAMEProfile selecting the controller (required)
-o, --output FORMATOutput format (json|table)

ExamplesSection anchor link

# Who holds and who's queued
sparkwing cluster concurrency --namespace deploy-prod --profile prod

sparkwing cluster gcSection anchor link

Sweep stale warm-PVC state

Operator-facing manual invocation of the warm-PVC sweep. Normally fires at 'sparkwing cluster worker' startup; exposed as a subcommand so operators can trigger it against a running pod via kubectl exec during incident response.

When --profile is omitted, the run-directory sweep is skipped; the mtime-based git/ and tmp/ sweeps still run and free disk. Supply --profile to enable the full sweep.

FlagsSection anchor link

FlagDescription
--root DIRWarm-PVC root (default: $SPARKWING_HOME resolution)
--profile NAMEProfile name; without it run-dir sweep is skipped

ExamplesSection anchor link

# mtime-only sweep in-pod (no controller)
sparkwing cluster gc

# Full sweep against prod controller
sparkwing cluster gc --profile prod

# Target a specific warm root
sparkwing cluster gc --root /var/lib/sparkwing --profile prod

sparkwing cluster imageSection anchor link

Rollout helpers for images referenced by a gitops repo

Composite verbs that operate on the images: block of a kustomization.yaml plus the downstream ArgoCD / kubectl dance. Building and pushing images stays with the consumer pipeline -- this subcommand only owns the "bump tag, commit, push, sync, wait for rollout" path.

SubcommandsSection anchor link

  • rollout -- Bump a kustomization newTag, commit+push, sync ArgoCD, wait for rollout

ExamplesSection anchor link

# Bump sparkwing-runner to a new commit tag
sparkwing cluster image rollout --image sparkwing-runner --tag commit-abc123 --profile prod --wait

sparkwing cluster image rolloutSection anchor link

Bump a kustomization image tag, commit+push, sync ArgoCD, optionally wait

Rewrites the newTag: field for the image whose entry in the gitops repo's kustomization.yaml matches --image (suffix match against the ECR / registry URL), commits + pushes the change, optionally triggers an ArgoCD sync, and optionally blocks on kubectl rollout status.

Gitops repo resolution order:

  1. --gitops-repo PATH explicit flag
  2. ~/code/gitops (the author's default layout)

The command is idempotent: if the newTag already matches --tag there is nothing to commit, and the pipeline continues to sync

  • wait without error. Use --dry-run to preview the plan without writing, committing, pushing, syncing, or waiting.

Optional tools are skipped cleanly when absent from PATH:

  • argocd missing -> sync is skipped with a one-line notice
  • kubectl missing -> --wait / --tail-logs error before side effects

This verb does NOT build or push the image itself. The consumer pipeline that produced --tag is responsible for publishing the image to the registry before calling rollout.

FlagsSection anchor link

FlagDescription
--image NAMEShort image name (matches the suffix of the ECR URL) (required)
--tag TAGNew tag to write in kustomization.yaml (required)
--profile NAMEProfile name. Reserved for future per-profile gitops repo + argocd context discovery. (required)
--gitops-repo PATHGitops repo path (default: ~/code/gitops)
--namespace NSKubernetes namespace for rollout status + logs (default: sparkwing)
--argocd-app NAMEArgoCD app name (default: derived from --image)
--message MSGCommit message (default: 'chore: bump to ')
--waitBlock until 'kubectl rollout status deployment/' returns
--tail-logsAfter rollout, 'kubectl logs -f -l app=' until ctrl-c
--dry-runPrint what would happen without writing, committing, pushing, or syncing

ExamplesSection anchor link

# Dry-run against the sparkwing-runner image
sparkwing cluster image rollout --image sparkwing-runner --tag commit-abc123 --profile prod --dry-run

# Bump and wait for the rollout
sparkwing cluster image rollout --image sparkwing-runner --tag commit-abc123 --profile prod --wait

# Bump, sync, wait, then tail pod logs
sparkwing cluster image rollout --image sparkwing --tag commit-abc123 --profile prod --wait --tail-logs

sparkwing cluster statusSection anchor link

Connectivity + fleet + queue health check against a remote cluster

Answers "is this cluster alive?" in one command. Runs the connectivity / auth probes from 'profiles test' plus cluster- state probes that hit /api/v1/agents, /api/v1/pool, /api/v1/triggers (status=claimed), and /api/v1/runs?since=24h.

Sections:

CONNECTIVITY controller / auth / logs / gitcache FLEET agents (connected vs stale) + warm-runner pool QUEUE stuck triggers + recent-run success rate

Exit 0 when every probe is ok or warn; exit 1 when any probe fails (auth reject, controller down, HTTP 5xx). Warnings are informational -- low success rate, empty pool, stale agents -- and don't change the exit code so scripts can still condition on "is the cluster reachable at all?".

FlagsSection anchor link

FlagDescription
--profile NAMEProfile name (default: current default) (required)
-o, --output FMTOutput format: pretty|json

ExamplesSection anchor link

# Quick-check prod
sparkwing cluster status --profile prod

# Structured output for a status dashboard
sparkwing cluster status --profile prod -o json

sparkwing cluster tokensSection anchor link

Manage controller API tokens

All subcommands resolve controller URL + admin bearer from the named profile (or the default profile when --profile is omitted). Token creation prints the raw value to stdout exactly ONCE -- stash it immediately.

SubcommandsSection anchor link

  • create -- Mint a new token (prints raw value once)
  • list -- List token prefixes + metadata (never prints raw)
  • revoke -- Mark a token revoked so further requests 401
  • lookup -- Print metadata for a single token by prefix
  • rotate -- Mint a replacement token with a grace window

sparkwing cluster tokens createSection anchor link

Mint a new API token

Creates a token of the given --type scoped to --principal. Comma-separated --scope lists which API surfaces the token may call. The raw token is printed to stdout exactly once; after this command exits it cannot be recovered.

FlagsSection anchor link

FlagDescription
--type KINDToken type: user | runner | service (required)
--principal NAMEFree-form label identifying the token holder (required)
--scope CSVComma-separated scopes (e.g. jobs:read,jobs:write)
--ttl DURATIONToken lifetime (e.g. 30d, 720h). 0 = never expires
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Mint a service token with write scopes
sparkwing cluster tokens create --type service --principal deploy-bot --scope jobs:read,jobs:write

# Mint a user token that expires in 30 days
sparkwing cluster tokens create --type user --principal alice --scope admin --ttl 720h

sparkwing cluster tokens listSection anchor link

List token prefixes + metadata

Prints the non-secret prefix + metadata (type, principal, scopes, last-used) for every token. The raw token value is never printed by this command.

The SCOPES column shows the comma-separated scope set granted to each token. Tokens carrying the controller's "admin" superset render as "*" since admin short-circuits every other scope check. An empty scope set renders as "-".

Use -o json to get a structured array with explicit scope arrays, suitable for piping into jq.

FlagsSection anchor link

FlagDescription
--type KINDFilter by token type
--include-revokedInclude revoked tokens in the output
-o, --output FORMATOutput format: pretty | json (default: pretty)
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# List all active tokens
sparkwing cluster tokens list

# Audit every revoked service token
sparkwing cluster tokens list --type service --include-revoked

# Inspect the warm-runner pool token's scopes as JSON
sparkwing cluster tokens list --profile prod -o json | jq '.[] | select(.principal=="agent:sparkwing-warm-runner") | .scopes'

sparkwing cluster tokens lookupSection anchor link

Print metadata for a single token

Prints the JSON metadata for a token given its non-secret prefix. Useful for confirming principal + scopes before revoking or rotating.

FlagsSection anchor link

FlagDescription
--prefix PREFIXNon-secret token prefix (required)
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Inspect a token before revoking
sparkwing cluster tokens lookup --prefix a1b2c3d4

sparkwing cluster tokens revokeSection anchor link

Mark a token revoked

Subsequent requests using the token receive HTTP 401. Revocation is immediate and irreversible.

FlagsSection anchor link

FlagDescription
--prefix PREFIXNon-secret token prefix (from 'tokens list') (required)
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Revoke a leaked token
sparkwing cluster tokens revoke --prefix a1b2c3d4

sparkwing cluster tokens rotateSection anchor link

Mint a replacement token with a grace window

Creates a new token and schedules the old token for revocation after --grace. During the grace window, both tokens work, which lets callers cycle credentials without downtime.

FlagsSection anchor link

FlagDescription
--prefix PREFIXNon-secret prefix of the token to rotate (required)
--grace DURATIONWindow during which the old token still authenticates (default: 24h)
--ttl DURATIONTTL of the new token (0 = preserve the old token's remaining TTL)
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Rotate a token with a 48h grace window
sparkwing cluster tokens rotate --prefix a1b2c3d4 --grace 48h

sparkwing cluster usersSection anchor link

Manage dashboard login users

Seeds admin credentials in the controller's users table, used by the web pod's login flow. Connection info comes from the selected profile; --profile overrides the default.

SubcommandsSection anchor link

  • add -- Create a user with a password (prompts hidden on stdin)
  • list -- Print every user + created_at + last_login_at
  • delete -- Remove a user (active sessions stay until expiry)

sparkwing cluster users addSection anchor link

Create a dashboard user

Prompts for a password on stdin with echo disabled when stdin is a TTY (the password is not shown on-screen or recorded in shell history). Passing --password skips the prompt -- useful for CI seed flows but leaks via shell history if used interactively.

FlagsSection anchor link

FlagDescription
--name NAMEDashboard username (required)
--password PASSWORDPassword (omit to prompt interactively)
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Interactive add
sparkwing cluster users add --name alice

# Non-interactive add for CI
sparkwing users add --name ci-bot --password "$CI_BOT_PW"

sparkwing cluster users deleteSection anchor link

Remove a dashboard user

Deletes the user row. Any sessions that user holds remain valid until their individual expiry -- sparkwing does not proactively invalidate active cookies on delete.

FlagsSection anchor link

FlagDescription
--name NAMEDashboard username to remove (required)
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Delete a user
sparkwing cluster users delete --name alice

sparkwing cluster users listSection anchor link

Print every user

Prints name, created_at, and last_login_at for every user in the controller's users table.

FlagsSection anchor link

FlagDescription
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# List users on the default profile
sparkwing cluster users list

# List users on prod
sparkwing cluster users list --profile prod

sparkwing cluster webhooksSection anchor link

Inspect and replay GitHub webhooks

Sparkwing-aware wrapper over the GitHub hooks API. Shells out to 'gh api' (inherits your gh auth); install gh from https://cli.github.com if it isn't on PATH.

Value-add over 'gh api' alone: the deliveries view joins GitHub's delivery log with sparkwing's trigger/run rows so each delivery shows the run id it produced and the run's terminal status -- without two separate lookups.

SubcommandsSection anchor link

  • list -- List hooks on a repo + derived pipeline name
  • deliveries -- Recent deliveries for one hook, joined with trigger state
  • replay -- Queue a redelivery of a specific delivery UUID

ExamplesSection anchor link

# List hooks on a repo
sparkwing cluster webhooks list --repo your-org/my-app --profile prod

# Recent deliveries for a hook
sparkwing cluster webhooks deliveries --repo your-org/my-app --hook 608819334 --since 1h --profile prod

sparkwing cluster webhooks deliveriesSection anchor link

List recent deliveries for a hook, joined with trigger state

Fetches recent deliveries via 'gh api' and, for each one, looks up the matching sparkwing trigger by GITHUB_DELIVERY env stamp. Surfaces TRIGGER_ID + RUN_STATUS columns so operators see GitHub-side status alongside the run it produced.

--since filters deliveries client-side (GitHub's API does not take a time filter). Default: 24h.

FlagsSection anchor link

FlagDescription
--repo OWNER/NAMEGitHub repo (required)
--hook NGitHub hook id from 'webhooks list' (required)
--since DURATIONOnly deliveries newer than this (default: 24h)
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
-o, --output FMTOutput format (json|table)
--profile NAMEProfile name (used for trigger/run lookups) (required)

ExamplesSection anchor link

# Recent deliveries for a hook
sparkwing cluster webhooks deliveries --repo your-org/my-app --hook 608819334 --since 1h --profile prod

sparkwing cluster webhooks listSection anchor link

List GitHub hooks configured on a repo

Calls 'gh api /repos/OWNER/NAME/hooks' and prints id, derived pipeline, active flag, last-delivery status, and URL.

The PIPELINE column is parsed from the hook URL path (/webhooks/github/). Hooks posting to the legacy unscoped /webhooks/github endpoint render as "(unscoped, legacy)" so operators can spot them for cleanup. Non-sparkwing hooks render as "(non-sparkwing)".

FlagsSection anchor link

FlagDescription
--repo OWNER/NAMEGitHub repo (owner can be omitted if gh has a default) (required)
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
-o, --output FMTOutput format (json|table)
--profile NAMEProfile name (reserved for symmetry; unused by list)

ExamplesSection anchor link

# List hooks on a repo
sparkwing cluster webhooks list --repo your-org/my-app --profile prod

sparkwing cluster webhooks replaySection anchor link

Queue a redelivery of a specific delivery UUID

POSTs /repos/OWNER/NAME/hooks/HOOK/deliveries/DELIVERY/attempts to GitHub. GitHub queues a fresh attempt; the new delivery appears in the hook's delivery log within seconds.

FlagsSection anchor link

FlagDescription
--repo OWNER/NAMEGitHub repo (required)
--hook NGitHub hook id (required)
--delivery UUIDDelivery GUID to redeliver (required)
--profile NAMEProfile name (reserved; unused by replay)

ExamplesSection anchor link

# Redeliver a webhook attempt
sparkwing cluster webhooks replay --repo your-org/my-app --hook 608819334 --delivery 0ac55946-3e96-11f1-9de8-f33e32f0060f --profile prod

sparkwing cluster workerSection anchor link

Claim triggers from a profile's controller and run them in-process

Polls the trigger queue at the selected profile's controller and executes each claimed trigger in-process. Laptop-local: no K8s, no warm pool, no image dispatch. For the cluster-mode worker with --runner k8s|warm and image / service-account flags, use sparkwing-runner.

Run against a remote controller via --profile prod (or whichever profile), or against a local 'sparkwing dashboard start' via --profile local. With --profile omitted, uses the default profile from profiles.yaml.

FlagsSection anchor link

FlagDescription
--profile PROFILEProfile name from profiles.yaml (default: default profile)
--poll DURClaim poll interval when the queue is empty (default: 1s)
--heartbeat DURClaim-lease heartbeat cadence (default: 5s)

ExamplesSection anchor link

# Run against the default profile
sparkwing cluster worker

# Run against a named profile
sparkwing cluster worker --profile local

# Faster polling for tight dev loops
sparkwing cluster worker --profile local --poll 250ms

sparkwing commandsSection anchor link

Emit the full CLI surface as structured data (agent self-discovery)

Returns every registered verb -- path, synopsis, description, positional args, flags, examples, subcommand list -- as one JSON document. Designed as the agent's "what is this CLI" probe: one tool call replaces walking every -h page.

The same Command record powers --help on every verb; this just emits all of them in one shot. Filter with --path PREFIX to narrow to a subtree (e.g. --path "sparkwing pipeline"). Default output is JSON because agents are the primary audience; -o plain emits one path per line for shell consumption.

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: json | plain | pretty (default: json)
--path PREFIXOnly emit commands whose Path starts with PREFIX
--include-hiddenAlso emit Hidden:true commands (default: skip)

ExamplesSection anchor link

# Full CLI surface (agent self-discovery)
sparkwing commands

# Just the pipelines subtree
sparkwing commands --path "sparkwing pipeline"

# All paths, one per line
sparkwing commands -o plain

sparkwing completionSection anchor link

Emit a shell completion script (bash|zsh|fish)

Prints a completion script for the selected shell. Source it from your shell rc:

# bash source <(sparkwing completion --shell bash)

# zsh (add 'autoload -U compinit; compinit' once above) source <(sparkwing completion --shell zsh)

# fish sparkwing completion --shell fish | source

zsh and fish get per-item descriptions; bash is name-only because compgen lacks the facility.

FlagsSection anchor link

FlagDescription
--shell NAMEbash | zsh | fish (required)

ExamplesSection anchor link

# Wire completion for the current zsh session
source <(sparkwing completion --shell zsh)

# Install persistent completion for fish
sparkwing completion --shell fish > ~/.config/fish/completions/sparkwing.fish

sparkwing configureSection anchor link

Configure laptop-local settings

Laptop-local setup commands. 'init' is the one-shot "prepare ~/.config/sparkwing/ + report what's there" command; 'profiles' manages remote-cluster connection profiles. Future laptop-level surfaces (aliases, default flags, per-repo config) land here.

Controller-side state (users, tokens) lives under 'sparkwing cluster ...' since it writes to the remote controller, not the local config. Secrets are top-level ('sparkwing secrets ...').

SubcommandsSection anchor link

  • init -- Set up ~/.config/sparkwing/ and report laptop-level config status
  • profiles -- Manage connection profiles for remote controllers
  • xrepo -- Cross-repo registry: list / add / remove / prune local checkouts

ExamplesSection anchor link

# First-time laptop setup
sparkwing configure init

# Status of laptop config
sparkwing configure init -o json

# List profiles
sparkwing configure profiles list

# Add a new profile
sparkwing configure profiles add --name prod --controller https://api.sparkwing.example --token $TOKEN

# Register the current repo with the cross-repo registry
sparkwing configure xrepo add

sparkwing configure initSection anchor link

Set up ~/.config/sparkwing/ and report laptop-level config status

Idempotent setup + status command for laptop-level sparkwing config. Creates ~/.config/sparkwing/ if it doesn't exist, then reports which config files are present (profiles.yaml, repos.yaml, secrets.env), the running CLI + Go toolchain version, and a curated list of next-step commands.

Pairs with the per-project flow: use this one on a fresh laptop after install, then run 'sparkwing pipeline new --name ' inside each project to scaffold .sparkwing/ + your first pipeline in one step (no separate init needed).

Re-running on an already-set-up laptop is a no-op status report. --dry-run skips the mkdir so the command pure-probes.

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
--dry-runProbe + report without creating ~/.config/sparkwing/

ExamplesSection anchor link

# First-time laptop setup
sparkwing configure init

# Status of laptop config (agent-readable)
sparkwing configure init -o json

# Probe without writing anything
sparkwing configure init --dry-run

sparkwing configure profilesSection anchor link

Manage connection profiles for remote controllers

Profile config lives at $SPARKWING_PROFILES (if set), else $XDG_CONFIG_HOME/sparkwing/profiles.yaml, else ~/.config/sparkwing/profiles.yaml. Permissions on save are 0600.

Every human-driven client command (tokens, users, jobs retry/cancel/prune/logs, gc) reads connection info from the selected profile via --profile NAME. No --controller/--token flags exist on other commands; profiles are the only config surface.

SubcommandsSection anchor link

  • add -- Register a new profile
  • list -- Print every profile; * marks the default
  • show -- Print one profile's full config
  • use -- Set the default profile
  • remove -- Delete a profile
  • duplicate -- Copy one profile's config into another
  • set -- Update fields on an existing profile
  • test -- Probe controller/auth/logs/gitcache for one profile

sparkwing configure profiles addSection anchor link

Register a new connection profile

Creates a new entry in profiles.yaml. --name and --controller are mandatory; the rest are optional. When this is the first profile registered, it's auto-set as the default.

FlagsSection anchor link

FlagDescription
--name NAMEProfile name (unique per profiles.yaml) (required)
--controller URLController base URL (required)
--logs URLLogs-service base URL
--token TOKENBearer token (omit for local/unauthed stacks)
--gitcache URLgitcache URL (fleet-worker uses this)
--default-runner NAMERunner name to pick when a job's Prefers don't match and several runners satisfy Requires (omit for local)
--defaultSet this profile as the default

ExamplesSection anchor link

# Add a prod profile
sparkwing configure profiles add --name prod --controller https://api.sparkwing.example --token $TOKEN

# Add a local profile without auth
sparkwing configure profiles add --name local --controller http://127.0.0.1:4344

# Add a profile that defaults to a cluster runner
sparkwing configure profiles add --name prod --controller https://api.sparkwing.example --token $TOKEN --default-runner cloud-linux

sparkwing configure profiles duplicateSection anchor link

Copy one profile's config into another

Useful when you want to tweak a known-good profile (say, change the token for a staging rotation) without hand-editing yaml.

FlagsSection anchor link

FlagDescription
--src NAMESource profile name (required)
--dst NAMEDestination profile name (must not exist yet) (required)

ExamplesSection anchor link

# Branch prod into a staging-prod profile
sparkwing configure profiles duplicate --src prod --dst staging-prod

sparkwing configure profiles listSection anchor link

Print every registered profile

Prints a table of profile name, controller URL, logs URL, token (redacted), and gitcache URL. The default profile is marked with a leading '*'.

ExamplesSection anchor link

# List profiles
sparkwing configure profiles list

sparkwing configure profiles removeSection anchor link

Delete a profile

Removes the entry from profiles.yaml. If the removed profile was the default, no new default is auto-picked -- operators must pass --profile on every call or set one via 'sparkwing profiles use --name '.

FlagsSection anchor link

FlagDescription
--name NAMEProfile name to remove (required)

ExamplesSection anchor link

# Remove a stale profile
sparkwing configure profiles remove --name old-stage

sparkwing configure profiles setSection anchor link

Update fields on an existing profile

Only flags you pass are overwritten. --token="" explicitly clears the token (empty value, not an omitted flag). Use --show-token on 'profiles show' afterward to confirm.

FlagsSection anchor link

FlagDescription
--name NAMEProfile name to mutate (required)
--controller URLNew controller URL
--logs URLNew logs-service URL
--token TOKENNew bearer token (empty string clears)
--gitcache URLNew gitcache URL
--default-runner NAMERunner name (empty clears, falls back to local)

ExamplesSection anchor link

# Rotate a profile's token
sparkwing configure profiles set --name prod --token $NEW_TOKEN

# Clear a stale logs URL
sparkwing profiles set --name prod --logs=""

# Point a profile at a different default runner
sparkwing configure profiles set --name prod --default-runner cloud-gpu

sparkwing configure profiles showSection anchor link

Print one profile's full config

Prints all fields of the profile named by --name. Token is redacted unless --show-token is passed. Omitting --name prints the current default profile.

FlagsSection anchor link

FlagDescription
--name NAMEProfile name (default: current default)
--show-tokenPrint the raw token (redacted by default)

ExamplesSection anchor link

# Show the default profile
sparkwing configure profiles show

# Show a named profile with the raw token
sparkwing configure profiles show --name prod --show-token

sparkwing configure profiles testSection anchor link

Probe controller/auth/logs/gitcache for one profile

Sequentially checks the profile's controller (/api/v1/health), auth (/api/v1/runs?limit=1 + /api/v1/auth/whoami), logs service (if configured), and gitcache (if configured). Each probe prints ok / warn / fail along with latency and any error detail.

Exit code is non-zero when any probe fails. Missing optional services (logs, gitcache) count as warn, not fail, so a minimally-configured laptop profile can still exit 0.

FlagsSection anchor link

FlagDescription
--profile NAMEProfile name (default: current default)
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
-o, --output FMTOutput format (json|table)

ExamplesSection anchor link

# Probe the default profile
sparkwing configure profiles test

# Probe a named profile
sparkwing configure profiles test --profile prod

# JSON for scripting
sparkwing configure profiles test --profile prod -o json

sparkwing configure profiles useSection anchor link

Set the default profile

Updates profiles.yaml so commands run without --profile target this profile. The previous default is untouched beyond losing its default status.

FlagsSection anchor link

FlagDescription
--name NAMEProfile name to mark as default (required)

ExamplesSection anchor link

# Switch the default to prod
sparkwing configure profiles use --name prod

sparkwing dashboardSection anchor link

Manage the local dashboard + API server

Background lifecycle for the laptop-local dashboard. 'start' spawns a detached server (writes PID + log under $SPARKWING_HOME), 'kill' stops it, 'status' reports liveness.

The server is one Go process that hosts the embedded Next.js SPA, the JSON API, the log endpoints, and the SQLite store on the same port. There is no separate Node process. The dashboard is purely for visualization -- everything it shows is reachable from the CLI as well.

SubcommandsSection anchor link

  • start -- Spawn the detached dashboard server (idempotent)
  • kill -- Stop a running dashboard server
  • status -- Report whether the dashboard is running

ExamplesSection anchor link

# Start the dashboard
sparkwing dashboard start

# Check liveness
sparkwing dashboard status

# Stop the dashboard
sparkwing dashboard kill

sparkwing dashboard killSection anchor link

Stop a running dashboard server

Sends SIGTERM to the PID recorded in $SPARKWING_HOME/dashboard.pid, polls for exit, escalates to SIGKILL after 5s if necessary, and removes the PID file. No-op (exit 0) when nothing is running.

FlagsSection anchor link

FlagDescription
--home DIRState directory (default: $SPARKWING_HOME or ~/.sparkwing)

ExamplesSection anchor link

# Stop the dashboard
sparkwing dashboard kill

sparkwing dashboard startSection anchor link

Spawn the detached dashboard server (idempotent)

Detaches a child process that runs the in-process dashboard + API + logs server (pkg/localws). PID is written to $SPARKWING_HOME/dashboard.pid; stdout/stderr are appended to $SPARKWING_HOME/dashboard.log. Returns once the listener is accepting TCP connections so callers can immediately curl it.

Idempotent: if a live server is already on file, prints the URL and returns 0 without spawning a duplicate.

FlagsSection anchor link

FlagDescription
--addr HOST:PORTBind address (default: 127.0.0.1:4343)
--home DIRState directory (default: $SPARKWING_HOME or ~/.sparkwing)
--profile PROFILEProfile from ~/.config/sparkwing/profiles.yaml (uses its log_store + artifact_store)
--log-store URLPluggable log backend URL (fs:///abs/path, s3://bucket/prefix). Overrides --profile.
--artifact-store URLPluggable artifact backend URL (fs:///abs/path, s3://bucket/prefix). Overrides --profile.
--read-onlyReject writes on /api/v1/* (auth + webhooks remain open)
--no-local-storeSkip local SQLite; list runs from --artifact-store. Requires --log-store + --artifact-store.

ExamplesSection anchor link

# Start with defaults
sparkwing dashboard start

# Use an alternate port
sparkwing dashboard start --addr 127.0.0.1:5000

# Isolate state under a scratch dir
sparkwing dashboard start --home /tmp/sparkwing-x

# Tail CI runs from S3 (no SQLite)
sparkwing dashboard start --profile ci-smoke --no-local-store --read-only

sparkwing dashboard statusSection anchor link

Report whether the dashboard is running

Reads $SPARKWING_HOME/dashboard.pid, probes the PID with kill(0), and reports running state + URL. Exit code 0 when running, 1 when not.

FlagsSection anchor link

FlagDescription
--home DIRState directory (default: $SPARKWING_HOME or ~/.sparkwing)

ExamplesSection anchor link

# Check liveness
sparkwing dashboard status

sparkwing debugSection anchor link

Interactive debugging for pipeline runs

Pause nodes at selected hook points, inspect the paused pod, drop into a shell, or release the node. Every debug verb is ephemeral -- pause directives live only on the run they launch, never in pipeline source. Pipelines stay production-clean.

SubcommandsSection anchor link

  • run -- Run a pipeline with --pause-before / --pause-after / --pause-on-failure
  • release -- Resume a paused node
  • attach -- kubectl exec into a paused node's pod (cluster mode)
  • env -- Print a paused node's env + workdir + claim holder
  • rerun -- Reproduce a node's dispatch frame and drop into a shell
  • replay -- Headlessly re-execute a single node from a prior run

ExamplesSection anchor link

# Pause before the tests node
sparkwing debug run build --pause-before tests

# Resume a paused node
sparkwing debug release --run run-X --node tests

sparkwing debug attachSection anchor link

kubectl exec into a paused node's pod (cluster mode)

Looks up the pod holding the paused node's claim-lease from the controller's node row, then shells out to kubectl exec -it -- bash. Local mode prints a note that attach does not apply (the process is already in your current shell's world) and exits 0.

FlagsSection anchor link

FlagDescription
--run IDRun ID holding the paused node (required)
--node NAMENode ID to attach to (required)
--profile NAMEProfile name (cluster mode)

ExamplesSection anchor link

# Attach in prod
sparkwing debug attach --run run-X --node tests --profile prod

sparkwing debug envSection anchor link

Print a paused node's env + workdir + claim holder

Inspection-only command: reads the stored node record (env map, claim holder, current pause state) and prints them to stdout. Does NOT spawn a shell. If the node is not paused, prints a warning and exits 0 -- env info is captured at pause time, not continuously.

FlagsSection anchor link

FlagDescription
--run IDRun ID holding the node (required)
--node NAMENode ID to inspect (required)
--profile NAMEProfile name (cluster mode)

ExamplesSection anchor link

# Inspect locally
sparkwing debug env --run run-X --node tests

sparkwing debug releaseSection anchor link

Resume a paused node

Flips the pause row's released_at timestamp so the orchestrator's poll loop wakes and continues dispatching past the pause point. Local and cluster modes share this surface.

FlagsSection anchor link

FlagDescription
--run IDRun ID holding the paused node (required)
--node NAMENode ID to release (required)
--profile NAMEProfile name (cluster mode)

ExamplesSection anchor link

# Release locally
sparkwing debug release --run run-X --node tests

# Release in prod
sparkwing debug release --run run-X --node tests --profile prod

sparkwing debug replaySection anchor link

Re-execute a single node headlessly using its dispatch snapshot

Mints a new run row linked to the original via replay_of_run_id / replay_of_node_id, creates a single nodes row for the target, and exec's the pipeline binary to execute that one node. The node's input struct is reconstituted from the stored dispatch snapshot; upstream Refs resolve against the original run's outputs without re-executing them.

Replay is "what would this node do now, with the same args+env?": secrets re-resolve fresh through sparkwing.Secret, BeforeRun hooks re-fire, and any code drift in the registered job struct (renamed type, removed field) aborts loud rather than silently producing wrong results.

With --profile PROF, the original run + target node + dep outputs + dispatch snapshot are first fetched from the named controller via HTTP and side-loaded into the local store. Replay execution itself always runs locally because the user's sparkwing binary owns the registered pipeline factories.

FlagsSection anchor link

FlagDescription
--run IDRun ID holding the original node (required)
--node NAMENode ID to re-execute (required)
--profile PROFSideload from this profile's controller before replaying locally

ExamplesSection anchor link

# Replay a node locally
sparkwing debug replay --run run-X --node deploy

# Replay a prod run on your laptop
sparkwing debug replay --profile prod --run run-X --node deploy

sparkwing debug rerunSection anchor link

Reproduce a node's dispatch frame in an interactive shell

Reads the dispatch snapshot for the given run/node and reproduces the env + workdir the orchestrator saw at dispatch time. Local mode exec's $SHELL with the snapshot env applied and writes upstream Ref outputs to ~/.sparkwing/rerun///refs so they're cat-able from the shell. Cluster mode shells out to 'kubectl run' against a runner image (--image or $SPARKWING_RERUN_IMAGE) with the snapshot env materialized as --env=K=V flags.

Replays do NOT freeze the rest of the cluster: secrets re-resolve through the standard sparkwing.Secret API on demand, and the runner image is whatever the cluster runs today. Replay is "what would this node do now, with the args+env it had then?", not a frozen reproduction.

Default --seq selects the most-recent attempt for the node; pass --seq 0 (or another integer) to target a specific attempt index.

FlagsSection anchor link

FlagDescription
--run IDRun ID holding the node (required)
--node NAMENode ID to reproduce (required)
--seq NAttempt index; -1 selects most recent
--profile NAMEProfile name (cluster mode)
--image REFRunner image for cluster-mode debug pod (cluster mode)

ExamplesSection anchor link

# Rerun locally
sparkwing debug rerun --run run-X --node tests

# Rerun a specific attempt
sparkwing debug rerun --run run-X --node tests --seq 1

# Rerun in prod
sparkwing debug rerun --run run-X --node tests --profile prod --image ghcr.io/me/runner:v1

sparkwing debug runSection anchor link

Run a pipeline with ephemeral pause directives

Runs the named pipeline exactly as 'sparkwing run ' would, with additional pause hooks the orchestrator honors before and after each matching node. Directives travel as env vars to the pipeline binary; they never land in git-tracked code.

--pause-before holds the node BEFORE its Run is invoked. --pause-after holds the node AFTER its Run returns (success or failure). Both flags are repeatable. --pause-on-failure holds ANY node whose Run returns a non-nil error. Skipped / cancelled / OnFailure-recovered nodes do NOT pause -- only honest Run errors.

Paused nodes hold for 30 minutes by default; set SPARKWING_PAUSE_TIMEOUT= to change. A timed-out pause is released with reason 'timeout-released' and surfaces in the run record.

See 'sparkwing debug release' to resume, 'sparkwing debug env' to inspect, and 'sparkwing debug attach' (cluster mode) to shell into the pod holding the paused node.

FlagsSection anchor link

FlagDescription
--pipeline NAMEPipeline (pipeline) name to run under debug supervision (required)
--pause-before NODEHold NODE before Run (repeatable)
--pause-after NODEHold NODE after Run (repeatable)
--pause-on-failureHold any node whose Run errors

ExamplesSection anchor link

# Pause before tests
sparkwing debug run --pipeline build --pause-before tests

# Pause on failure
sparkwing debug run --pipeline build --pause-on-failure

sparkwing docsSection anchor link

Embedded user docs (offline)

The sparkwing docs are shipped inside the binary. sparkwing docs read --topic getting-started returns the raw markdown to stdout; sparkwing docs all dumps every doc in one shot for an agent that wants the full corpus in context. The docs match the binary version exactly -- no risk of the website explaining a flag your CLI doesn't have.

Discovery: sparkwing docs list -o json returns slug + title + summary for every topic. sparkwing docs search --query "warm pool" substring-matches across slug + title + body.

SubcommandsSection anchor link

  • list -- Enumerate every doc topic (slug, title, summary)
  • read -- Print one doc's markdown to stdout (--topic NAME)
  • all -- Concatenate every doc to stdout (full corpus dump)
  • search -- Substring search across docs (--query TEXT)
  • migrations -- Per-version migration guides (list / read / between)
  • versions -- List doc versions known to this CLI (and sparkwing.dev with --web)
  • cache -- Inspect / clear the on-disk cache used by --web

ExamplesSection anchor link

# List all topics (table)
sparkwing docs list

# List all topics (agent-readable)
sparkwing docs list -o json

# Read one topic
sparkwing docs read --topic pipelines

# Read one topic at a specific version (online)
sparkwing docs read --topic pipelines --version v0.3.0 --web

# Slurp the whole corpus into context
sparkwing docs all

# Find docs that mention warm pool
sparkwing docs search --query "warm pool"

# List migration guides this CLI knows
sparkwing docs migrations list

# Pipe every guide up to v0.4.0 into context
sparkwing docs migrations between --to v0.4.0

# List every version available online
sparkwing docs versions --web

sparkwing docs allSection anchor link

Concatenate every doc to stdout (full corpus dump)

Prints every embedded doc to stdout, separated by short ASCII headers. The "give me everything" path for an agent that wants the full corpus in context with one Bash invocation.

ExamplesSection anchor link

# Slurp every doc into context
sparkwing docs all

sparkwing docs cacheSection anchor link

Inspect or clear the on-disk cache used by --web

--web fetches are cached to $XDG_CACHE_HOME/sparkwing/web/ (or ~/.cache/sparkwing/web/). The cache mirrors the URL path, so you can cat the cached files directly when debugging.

Use cache info to see size / counts; use cache clear to wipe it.

SubcommandsSection anchor link

  • info -- Print cache dir, total size, per-resource breakdown
  • clear -- Remove every cached file (refuses to escape the cache dir)

ExamplesSection anchor link

# How big is the cache?
sparkwing docs cache info

# Force-refresh on next --web call
sparkwing docs cache clear

sparkwing docs cache clearSection anchor link

Remove every cached file

Deletes every file under the cache directory. Safe: the implementation refuses to remove paths that don't resolve inside the cache dir, so a stray symlink in the cache can't escape.

Useful when a cached versions.json or index.json has gone stale faster than the 24h TTL window, or when debugging --web behavior.

ExamplesSection anchor link

# Wipe the cache
sparkwing docs cache clear

sparkwing docs cache infoSection anchor link

Print cache dir, total size, per-resource breakdown

Walks the cache and prints a summary: total size, file counts broken down by doc / migration / index, and the freshness state of the cached versions.json (24h TTL).

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json (default: pretty)

ExamplesSection anchor link

# Human-readable
sparkwing docs cache info

# Agent-readable
sparkwing docs cache info -o json

sparkwing docs listSection anchor link

Enumerate every doc topic

Walks the docs corpus and prints one row per topic with its slug, first-H1 title, and first-paragraph summary. By default reads the binary's embedded copy (hermetic, version-locked); pass --web to fetch from sparkwing.dev for another version.

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
--webFetch from sparkwing.dev instead of the embedded corpus
--version vX.Y.ZDoc version (e.g. v0.4.0, 'latest'). Defaults to this CLI's embedded version.
--no-cacheWith --web, bypass the on-disk cache for this invocation

ExamplesSection anchor link

# Human-readable table
sparkwing docs list

# Agent-readable
sparkwing docs list -o json

# Slug-per-line for shell loops
sparkwing docs list -o plain

# List the v0.3.0 corpus from sparkwing.dev
sparkwing docs list --web --version v0.3.0

sparkwing docs migrationsSection anchor link

Per-version migration guides (agent-friendly)

Surface the migration guides shipped under docs/migrations/. Each released sparkwing version that introduces breaking changes gets a guide; sparkwing docs migrations between concatenates every guide in a version range into one blob you can pipe straight into an agent context.

The same files are also reachable as regular docs (e.g. sparkwing docs read --topic migrations/v0.4.0); this subcommand is the ergonomics layer with semver-aware filtering and range output.

SubcommandsSection anchor link

  • list -- Table of every migration guide this CLI knows about
  • read -- Print one migration guide to stdout (--version vX.Y.Z)
  • between -- Concatenate every guide in (--from, --to] into one blob

ExamplesSection anchor link

# List embedded migration guides
sparkwing docs migrations list

# Read one guide
sparkwing docs migrations read --version v0.4.0

# Every guide upgrading from v0.3.0 to v0.4.0
sparkwing docs migrations between --from v0.3.0 --to v0.4.0

# Every guide this CLI knows (one-shot agent context)
sparkwing docs migrations between

sparkwing docs migrations betweenSection anchor link

Concatenate every guide in a version range into one blob

Returns every migration guide whose version is in (--from, --to], in ascending version order, separated by markdown horizontal rules. The output starts with a "Migration: vA -> vB" header so an agent knows the range up-front.

This is the agent-killer command: one invocation produces the full migration context for an N-version jump in a form ready to pipe.

--from defaults to v0.0.0 (every guide up through --to). --to defaults to the highest version this CLI knows about.

FlagsSection anchor link

FlagDescription
--from vX.Y.ZExclusive lower bound (default v0.0.0)
--to vA.B.CInclusive upper bound (default = latest embedded version)
-o, --output FORMATOutput format: markdown | plain (default: markdown)
--webFetch every guide in the range from sparkwing.dev
--no-cacheWith --web, bypass the on-disk cache for this invocation

ExamplesSection anchor link

# Every guide for a v0.3.0 -> v0.4.0 jump
sparkwing docs migrations between --from v0.3.0 --to v0.4.0

# Every guide up to a target version
sparkwing docs migrations between --to v0.4.0

# Every guide this CLI knows (one-shot agent context)
sparkwing docs migrations between

# Full range from sparkwing.dev (includes versions not yet embedded)
sparkwing docs migrations between --web

sparkwing docs migrations listSection anchor link

Table of every embedded migration guide

Lists each migration guide bundled with this binary in descending semver order, with date and one-line summary parsed from docs/migrations/README.md. Use --output json for an agent-readable array of {version, date, summary, slug, bytes}.

When the CLI's own version is older than the newest embedded guide a one-line stderr note suggests rebuilding.

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
--webFetch the index from sparkwing.dev/migrations/index.json instead of the embed
--no-cacheWith --web, bypass the on-disk cache for this invocation

ExamplesSection anchor link

# Human-readable table
sparkwing docs migrations list

# Agent-readable
sparkwing docs migrations list -o json

# Version-per-line for shell loops
sparkwing docs migrations list -o plain

# Online (every release on sparkwing.dev)
sparkwing docs migrations list --web

sparkwing docs migrations readSection anchor link

Print one migration guide's markdown to stdout

Outputs the markdown body for a single migration guide. Default output is the raw markdown so an agent can pipe straight into its context. Cross-doc markdown links to other topics are rewritten into sparkwing docs read --topic <slug> form (same transform as sparkwing docs read).

ArgumentsSection anchor link

  • [vX.Y.Z] (optional) -- Migration guide version, when --version is not supplied

FlagsSection anchor link

FlagDescription
--version vX.Y.ZMigration guide version (e.g. v0.4.0). Positional fallback accepted.
-o, --output FORMATOutput format: markdown | plain (default: markdown)
--webFetch from sparkwing.dev instead of the embedded corpus
--no-cacheWith --web, bypass the on-disk cache for this invocation

ExamplesSection anchor link

# Read the v0.4.0 guide
sparkwing docs migrations read --version v0.4.0

# Positional shortcut
sparkwing docs migrations read v0.4.0

# Read v0.5.0 from sparkwing.dev (not yet embedded)
sparkwing docs migrations read --version v0.5.0 --web

sparkwing docs readSection anchor link

Print one doc's raw markdown to stdout

Prints the raw markdown body for the named topic. The slug is the filename under /docs/ minus .md (run sparkwing docs list to see them all). Subdirs use slash-separated paths (e.g. design/remote-retry).

Default source is the binary's embedded corpus. Use --web to fetch from sparkwing.dev, optionally pinned to --version vX.Y.Z or --version latest.

FlagsSection anchor link

FlagDescription
--topic NAMEDoc slug (e.g. getting-started, pipelines, mcp) (required)
--webFetch from sparkwing.dev instead of the embedded corpus
--version vX.Y.ZDoc version (e.g. v0.4.0, 'latest'). Defaults to this CLI's embedded version.
--no-cacheWith --web, bypass the on-disk cache for this invocation

ExamplesSection anchor link

# Read the getting-started page
sparkwing docs read --topic getting-started

# Pipe through a pager
sparkwing docs read --topic pipelines | less

# Read v0.3.0's pipelines page online
sparkwing docs read --topic pipelines --version v0.3.0 --web

# Always fetch the freshest version
sparkwing docs read --topic pipelines --version latest --web

Substring search across embedded docs

Returns every doc whose slug + title + body contains every space-separated token in --query (case-insensitive). Hits in title/slug rank above body-only matches. Output shape matches sparkwing docs list so -o json composes the same way.

FlagsSection anchor link

FlagDescription
-q, --query TEXTSearch terms (every token must match) (required)
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)

ExamplesSection anchor link

# Find docs about the warm pool
sparkwing docs search --query "warm pool"

# JSON for agents
sparkwing docs search -q approval -o json

sparkwing docs versionsSection anchor link

List doc versions known to this CLI (and sparkwing.dev with --web)

Reports each doc version the source knows about. Default output is hermetic: only the binary's embedded version (plus every migration-guide version shipped in the embed) appears, with no network calls.

With --web, fetches sparkwing.dev/versions.json and merges in every release available online -- useful for discovering newer versions this CLI can render via --web on the read / list verbs.

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
--webMerge in sparkwing.dev/versions.json (network)
--no-cacheWith --web, bypass the on-disk cache for this invocation

ExamplesSection anchor link

# Embedded only (default)
sparkwing docs versions

# Every version available online
sparkwing docs versions --web

# Agent-readable JSON
sparkwing docs versions --web -o json

sparkwing infoSection anchor link

Self-describe sparkwing + the current project (agent entrypoint)

One command that answers "what is sparkwing, am I in a project, what should I run next" without prior knowledge. Prints the CLI version, whether the current directory is inside a sparkwing project (and how many pipelines it has), whether the Go toolchain is on PATH, a curated list of next-step commands, and the docs URL.

This is the canonical first command an agent runs after install. Use -o json for structured output that an agent can parse, or -o plain to emit one next-step command per line for shell pipelines (head -n1 yields the most-likely next command).

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
--for-agentEmit a paste-ready block for CLAUDE.md / AGENTS.md (no ANSI, no extras)
--first-timePrint the post-install onboarding card (used by install.sh; re-runnable any time)

ExamplesSection anchor link

# Human-readable card
sparkwing info

# Agent-readable record
sparkwing info -o json

# Paste into CLAUDE.md / AGENTS.md
sparkwing info --for-agent >> CLAUDE.md

# Reprint the post-install onboarding card
sparkwing info --first-time

sparkwing maintenanceSection anchor link

Sweep the local concurrency tables without a controller

Runs the janitorial pass the controller normally runs on a schedule, but against the local state database with no controller required. Reaps lease-expired concurrency holders and promotes the next queued waiters, deletes stale and orphaned waiters, sweeps expired and over-cap cache rows, and reconciles keys with idle capacity.

Local runs trigger this pass inline, throttled to once every few minutes. Run this command to force a full pass now -- from cron, or to reclaim a database that grew while the box sat idle. It touches only finished or expired rows, so it is safe to run alongside live runs.

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)

ExamplesSection anchor link

# Sweep now
sparkwing maintenance

# Machine-readable summary
sparkwing maintenance -o json

# Hourly from cron
0 * * * * sparkwing maintenance

sparkwing pipelineSection anchor link

This repo's pipelines

Per-project namespace. Every verb here operates on the nearest .sparkwing/ walking up from the current directory.

Discovery (list / describe / discover / explain) shows what pipelines this repo defines. 'new' scaffolds a fresh pipeline (auto-bootstraps .sparkwing/ on first use). 'run' invokes one (positional name; same as 'sparkwing run '). 'hooks' wires pipelines to git pre-commit / pre-push / post-commit. 'sparks' manages reusable spark libraries declared in .sparkwing/sparks.yaml.

The discovery verbs (list / describe / discover / templates) support -o json so an agent can parse output directly rather than scraping tab-complete.

To bump the pipeline SDK pin in .sparkwing/go.mod, use 'sparkwing version update --sdk'. To see the current pin, run 'sparkwing version' (composite card).

SubcommandsSection anchor link

  • list -- Enumerate every pipeline with metadata
  • describe -- Print one pipeline's full metadata
  • discover -- Fuzzy search over names, descriptions, tags
  • new -- Scaffold a new pipeline (auto-bootstraps .sparkwing/ if missing)
  • templates -- List the sparks-core template registry (starters for new --template)
  • explain -- Render the pipeline's Plan DAG without running
  • plan -- Render the runtime-resolved DAG (would-run/would-skip) without running
  • run -- Invoke a pipeline (canonical form of sparkwing run <name>)
  • trigger -- Submit a pipeline to a profile's controller (remote execution)
  • hooks -- Git pre-commit / pre-push / post-commit hooks: install / uninstall / status
  • sparks -- Manage sparks libraries: list / add / remove / lint / resolve / update / warmup

ExamplesSection anchor link

# Machine-readable catalog
sparkwing pipeline list -o json

# One pipeline's details
sparkwing pipeline describe --name release -o json

# Search by intent
sparkwing pipeline discover --query "tag a release"

# First pipeline in a fresh repo (auto-bootstraps)
sparkwing pipeline new --name release

# Inspect the DAG before running
sparkwing pipeline explain --name release-all

# Run a pipeline
sparkwing pipeline run release

sparkwing pipeline describeSection anchor link

Print one pipeline's full metadata

Emits the full record for a single pipeline: kind, group, description, typed args, examples, triggers, and (for scripts) frontmatter-declared positional args and flags. Always resolves hidden entries -- if you're asking for a name explicitly, the hidden flag shouldn't surprise you.

FlagsSection anchor link

FlagDescription
--name NAMEPipeline name to describe (required)
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)

ExamplesSection anchor link

# Human-readable
sparkwing pipeline describe --name release

# Agent-readable
sparkwing pipeline describe --name release -o json

sparkwing pipeline discoverSection anchor link

Fuzzy search over pipeline names + descriptions + tags

Search the catalog by intent. Every token in --query must match some haystack field (name / short / help / group / tags / triggers); matches in the name score higher than matches in prose so direct hits surface first.

-o json emits {name, kind, group, ..., score} records sorted by score descending; agents should prefer -o json for consumption.

FlagsSection anchor link

FlagDescription
--query TEXTSearch query (one or more tokens, all must hit some field) (required)
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)

ExamplesSection anchor link

# Find release-related pipelines
sparkwing pipeline discover --query release

# Multi-token, all must hit
sparkwing pipeline discover --query "tag release"

# Agent-readable ranked hits
sparkwing pipeline discover --query deploy -o json

sparkwing pipeline explainSection anchor link

Render the pipeline's Plan DAG without dispatching any jobs

Compiles the nearest .sparkwing/ binary, calls the named pipeline's Plan method, and prints the resulting DAG (nodes, dependencies, approval gates) without running a single job.

Any --flag value tokens that are NOT recognized by explain itself (i.e. anything other than --name / --all / -o/--output / --help) are forwarded to the pipeline so Plans that branch on --env / --version / etc. can be previewed under realistic inputs. Missing required args are non-fatal here -- explain renders a best-effort plan so the shape is visible before every flag is provided.

--all sweeps every pipeline in .sparkwing/sparkwing.yaml, runs Plan() on each with no extra args, and exits non-zero if any pipeline fails. Designed as a CI gate: a Plan-time validation mismatch (sparkwing.RefTo[T] type drift, Produces[T] / SetResult asymmetry, duplicate node ID, etc.) blocks merges before the pipeline ever runs.

FlagsSection anchor link

FlagDescription
--name NAMEPipeline to explain (one of --name or --all required)
--allValidate every pipeline in this repo's sparkwing.yaml; non-zero exit on any failure
-o, --output FORMATOutput format: pretty | json (default: pretty)

ExamplesSection anchor link

# Inspect release-all's DAG
sparkwing pipeline explain --name release-all

# Preview with args (forwarded to the pipeline)
sparkwing pipeline explain --name example-release --env prod

# Agent-readable JSON
sparkwing pipeline explain --name release-all -o json

# Validate every pipeline (CI gate)
sparkwing pipeline explain --all

sparkwing pipeline hooksSection anchor link

Install / uninstall git pre-commit + pre-push + post-commit hooks

Writes small git hook scripts into the repo's .git/hooks/ directory that call 'sparkwing run ' for every pipeline that declares pre_commit:, pre_push:, or post_commit: in its .sparkwing/sparkwing.yaml triggers block.

The post-commit hook is non-blocking: the commit has already landed, so it runs its pipelines, tolerates failures, and never aborts. pre-commit and pre-push abort the git action on the first failing pipeline.

Managed hooks carry a "Installed by sparkwing" marker so uninstall and status can tell them apart from hand-written hooks. Existing unmanaged hooks are left alone; install skips them with a warning.

SubcommandsSection anchor link

  • install -- Write pre-commit / pre-push / post-commit hooks for the enclosing repo
  • uninstall -- Remove sparkwing-managed git hooks
  • status -- Report which sparkwing hooks are installed

sparkwing pipeline hooks installSection anchor link

Install pre-commit / pre-push / post-commit git hooks from sparkwing.yaml triggers

Discovers the enclosing .sparkwing/sparkwing.yaml, reads pre_commit / pre_push / post_commit triggers, and writes one hook file per hook name that fans out to the matching pipelines. Existing non-sparkwing hooks are skipped so hand-written ones survive.

FlagsSection anchor link

FlagDescription
--repo DIRRepo directory (default: discovered via nearest .sparkwing/)

ExamplesSection anchor link

# Install in the current repo
sparkwing pipeline hooks install

# Install in a different repo
sparkwing pipeline hooks install --repo /path/to/repo

sparkwing pipeline hooks statusSection anchor link

Report which sparkwing hooks are installed

Lists every managed hook file under .git/hooks/ along with the pipelines it invokes. Prints a hint when nothing is installed.

FlagsSection anchor link

FlagDescription
--repo DIRRepo directory (default: discovered via nearest .sparkwing/)

ExamplesSection anchor link

# Show hook status
sparkwing pipeline hooks status

sparkwing pipeline hooks uninstallSection anchor link

Remove sparkwing-managed git hooks

Deletes every file under .git/hooks/ that carries the "Installed by sparkwing" marker. Hand-written hooks are left alone.

FlagsSection anchor link

FlagDescription
--repo DIRRepo directory (default: discovered via nearest .sparkwing/)

ExamplesSection anchor link

# Uninstall in the current repo
sparkwing pipeline hooks uninstall

sparkwing pipeline listSection anchor link

Enumerate every pipeline with metadata

Walks up from the current directory to locate .sparkwing/, merges sparkwing.yaml entries with the describe cache's typed metadata, and prints a grouped aligned table.

-o json emits structured records instead; agents should prefer -o json since tab-complete / table output is for human reading.

--all includes entries marked 'hidden: true'. By default they're omitted.

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
--allInclude entries marked hidden

ExamplesSection anchor link

# Human-readable table
sparkwing pipeline list

# Agent-readable catalog
sparkwing pipeline list -o json

# Include hidden entries
sparkwing pipeline list --all

sparkwing pipeline newSection anchor link

Scaffold a new Go pipeline

Creates a stub pipeline in the nearest .sparkwing/: jobs/.go plus a sparkwing.yaml entry. Auto-bootstraps .sparkwing/ on first use, so a fresh repo's first scaffold sets up the package skeleton too -- no separate init step, no sample pipeline you didn't ask for.

Before building by hand, browse the ready-made starters: 'sparkwing pipeline templates' lists task-shaped registry templates (Go CI hygiene, docker/static deploys for AWS+GCP, migrations, ...); scaffold one with --template [--param k=v ...].

Pass --sw-cd/-C to scaffold into a repo other than the current directory (the .sparkwing search re-anchors there).

Built-in templates (registry templates are listed by 'pipeline templates'):

  • minimal (default): single-node Plan with a stubbed Run. Smallest viable shape; the editor's first move is replacing the placeholder Info() line with real logic.
  • build-test-deploy: three-node Plan (build -> test -> deploy) with echo Run bodies that print a placeholder line on each step. The canonical CI shape; first 'sparkwing run ' surfaces three exec banners + three echoed lines so the structure is visible end-to-end.

Refuses to clobber: if the name already exists in sparkwing.yaml the command fails before writing anything.

Supply --hidden to hide from default listings; --short to pre-fill the description.

See also: If your pipeline is a single linear shell sequence with no DAG, retry, or cross-runner concerns, a plain shell-script runner (e.g. just / make / a wrapper over ./bin/*.sh) is probably a better fit -- it skips the compile cycle.

FlagsSection anchor link

FlagDescription
--name NAMENew pipeline's kebab-case name (a-z, 0-9, -) (required)
-C, --sw-cd DIRScaffold as if started in this directory (re-anchors the .sparkwing search)
--template KINDminimal | build-test-deploy | any registry name from sparkwing pipeline templates (default: minimal)
--param K=VRegistry template parameter (repeatable); see sparkwing pipeline templates
--hiddenMark the entry hidden in default tab-complete menus
--short TEXTPre-fill the ShortHelp / desc line (built-in templates only)

ExamplesSection anchor link

# Single-node pipeline (default template)
sparkwing pipeline new --name release

# Build/test/deploy DAG (three-node)
sparkwing pipeline new --name release-all --template build-test-deploy

# From a registry template
sparkwing pipeline new --name deploy --template go-test-build-deploy-k8s --param image=myapp --param namespace=myapp --param app-name=myapp --param health-url=http://myapp.myapp.svc:8080/health

sparkwing pipeline planSection anchor link

Render the runtime-resolved DAG without dispatching any jobs

Compiles the nearest .sparkwing/ binary, calls the named pipeline's Plan method, and prints the runtime-resolved DAG -- the same structure 'explain' shows plus a per-step decision ("would_run" / "would_skip ") evaluated under the supplied args and --start-at / --stop-at bounds. NO step bodies execute.

Skip reasons surface their cause:

  • user_skipif : a SkipIf predicate would match at run time
  • range_skip : item is outside the --start-at..--stop-at window

For SpawnNodeForEach generators (dynamic fan-out), cardinality is reported as "unresolved" with a pointer to the source item -- the honest answer when the count depends on a runtime value.

State-loading caveat: if a step normally populates in-memory state that downstream steps consume, --start-at past it leaves state empty. The plan output reflects this honestly (downstream steps show "would_run") but operators should design step bodies to lazy-load when state isn't populated, so resume-from-step is safe.

Like 'explain', this is the read-only pre-flight surface; pair with 'sparkwing run ' to actually dispatch.

FlagsSection anchor link

FlagDescription
--name NAMEPipeline to plan
--start-at STEPSkip every WorkStep upstream of STEP in the resulting plan
--stop-at STEPSkip every WorkStep downstream of STEP in the resulting plan
-o, --output FORMATOutput format: pretty | json (default: pretty)

ExamplesSection anchor link

# Resolve cluster-up's DAG with current args
sparkwing pipeline plan --name cluster-up

# Preview a resume-from-step
sparkwing pipeline plan --name cluster-up --start-at install-argocd

# Agent-readable JSON for diff against expectations
sparkwing pipeline plan --name release-all -o json

sparkwing pipeline runSection anchor link

Invoke a pipeline (canonical form of sparkwing run <name>)

Compiles the nearest .sparkwing/ binary and exec's it with the named pipeline. Identical to the top-level shortcut 'sparkwing run '.

The pipeline name is the only positional in the sparkwing surface -- a deliberate exception, kept short because run is typed many times a day.

Any flag not recognized by run itself is forwarded to the pipeline binary, e.g. 'sparkwing pipeline run release --version v1.2.3' passes --version through to the pipeline's Args.

ArgumentsSection anchor link

  • <pipeline> (required) -- Pipeline name registered in .sparkwing/sparkwing.yaml

FlagsSection anchor link

FlagDescription
-C, --sw-cd PATHRun as if started in PATH
--sw-ref REFRun the pipeline at REF (branch/tag/SHA) instead of the working tree
-v, --sw-verboseEnable debug logging
--sw-start-at STEPStart the run at STEP
--sw-stop-at STEPStop the run after STEP
--sw-only GLOBRun only jobs whose ID matches GLOB (plus their Needs ancestors)
--sw-no-cacheIgnore cached per-node results (writes still happen)
--sw-local-onlyForce local state, cache, and logs for this run; ignore any configured shared backends
--sw-dry-runRun each step's dry-run probe instead of its real action
--sw-allow LABEL[,LABEL...]Authorize risk-labeled steps (repeatable)
--profile NAMERun / read against the named profile from ~/.config/sparkwing/profiles.yaml (default: laptop)
--target TARGETRun against the named pipeline deployment target (e.g. dev, prod)
--sw-box-slots NMax concurrent sparkwing run processes on this host (default: max(1, NumCPU/SPARKWING_WORKERS); use 0 or off to disable)
--sw-no-waitFail immediately when box slots are full instead of queueing

ExamplesSection anchor link

# Run with no flags
sparkwing pipeline run build-test-deploy

# Pass a typed pipeline arg
sparkwing pipeline run release --version v0.28.1

# Run from a different git ref
sparkwing pipeline run build-test-deploy --sw-ref feature/xyz

# Dispatch remotely
sparkwing pipeline trigger deploy --profile prod

sparkwing pipeline sparksSection anchor link

Manage sparks libraries declared in .sparkwing/sparks.yaml

Sparks libraries are Go modules that add opinionated helpers (Docker builds, GitOps deploys, ECR auth, language-specific checks) on top of the unopinionated SDK. Consumers declare which libraries they want live-tracked in .sparkwing/sparks.yaml; the resolver writes an overlay modfile at .sparkwing/.resolved.mod that the compile step uses via 'go build -modfile='. The consumer's git-tracked go.mod is never modified.

See docs/sparks.md for the full spec (spark.json schema, sparks.yaml shape, resolution rules, warmup).

SubcommandsSection anchor link

  • list -- Show declared libraries and resolved versions
  • lint -- Validate a spark.json library manifest
  • resolve -- Resolve versions and materialize the overlay modfile
  • update -- Re-resolve one or all libraries
  • add -- Add a library to sparks.yaml
  • remove -- Remove a library from sparks.yaml
  • warmup -- Pre-compile pipeline binaries and upload to gitcache

ExamplesSection anchor link

# List declared sparks libraries
sparkwing pipeline sparks list

# Validate a library's spark.json
sparkwing pipeline sparks lint ~/code/sparks-core

# Re-materialize the overlay modfile
sparkwing pipeline sparks resolve

# Add a library pinned to latest
sparkwing pipeline sparks add github.com/sparkwing-dev/sparks-core

sparkwing pipeline sparks addSection anchor link

Add a library to sparks.yaml

Appends a new entry to .sparkwing/sparks.yaml. Defaults the version to 'latest' when --version is omitted. Refuses to add a duplicate (same source or same name).

FlagsSection anchor link

FlagDescription
--source PATHGo module path (e.g. github.com/user/sparks-lib) (required)
--version VERDeclared version ('latest', exact tag, or semver range)
--name NAMEShort library name (default: last path segment of --source)
--sparkwing-dir DIRPath to .sparkwing/ (default: /.sparkwing)

ExamplesSection anchor link

# Add a library pinned to latest
sparkwing pipeline sparks add --source github.com/sparkwing-dev/sparks-core

# Add with a semver range
sparkwing pipeline sparks add --source github.com/sparkwing-dev/sparks-core --version "^v0.10.0"

sparkwing pipeline sparks lintSection anchor link

Validate a spark.json library manifest

Loads spark.json from the given path (or the current directory if omitted) and checks: required fields (name, description, author, packages), that each packages[] path exists as a directory under the module root, stability values are valid, and package paths are not duplicated. Unknown fields are a soft warning, not an error. Exits non-zero on any hard failure.

FlagsSection anchor link

FlagDescription
--path PATHLibrary directory or direct spark.json path (default: .)

ExamplesSection anchor link

# Lint the library in the current directory
sparkwing pipeline sparks lint

# Lint a sibling library by path
sparkwing pipeline sparks lint --path ~/code/sparks-core

sparkwing pipeline sparks listSection anchor link

Show declared sparks libraries and their resolved versions

Reads .sparkwing/sparks.yaml and prints one row per declared library with its declared constraint and the resolved tag (found via the module proxy). Use --no-resolve to skip the proxy calls when offline.

FlagsSection anchor link

FlagDescription
--sparkwing-dir DIRPath to .sparkwing/ (default: /.sparkwing)
-o, --output FMTOutput format: pretty|json|plain
--no-resolveSkip module-proxy lookups; print declared versions only

ExamplesSection anchor link

# Table output
sparkwing pipeline sparks list

# JSON for scripting
sparkwing pipeline sparks list -o json

# Offline (no proxy calls)
sparkwing pipeline sparks list --no-resolve

sparkwing pipeline sparks removeSection anchor link

Remove a library from sparks.yaml

Removes the entry matching NAME (or matching its source path).

FlagsSection anchor link

FlagDescription
--name NAMELibrary name or source path to remove (required)
--sparkwing-dir DIRPath to .sparkwing/ (default: /.sparkwing)

ExamplesSection anchor link

# Remove by short name
sparkwing pipeline sparks remove --name sparks-core

# Remove by source path
sparkwing pipeline sparks remove --name github.com/sparkwing-dev/sparks-core

sparkwing pipeline sparks resolveSection anchor link

Resolve versions and materialize the overlay modfile

Runs the same pipeline as 'sparkwing run ' takes before compile: load sparks.yaml, resolve each entry against the module proxy, and write .sparkwing/.resolved.mod + .resolved.sum. Idempotent -- a second run with no upstream change is a fast no-op that prints 'up-to-date'. Never modifies the git-tracked go.mod.

FlagsSection anchor link

FlagDescription
--sparkwing-dir DIRPath to .sparkwing/ (default: /.sparkwing)
-q, --quietSuppress the 'up-to-date' message

ExamplesSection anchor link

# Resolve and write the overlay
sparkwing pipeline sparks resolve

# Quiet mode for scripts
sparkwing pipeline sparks resolve -q

sparkwing pipeline sparks updateSection anchor link

Re-resolve one or all libraries

Re-runs resolution for every declared library (or a single named one) and re-materializes the overlay modfile. For a range or 'latest' constraint this picks up any new tag from the module proxy; for an exact pin it is a no-op.

FlagsSection anchor link

FlagDescription
--name NAMERestrict update to one library (name or source); omit to update all
--sparkwing-dir DIRPath to .sparkwing/ (default: /.sparkwing)

ExamplesSection anchor link

# Update every declared library
sparkwing pipeline sparks update

# Update one by name
sparkwing pipeline sparks update --name sparks-core

sparkwing pipeline sparks warmupSection anchor link

Pre-compile pipeline binaries after a sparks release

Post-release optimization: resolve the latest versions, compile the pipeline binary for the current .sparkwing/ tree, and upload to gitcache so the next 'sparkwing run' in-cluster or on a fresh laptop gets a cache hit instead of paying the full compile cost.

Uses the exact same build path as 'sparkwing run', so the cache key matches. Warmup is optional -- pipelines always resolve on build -- it just removes the first-run compile cost after a new sparks version is published.

FlagsSection anchor link

FlagDescription
--sparkwing-dir DIRPath to .sparkwing/ (default: /.sparkwing)
--clear-cacheDelete the local pipeline binary cache before compiling

ExamplesSection anchor link

# Warm up the current repo's pipelines
sparkwing pipeline sparks warmup

# Force a fresh compile
sparkwing pipeline sparks warmup --clear-cache

sparkwing pipeline templatesSection anchor link

List the sparks-core template registry

Lists the curated, parameterized pipeline starters in the sparks-core/templates registry -- the values usable as 'sparkwing pipeline new --template '. Each entry shows a "when to use" signal and its required / optional parameters.

These are distinct from the two built-in stubs (minimal, build-test-deploy) that ship in the CLI itself: the registry templates are richer, real-world shapes (build-test-deploy to k8s, static-site, migrate+deploy, ...).

-o json emits the manifests (name, description, whenToUse, parameters, applicability) -- prefer it for agent consumption.

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json (default: pretty)

ExamplesSection anchor link

# Browse the registry
sparkwing pipeline templates

# Agent-readable manifests
sparkwing pipeline templates -o json

# Scaffold from one
sparkwing pipeline new --name deploy --template go-test-build-deploy-k8s --param image=myapp

sparkwing pipeline triggerSection anchor link

Submit a pipeline to a profile's controller (remote execution)

Submits a trigger to the controller defined by --profile and follows the remote run until it reaches a terminal state.

When the profile defines a logs URL, the follow streams full log output; otherwise it shows node-status updates from the controller. --detach skips the follow and prints the run id once the trigger is registered (the trigger POST itself always completes before the command exits, so the run is guaranteed queued).

Any flag not recognized here is forwarded to the pipeline as a typed Arg, e.g. 'sparkwing pipeline trigger release --profile prod --version v1.2.3' passes --version through to the trigger payload -- same shape as 'sparkwing run'.

Requires a profile with controller: set. For local execution against a profile's storage, use 'sparkwing run --profile X'.

ArgumentsSection anchor link

  • <pipeline> (required) -- Pipeline name registered on the controller

FlagsSection anchor link

FlagDescription
--profile NAMEProfile (from ~/.config/sparkwing/profiles.yaml) whose controller runs the pipeline (required)
--detachReturn once the trigger is registered (print the run id); don't follow

ExamplesSection anchor link

# Submit and follow
sparkwing pipeline trigger release --profile prod --version v1.2.3

# Fire-and-forget; print run id and exit
sparkwing pipeline trigger release --profile prod --detach

sparkwing profileSection anchor link

Show which profile sparkwing would use right now, and why

Reports the profile a sparkwing command would resolve to and the chain that picked it (flag > project hint > detect > default > builtin laptop), using the same resolver 'sparkwing run' and 'sparkwing pipeline trigger' use -- so the answer matches what they would actually do.

With no flag it shows the active no-flag resolution. With --profile NAME it shows the hypothetical: what adding that flag to your next command would select. Tokens are never printed.

FlagsSection anchor link

FlagDescription
--profile NAMEShow the hypothetical resolution for --profile NAME
-o, --output FORMATOutput format: pretty|json (default: pretty)

ExamplesSection anchor link

# Active profile with no flag
sparkwing profile

# What would --profile prod pick
sparkwing profile --profile prod

# Machine-readable
sparkwing profile -o json

sparkwing runSection anchor link

Invoke a pipeline

Compiles the nearest .sparkwing/ binary and exec's it with the named pipeline.

The pipeline name is the only positional in the sparkwing surface -- a deliberate exception, kept short because run is typed many times a day. Every other input is a named flag.

Any flag not recognized by run itself is forwarded to the pipeline binary, e.g. 'sparkwing run release --version v1.2.3' passes --version through to the pipeline's Args.

For remote execution on a profile's controller, use 'sparkwing pipeline trigger --profile PROF'.

Output: a human-readable per-node summary when stdout is a terminal, line-delimited JSON otherwise (so piped/agent/CI consumers get a stable JSONL stream). Force a format with SPARKWING_LOG_FORMAT=pretty|json|quiet. quiet collapses the run to a progress line plus a one-line pass/fail status with the run id, surfacing the failing step only on failure; it is the default for managed git hooks.

ArgumentsSection anchor link

  • <pipeline> (required) -- Pipeline name registered in .sparkwing/sparkwing.yaml

FlagsSection anchor link

FlagDescription
-C, --sw-cd PATHRun as if started in PATH
--sw-ref REFRun the pipeline at REF (branch/tag/SHA) instead of the working tree
-v, --sw-verboseEnable debug logging
--sw-start-at STEPStart the run at STEP
--sw-stop-at STEPStop the run after STEP
--sw-only GLOBRun only jobs whose ID matches GLOB (plus their Needs ancestors)
--sw-no-cacheIgnore cached per-node results (writes still happen)
--sw-local-onlyForce local state, cache, and logs for this run; ignore any configured shared backends
--sw-dry-runRun each step's dry-run probe instead of its real action
--sw-allow LABEL[,LABEL...]Authorize risk-labeled steps (repeatable)
--profile NAMERun / read against the named profile from ~/.config/sparkwing/profiles.yaml (default: laptop)
--target TARGETRun against the named pipeline deployment target (e.g. dev, prod)
--sw-box-slots NMax concurrent sparkwing run processes on this host (default: max(1, NumCPU/SPARKWING_WORKERS); use 0 or off to disable)
--sw-no-waitFail immediately when box slots are full instead of queueing

ExamplesSection anchor link

# Run with no flags
sparkwing run build-test-deploy

# Pass a typed pipeline arg
sparkwing run release --version v0.28.1

# Run from a different git ref
sparkwing run build-test-deploy --sw-ref feature/xyz

# Retry a failed run
sparkwing runs retry RUN_ID --failed

# Submit to a remote controller
sparkwing pipeline trigger deploy --profile prod

sparkwing run configSection anchor link

Print the resolved Config struct + declared Secrets for a pipeline + target

Pure inspection: resolves the pipeline's typed Config struct through the same layering sparkwing run uses (struct defaults < sparkwing.yaml values.base < per-target values) and prints each field's resolved value alongside which layer contributed it. Also lists every declared Secret with its source binding -- useful before driving destructive --for prod runs to confirm you'd hit the right vault.

Honors --for (the target selection). No Plan() runs, nothing dispatches, nothing mutates.

Invocation: sparkwing run <pipeline> config --for <target> -- the pipeline binary handles the subverb directly.

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json (default: pretty)

ExamplesSection anchor link

# Inspect the staging config
sparkwing run release config --for staging

# Agent-readable form
sparkwing run release config --for prod -o json

sparkwing runsSection anchor link

Inspect and control pipeline runs

Runs are the per-invocation records of pipeline execution. Every 'sparkwing run ' produces a run; cluster mode surfaces the same runs remotely via the controller.

Local-mode subcommands (list, status, logs, errors) read from ~/.sparkwing/runs/. Controller-mode subcommands (cancel, retry, prune) require a profile; 'jobs logs' supports both.

SubcommandsSection anchor link

  • list -- List recent runs with filters (pipeline, status, branch, sha, search, etc.)
  • status -- Show a single run's status (with per-step + approval state)
  • summary -- Aggregated work view: groups, work items, modifiers, annotations
  • timeline -- ASCII waterfall of a run's nodes (and steps)
  • wait -- Block until a run reaches a terminal status
  • find -- Find runs matching a git SHA / repo / pipeline filter
  • grep -- Search log bodies across recent runs for a substring
  • logs -- Print a run's logs (optionally --follow)
  • errors -- Surface the error trail for a failed run
  • failures -- List recent failed runs; optional clustering by step
  • stats -- Aggregate stats (pass/fail, success %, avg/p95 duration)
  • last -- Show the most recent run; --watch tails new runs
  • tree -- ASCII tree of a run and every descendant run
  • get -- Emit one run's raw JSON (run + nodes)
  • receipt -- Emit a run's audit + cost receipt as JSON
  • annotations -- Read or append persistent node + step annotations
  • approvals -- List, approve, or deny approval gates
  • triggers -- Inspect trigger envelopes that produced runs
  • retry -- Trigger fresh runs copying pipeline + args from old ones
  • cancel -- Request cancellation of in-flight runs
  • prune -- Delete finished runs older than a threshold, or by id

sparkwing runs annotationsSection anchor link

Read or append persistent node + step annotations

Annotations are short summary strings that pipelines (via sparkwing.Annotate) and agents append to a node or step during a run. They show up on the dashboard alongside outcome. This verb lets an agent read every annotation on a run or contribute one without going through the SDK.

SubcommandsSection anchor link

  • list -- List annotations on a run (optionally filtered to a node/step)
  • add -- Append one annotation to a node or step

sparkwing runs annotations addSection anchor link

Append an annotation to a node or step

Appends one message to the annotations list on a node, or on a step when --step is given. Annotations are append-only; the same message string can be added more than once and the order is preserved as the dashboard renders them.

FlagsSection anchor link

FlagDescription
--run RUN_IDRun identifier (required)
--node NODE_IDNode identifier (required)
--step STEP_IDStep identifier (annotates the step instead of the node)
-m, --message TEXTAnnotation text (required)
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Note something on a node
sparkwing runs annotations add --run run-... --node deploy -m 'agent: retried after 502'

# Note something on a step inside a node
sparkwing runs annotations add --run run-... --node deploy --step canary -m 'rolled out 5%'

sparkwing runs annotations listSection anchor link

List annotations on a run

Prints node-level annotations by default. Pass --steps to also include per-step annotations as separate rows; passing --step implies step-scope and limits to the matching step.

FlagsSection anchor link

FlagDescription
--run RUN_IDRun identifier (required)
--node NODE_IDLimit to one node
--step STEP_IDLimit to one step (implies step-scope reads)
--stepsInclude per-step annotations
-o, --output FORMATOutput format: pretty|json|plain
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Every node annotation on a run
sparkwing runs annotations list --run run-...

# Include per-step annotations
sparkwing runs annotations list --run run-... --steps

# One node's annotations as JSON
sparkwing runs annotations list --run run-... --node build -o json

sparkwing runs approvalsSection anchor link

List approval gates (pending and history)

Inspect approval gates. Without --run returns every pending gate across all runs; with --run returns one run's full history (pending + resolved).

SubcommandsSection anchor link

  • list -- List pending approvals, or one run's history with --run (the default verb)
  • approve -- Approve a pending gate: --run --node [--comment ...]
  • deny -- Deny a pending gate: --run --node [--comment ...]

sparkwing runs approvals approveSection anchor link

Approve a pending approval-gate node

Resolves the named approval gate as 'approved'. The gate's downstream nodes begin dispatching on the next orchestrator poll (roughly 500ms). The approver is recorded from the authenticated principal when --profile is set, or from $USER in local mode.

Exit code is 0 on success, non-zero if the gate doesn't exist or was already resolved (409).

FlagsSection anchor link

FlagDescription
--run IDRun ID holding the approval gate (required)
--node IDNode ID of the approval gate (required)
--comment STROptional note recorded on the approval
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Approve a local gate
sparkwing runs approvals approve --run run-20260423-143012-abcd --node approve-prod

# Approve a prod gate with a comment
sparkwing runs approvals approve --run run-... --node approve-prod --profile prod --comment "release notes ok"

sparkwing runs approvals denySection anchor link

Deny a pending approval-gate node

Resolves the named approval gate as 'denied'. The gated node fails; downstream nodes see the failure and propagate per their ContinueOnError / Optional settings.

FlagsSection anchor link

FlagDescription
--run IDRun ID holding the approval gate (required)
--node IDNode ID of the approval gate (required)
--comment STROptional note recorded on the approval
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Deny a local gate
sparkwing runs approvals deny --run run-20260423-143012-abcd --node approve-prod

# Deny a prod gate with a reason
sparkwing runs approvals deny --run run-... --node approve-prod --profile prod --comment "tests still red"

sparkwing runs approvals listSection anchor link

List pending approvals (or one run's history)

Prints a table of approval rows. Without --run the list is the cross-run pending queue; with --run it's every approval for that run, both pending and resolved.

FlagsSection anchor link

FlagDescription
--run RUN_IDRestrict to one run's approvals
-o, --output FORMATOutput format: pretty|json|plain
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Pending gates on the local store
sparkwing runs approvals list

# Pending gates on prod
sparkwing runs approvals list --profile prod

# Full history for one run
sparkwing runs approvals list --run run-...

# Emit JSON for an agent
sparkwing runs approvals list -o json

sparkwing runs cancelSection anchor link

Request cancellation of in-flight runs

Sends a cancel request per run to the controller. Each run transitions to 'cancelling' and then 'cancelled' once the runner acknowledges. Already-finished runs surface a per-id error but don't abort the batch.

Pass --run once per id (repeatable). Use --run - to read ids from stdin, one per line.

FlagsSection anchor link

FlagDescription
--run RUN_IDRun id to cancel (repeatable; use --run - to read ids from stdin)
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Cancel one run
sparkwing runs cancel --run run-... --profile prod

# Cancel every running prod run
sparkwing runs list --status running --profile prod -q | sparkwing runs cancel --run - --profile prod

sparkwing runs errorsSection anchor link

Surface the error trail for a failed run

Walks the run's node DAG and prints the error chain for any node that failed. Quicker than paging through full logs when you only care about the terminal failure. Reads from the local run store.

FlagsSection anchor link

FlagDescription
--run RUN_IDRun identifier (required)
-o, --output FORMATOutput format: pretty|json|plain

ExamplesSection anchor link

# Inspect a local failure
sparkwing runs errors --run run-20260422-142501-abcd

# As JSON
sparkwing runs errors --run run-... -o json

sparkwing runs failuresSection anchor link

List recent failed runs, optionally clustered

Fetches recent runs with status=failed and extracts the first failing node's step + error message for each. --group-by clusters the output by step so a systemic failure surfaces as one row with a count.

FlagsSection anchor link

FlagDescription
--pipeline NAMERestrict to one pipeline
--since DURATIONOnly failures newer than this (e.g. 24h, 7d)
--limit NMax failures to analyze (default: 20)
--group-by KEYCluster by: step | node
-o, --output FORMATOutput format: pretty|json|plain
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Recent local failures
sparkwing runs failures --since 24h

# Prod failures clustered by step
sparkwing runs failures --profile prod --group-by step

sparkwing runs findSection anchor link

Find runs by git SHA / repo / pipeline filter

Searches recent runs for a match. Use --git-sha to find the run that was fired by a specific commit; add --pipeline to disambiguate when multiple pipelines respond to the same push. --repo matches the GITHUB_REPOSITORY env on the trigger (owner/name), useful when one controller handles webhooks from multiple repos.

With --wait, blocks until at least one match appears, up to --find-timeout. Pairs with 'jobs wait' for the push-and-follow loop:

git push &&
sparkwing runs find --git-sha $(git rev-parse HEAD) --pipeline X --wait --profile prod -q |
xargs -n1 -I{} sparkwing runs wait --run {} --profile prod

Exit code 0 on match, non-zero on timeout-without-match or infrastructure error.

FlagsSection anchor link

FlagDescription
--git-sha SHAMatch runs whose git SHA starts with this value (prefix match)
--pipeline NAMERestrict to one pipeline
--repo OWNER/NAMEMatch trigger's GITHUB_REPOSITORY env
--since DURATIONLookback window (default: 1h)
--limit NMax results (default: 20)
--waitBlock until at least one match appears
--find-timeout DURATIONGive up (nonzero exit) after this long when --wait is set (default: 2m)
-o, --output FORMATOutput format: pretty|json|plain
-q, --quietPrint only run ids, one per line (or a JSON array of ids with -o json)
--profile NAMEProfile name (cluster mode). Omit to search the local SQLite store.

ExamplesSection anchor link

# Find a run by SHA + pipeline on prod
sparkwing runs find --git-sha $(git rev-parse HEAD) --pipeline build-test-deploy --profile prod

# Block until the matching run appears
sparkwing runs find --git-sha abc123 --pipeline X --wait --profile prod

# Pipe matching ids into jobs wait
sparkwing runs find --git-sha abc --wait -q --profile prod | xargs -n1 -I{} sparkwing runs wait --run {} --profile prod

sparkwing runs getSection anchor link

Emit one run's raw JSON (run + nodes)

Prints a combined {run, nodes} JSON blob to stdout. Consumed by agents and scripts that need the full store shape rather than the summary 'status' command renders.

FlagsSection anchor link

FlagDescription
--run RUN_IDRun identifier (required)
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Fetch a local run as JSON
sparkwing runs get --run run-...

# Fetch a prod run
sparkwing runs get --run run-... --profile prod

sparkwing runs grepSection anchor link

Search log bodies across recent runs for a substring

Walks the runs matching the filter set and substring-greps every node's log. Reuses the same filter flags as runs list so the candidate set is identical to what that verb would return. In cluster mode the grep runs server-side per (run, node), so only matching bytes come back over the wire.

Default output is a table of RUN / NODE / LINE / TEXT. -q (quiet) prints just the unique matching run ids -- the usual shape for piping into runs logs or runs status.

Exit code 0 even when there are no matches.

FlagsSection anchor link

FlagDescription
--pattern TEXTSubstring to match (case-sensitive) (required)
--pipeline NAMERestrict candidate runs to one pipeline (repeatable; ! to exclude)
--status STATUSRestrict by status (repeatable; ! to exclude)
--branch BRANCHRestrict by git branch (repeatable; ! to exclude)
--sha PREFIXRestrict by git sha prefix (repeatable; ! to exclude)
--since DURATIONOnly runs newer than this
--started-after DATEOnly runs whose StartedAt >= this
--started-before DATEOnly runs whose StartedAt <= this
--limit NMax candidate runs to scan (default: 50)
--max-matches MPer-node match cap (0 = no cap) (default: 5)
-o, --output FORMATOutput format: pretty|json|plain (default: pretty on TTY, json when piped)
-q, --quietPrint only the unique matching run ids
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Find every run that hit a permission-denied line in the past week
sparkwing runs grep --pattern 'permission denied' --since 7d

# Pipe matching run ids into runs logs
sparkwing runs grep --pattern OOMKilled --since 24h -q | xargs -I{} sparkwing runs logs --run {}

# Search prod runs as JSON for an agent
sparkwing runs grep --pattern 'connection refused' --profile prod --since 24h -o json

sparkwing runs lastSection anchor link

Print the most recent run

Shorthand for 'jobs list --limit 1' with a compact one-line output. --watch tails for new runs, reprinting whenever a newer run ID appears.

FlagsSection anchor link

FlagDescription
--pipeline NAMERestrict to one pipeline
-w, --watchTail for new runs
-o, --output FORMATOutput format: pretty|json|plain
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Local last run
sparkwing runs last

# Watch prod for new runs
sparkwing runs last --profile prod --watch

sparkwing runs listSection anchor link

List recent pipeline runs

Without --profile, reads from the local run directory. With --profile NAME, fetches from the named profile's controller. Filters compose with AND semantics across flag types (pipeline=X AND status=Y), OR semantics within a repeated flag (pipeline=X OR pipeline=Y).

With -q / --quiet the output is just run ids, one per line, for shell piping:

sparkwing runs list --pipeline X --limit 1 -q --profile prod
| xargs -I{} sparkwing runs logs --run {} --profile prod --follow

FlagsSection anchor link

FlagDescription
--pipeline NAMEFilter by pipeline name (repeatable; prefix ! to exclude)
--status STATUSFilter by status: running|success|failed|cancelled (repeatable; prefix ! to exclude)
--tag TAGFilter by sparkwing.yaml tag (repeatable)
--branch BRANCHFilter by git branch (repeatable; prefix ! to exclude)
--sha PREFIXFilter by git sha prefix (repeatable; prefix ! to exclude)
--error SUBSTRSubstring match against the persisted failure reason
--search QUERYFree-text search across pipeline/branch/sha/id/error; prefix a term with - to exclude
--since DURATIONOnly runs newer than this (e.g. 1h, 24h, 7d)
--started-after DATEOnly runs whose StartedAt >= this (today, yesterday, 24h, 7d, or a date)
--started-before DATEOnly runs whose StartedAt <= this
--finished-after DATEOnly runs whose FinishedAt >= this (excludes still-running)
--finished-before DATEOnly runs whose FinishedAt <= this (excludes still-running)
--limit NMax runs to show (default: 20)
-o, --output FORMATOutput format: pretty|json|plain
-q, --quietPrint only run ids, one per line (or JSON array of ids with -o json)
--by-pipelinePivot into one row per pipeline with a status sparkline of the last N runs
--sparkline NSparkline length when --by-pipeline is set (default: 30)
--style STYLESparkline glyph style: ascii|block|dot (default: ascii)
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Last 20 local runs
sparkwing runs list

# Failed runs in the past day
sparkwing runs list --status failed --since 24h

# Exclude success from the list
sparkwing runs list --status '!success' --since 24h

# Runs on main, excluding canary
sparkwing runs list --branch main --search '-canary'

# Runs that hit a specific failure
sparkwing runs list --error 'permission denied'

# Runs finished today
sparkwing runs list --finished-after today

# List prod runs
sparkwing runs list --profile prod --limit 50

# By-pipeline rollup with sparkline
sparkwing runs list --by-pipeline --since 7d

# By-pipeline JSON for an agent
sparkwing runs list --by-pipeline -o json --since 24h

# Pipe the most recent run id into another verb
sparkwing runs list --limit 1 -q | xargs -I{} sparkwing runs logs --run {}

sparkwing runs logsSection anchor link

Print a run's logs

Without --profile, reads logs from the local run directory. Pass --profile NAME to read from a remote controller's logs service (profile must carry both controller + logs URLs). Line-selection filters (--tail/--head/--lines/--grep) apply server-side in cluster mode so the CLI never tails giant logs over the wire.

--since D drops nodes whose StartedAt is older than now-D; useful for runs that have been retried several times where only the newest attempt matters. Filtering is node-level (log lines aren't timestamped on disk).

FlagsSection anchor link

FlagDescription
--run RUN_IDRun identifier (required)
--node NODE_IDLimit output to one node id
--tail NPrint only the last N lines
--head NPrint only the first N lines
--lines A:B1-indexed inclusive line range
--grep PATTERNSubstring match (case-sensitive)
--since DURATIONOnly include nodes that started within the last D (e.g. 5m, 1h)
--treeMerge root + descendant runs into one stream (local only)
-f, --followTail the log(s) until the run terminates
-o, --output FORMATOutput format: pretty|json|plain
--profile NAMEProfile name (omit for local-only reads)

ExamplesSection anchor link

# Read local logs
sparkwing runs logs --run run-20260422-142501-abcd

# Last 20 lines of a remote run
sparkwing runs logs --run run-... --profile prod --tail 20

# Only the most recent attempt's output
sparkwing runs logs --run run-... --profile prod --since 5m

# Search logs for an error substring
sparkwing runs logs --run run-... --grep 'permission denied'

# Merge a parent run with every descendant
sparkwing runs logs --run run-... --tree

# JSON stream for an agent
sparkwing runs logs --run run-... -o json

# Plain text with node/step prefix
sparkwing runs logs --run run-... -o plain

# Force the colored renderer when piping
sparkwing runs logs --run run-... -o pretty | less -R

sparkwing runs pruneSection anchor link

Delete finished runs older than a threshold, or by id

Prunes terminal runs (success / failed / cancelled) so the controller's SQLite store doesn't grow unbounded. Supply either --older-than DUR (batch by age) or one-or-more run ids via --run (repeatable). Use --run - to read ids from stdin. The two modes are mutually exclusive.

Use --dry-run first to confirm the victim list.

FlagsSection anchor link

FlagDescription
--older-than DURATIONPrune runs older than this
--run RUN_IDRun id to prune (repeatable; use --run - to read ids from stdin)
--dry-runList matching runs without deleting
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Preview what a 7-day prune would delete
sparkwing runs prune --older-than 7d --dry-run --profile prod

# Delete a few specific runs
sparkwing runs prune --run run-A --run run-B --profile prod

# Prune ids from another query
sparkwing runs list --pipeline scratch -q | sparkwing runs prune --run - --profile prod

sparkwing runs receiptSection anchor link

Emit a run's audit + cost receipt as JSON

Recomputes the per-run receipt from the run + nodes rows on demand and prints it as JSON. The receipt bundles identity hashes (pipeline_version_hash, inputs_hash, plan_hash, per-node outputs_hash), per-step observability (durations, outcomes), and runner-time × profile-rate compute cost.

Local mode reads from the SQLite store and uses the local profile's cost_per_runner_hour for the cost calc. --profile NAME reads from the remote controller's receipt endpoint; in that case the controller's configured rate (not the local profile) supplies cost.

FlagsSection anchor link

FlagDescription
--run RUN_IDRun identifier (required)
-o, --output FORMATOutput format: json (default)
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Local receipt as JSON
sparkwing runs receipt --run run-...

# Prod receipt
sparkwing runs receipt --run run-... --profile prod

sparkwing runs retrySection anchor link

Trigger fresh runs copying pipeline + args from old ones

Issues a new trigger per source run with the same pipeline, args, branch, and SHA. Each new run is tagged with retry_of=.

Pick a rerun scope explicitly: --failed reuse cached/passed nodes from the source run; re-execute only the failed or unreached subset. --all ignore prior outcomes and re-execute every node.

One of --failed or --all is required -- the silent default caused operators to ship a partial rerun when they meant a full one (and vice versa).

Pass --run once per source id (repeatable). Use --run - to read ids from stdin, one per line. Failures on individual ids don't abort the batch; the verb prints a per-id status line and exits non-zero only when at least one id failed.

FlagsSection anchor link

FlagDescription
--run RUN_IDSource run id (repeatable; use --run - to read ids from stdin)
--failedRerun from failed: reuse passed nodes, re-execute only failed/unreached
--allRerun all: re-execute every node from scratch
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Rerun only the failed nodes
sparkwing runs retry --failed --run run-...

# Rerun every node from scratch
sparkwing runs retry --all --run run-...

# Rerun every recently failed run
sparkwing runs list --status failed --since 1h -q | sparkwing runs retry --failed --run - --profile prod

sparkwing runs statsSection anchor link

Aggregate run counts, success %, avg + p95 duration

Per-pipeline aggregates across the last 500 root runs (or the --since window). In-flight runs count toward RUN (running) but do not contribute to timing percentiles.

FlagsSection anchor link

FlagDescription
--pipeline NAMERestrict to one pipeline
--since DURATIONOnly runs newer than this (e.g. 7d)
-o, --output FORMATOutput format: pretty|json|plain
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# 7-day local stats
sparkwing runs stats --since 7d

# Prod stats as JSON
sparkwing runs stats --profile prod -o json

sparkwing runs statusSection anchor link

Show one run's status (non-zero exit unless status=success)

Prints a summary of the run (pipeline, status, node states). With --follow, polls until the run reaches a terminal status. Pass --profile NAME to read from a remote controller.

Exit code contract: after rendering, 'jobs status' exits 0 only when status == success. Any non-success terminal status (failed, cancelled) exits 1; a run that is still running when the (non-follow) read returns also exits 1. Pass --exit-zero to inspect a known-failed run without the shell redline. For a blocking wait, use 'jobs wait'.

FlagsSection anchor link

FlagDescription
--run RUN_IDRun identifier (e.g. run-20260422-142501-abcd) (required)
-f, --followPoll until the run reaches a terminal state
-o, --output FORMATOutput format: pretty|json|plain
--stepsRender every step under every node (plain output). Failed / skipped / annotated nodes always include their steps; this flag forces success nodes too.
--exit-zeroReturn exit code 0 even when the run failed/cancelled
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Check a local run once
sparkwing runs status --run run-20260422-142501-abcd

# Follow a running job to completion
sparkwing runs status --run run-... --follow

# Inspect a known-failed run without nonzero exit
sparkwing runs status --run run-... --exit-zero

# Expand every step on every node
sparkwing runs status --run run-... --steps

# Check a prod run
sparkwing runs status --run run-... --profile prod

sparkwing runs summarySection anchor link

Aggregated work view: groups, work items, modifiers, annotations

Run-level rollup of every node in one render. Mirrors the dashboard's Summary tab: run header + run-wide annotations + node groups + work items (nodes and inner steps) + modifiers in effect + any approval-gate state. Useful for the "did this run actually do what I asked" agent question.

FlagsSection anchor link

FlagDescription
--run RUN_IDRun identifier (required)
-o, --output FORMATOutput format: pretty|json (default: pretty on TTY, json when piped)
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Quick run rollup
sparkwing runs summary --run run-...

# JSON for an agent
sparkwing runs summary --run run-... -o json

sparkwing runs timelineSection anchor link

ASCII waterfall of nodes (and optional steps) for a run

Renders one row per node, laid out along the run's wall-clock span. With --steps each node also expands into its inner Work steps. Useful for an agent reasoning about parallelism and the critical path without correlating logs by hand. JSON output emits start/end offsets in milliseconds per row.

FlagsSection anchor link

FlagDescription
--run RUN_IDRun identifier (required)
--stepsInclude per-step rows under each node
--width NBar width in characters (default: 60)
-o, --output FORMATOutput format: pretty|json (default: pretty on TTY, json when piped)
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Default node waterfall
sparkwing runs timeline --run run-...

# Expand into per-step bars
sparkwing runs timeline --run run-... --steps

# JSON for an agent
sparkwing runs timeline --run run-... --steps -o json

sparkwing runs treeSection anchor link

Show a run and every descendant run as an ASCII tree

Walks parent_run_id links so cross-pipeline spawns (RunAndAwait) show up under their originating run. Local mode reads from SQLite; --profile NAME reads from the profile's controller.

FlagsSection anchor link

FlagDescription
--run RUN_IDRoot run identifier (required)
-o, --output FORMATOutput format: pretty|json|plain
--profile NAMEProfile name; omit for local-only

ExamplesSection anchor link

# Tree for a local run
sparkwing runs tree --run run-20260422-142501-abcd

# Tree for a prod run as JSON
sparkwing runs tree --run run-... --profile prod -o json

sparkwing runs triggersSection anchor link

Fire, list, or inspect controller triggers

Triggers are the controller's queue of pending work. Every pipeline run starts as a trigger (from a webhook, hook, 'sparkwing run --profile', or 'triggers fire') that a worker atomically claims and turns into a run.

'fire' posts a synthetic trigger -- the sparkwing equivalent of 'gh workflow run'. 'list' surfaces queued / in-flight / done entries so operators can see what's stuck without diving into controller logs. 'get' inspects one trigger by id.

Connection info comes from the selected profile (--profile NAME); there are no --controller / --token flags on this command.

SubcommandsSection anchor link

  • list -- List pending / claimed / done triggers
  • get -- Inspect one trigger's full metadata by id

ExamplesSection anchor link

# List pending triggers on prod
sparkwing runs triggers list --profile prod --status pending

# Inspect one trigger
sparkwing runs triggers get --id run-... --profile prod

# Fire a trigger (use pipeline run)
sparkwing pipeline run --pipeline deploy --profile prod

sparkwing runs triggers getSection anchor link

Inspect one trigger's full metadata by id

Fetches GET /api/v1/triggers/{id} and prints the full row (pipeline, args, git, env, status, claim lease). Defaults to a compact multi-line rendering; -o json emits the raw response.

FlagsSection anchor link

FlagDescription
--id TRIGGER_IDTrigger / run identifier (same value 'fire' prints) (required)
-o, --output FORMATOutput format: json emits the raw response
--profile NAMEProfile name (default: current default) (required)

ExamplesSection anchor link

# Inspect one trigger
sparkwing runs triggers get --id run-20260422-142501-abcd --profile prod

# Raw JSON for scripting
sparkwing runs triggers get --id run-... --profile prod -o json

sparkwing runs triggers listSection anchor link

List pending / claimed / done triggers

Queries GET /api/v1/triggers on the selected profile's controller. Empty filters return the most recent 20 entries across all statuses.

Useful when the queue looks stuck ("why isn't my trigger being claimed?"): --status pending shows unclaimed work, --status claimed shows what a worker has in-flight. The repo filter matches GITHUB_REPOSITORY on the trigger env so webhook-driven entries narrow cleanly.

FlagsSection anchor link

FlagDescription
--status STATUSFilter by status: pending | claimed | done
--pipeline NAMEFilter by pipeline name
--repo OWNER/NAMEMatch GITHUB_REPOSITORY on the trigger env
--limit NMax triggers to show (default: 20)
-q, --quietPrint only trigger ids, newline-separated
-o, --output FORMATOutput format: json emits the raw triggers array
--profile NAMEProfile name (default: current default) (required)

ExamplesSection anchor link

# Recent triggers on prod
sparkwing runs triggers list --profile prod

# Just pending
sparkwing runs triggers list --profile prod --status pending

# Pipeline-specific, JSON
sparkwing runs triggers list --profile prod --pipeline build-test-deploy --limit 5 -o json

sparkwing runs waitSection anchor link

Block until a run reaches a terminal status

Polls the run until its status is success / failed / cancelled, then exits. Exit code contract:

0 status == success 1 status == failed or cancelled 2 timed out before the run reached a terminal status 3+ infrastructure error (controller unreachable, run not found, ...)

Pair with 'jobs find --wait' for the "push then find then wait" loop described in the CLI wishlist.

FlagsSection anchor link

FlagDescription
--run RUN_IDRun identifier to wait on (required)
--timeout DURATIONGive up (exit 2) after this long (default: 10m)
--poll DURATIONPoll interval (default: 3s)
-o, --output FORMATOutput format: pretty|json|plain
--profile NAMEProfile name (cluster mode). Omit to poll the local SQLite store.

ExamplesSection anchor link

# Wait for a local run
sparkwing runs wait --run run-20260422-142501-abcd

# Wait with a custom timeout
sparkwing runs wait --run run-... --timeout 30m --profile prod

# Tight polling on a fast run
sparkwing runs wait --run run-... --poll 500ms --profile prod

sparkwing secretsSection anchor link

Manage secrets (local dotenv or controller-stored)

Without --profile, reads/writes the laptop dotenv at ~/.config/sparkwing/secrets.env (masked) or ~/.config/sparkwing/config.env (--plain). Used by jobs invoked through 'sparkwing run ' locally.

With --profile PROF, reads/writes the named profile's controller. Used for prod / staging secrets that the cluster needs at run time. Pipelines pull a secret by listing it in the sparkwing.yaml 'secrets:' block. Raw values never transit the CLI except via 'secrets get'.

SubcommandsSection anchor link

  • set -- Store (or replace) a secret value
  • get -- Print a secret's raw value to stdout
  • list -- List secret names + metadata (never prints values)
  • delete -- Remove a secret

sparkwing secrets deleteSection anchor link

Remove a secret

Deletes the secret row from the controller. Pipelines that reference the name will fail to resolve until the secret is re-added.

FlagsSection anchor link

FlagDescription
--name NAMESecret name to remove (required)
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Delete a secret
sparkwing secrets delete --name API_TOKEN --profile prod

sparkwing secrets getSection anchor link

Print a secret's raw value to stdout

Prints only the raw value (no trailing newline) so it can be piped into another command. Use 'secrets list' for metadata.

FlagsSection anchor link

FlagDescription
--name NAMESecret name (required)
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Fetch a secret
sparkwing secrets get --name API_TOKEN --profile prod

sparkwing secrets listSection anchor link

List secret names + metadata

Prints a table of name, created_at, and the principal that last updated each secret. Raw values are never printed by this command.

FlagsSection anchor link

FlagDescription
--grep PATTERNFilter by name substring (case-sensitive)
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# List secrets on prod
sparkwing secrets list --profile prod

# Filter to API-related names
sparkwing secrets list --profile prod --grep API

sparkwing secrets setSection anchor link

Store (or replace) a secret value

Uploads --value (or the contents of --file) to the controller under --name. Replaces any existing secret with that name. Prefer --file for long or multi-line values so the raw text does not land in shell history.

FlagsSection anchor link

FlagDescription
--name NAMESecret name (unique per controller) (required)
--value VALUESecret value (prefer --file for long values)
--file PATHRead value from file (keeps value out of shell history)
--plainStore as non-masked config (e.g. REGION, LOG_LEVEL) -- value will NOT be redacted in run logs. Default is masked.
--profile NAMEProfile name (default: current default)

ExamplesSection anchor link

# Set a masked secret (default)
sparkwing secrets set --name API_TOKEN --value abc123 --profile prod

# Set from a file
sparkwing secrets set --name TLS_CERT --file ./tls.crt --profile prod

# Set non-masked config
sparkwing secrets set --name REGION --value us-east-1 --plain --profile prod

sparkwing updateSection anchor link

Self-update the CLI binary

Downloads, checksum-verifies, and atomically installs the latest (or a specific) sparkwing release from GitHub Releases.

By default the command fetches the latest version pointer, pulls the matching tarball for the current OS/arch, verifies its SHA256 against the published SHA256SUMS, and replaces the running binary via an atomic rename. macOS arm64 binaries are ad-hoc-codesigned after installation to avoid SIGKILL on first run.

--check is the read-only probe: it reports the installed version and the latest published release, exits 0 when already current, and exits 1 when a newer release exists (useful for CI/notifications).

Downgrades are blocked by default. Pass --force to install an older release (e.g. bisecting a regression).

For SDK (go.mod) bumps, use 'sparkwing version update --sdk'.

FlagsSection anchor link

FlagDescription
--checkReport installed vs latest; exit 1 if a newer release exists (read-only)
--forceAllow downgrading to an older release
--version TAGTarget release tag (e.g. v0.17.0). Default: latest.

ExamplesSection anchor link

# Check for a newer release (read-only)
sparkwing update --check

# Update to latest
sparkwing update

# Pin to a specific release
sparkwing update --version v0.44.0

# Downgrade to an older release
sparkwing update --version v0.40.0 --force

sparkwing versionSection anchor link

Show + update versions (CLI, SDK, sparks)

Reports the installed CLI version + build provenance, the latest published release on GitHub (with a short network fetch -- bounded by ~3s, fail-soft when offline), and the .sparkwing/go.mod SDK pin + any sparks-* libraries declared alongside it.

Behind-by-version is computed via semver compare for both the CLI itself and the SDK pin so an agent reading -o json can trigger an upgrade without parsing prose.

--offline skips the network fetch entirely; -o json emits the structured report; -o plain prints semver lines (CLI then latest) for shell pipelines.

SubcommandsSection anchor link

  • update -- Self-update CLI binary or bump SDK pin (requires --cli or --sdk)

FlagsSection anchor link

FlagDescription
-o, --output FORMATOutput format: pretty | json | plain (default: pretty)
--offlineSkip the network fetch for latest release

ExamplesSection anchor link

# Human-readable card
sparkwing version

# Agent-readable record
sparkwing version -o json

# CLI semver only (scripts)
sparkwing version -o plain | head -n1

# Local-only (no network)
sparkwing version --offline

# Update the CLI binary
sparkwing version update --cli

# Bump the SDK pin in this project
sparkwing version update --sdk

sparkwing version updateSection anchor link

Self-update the CLI binary (--cli) or bump this project's SDK pin (--sdk)

Two targets, one verb:

--cli Replace the running sparkwing binary with the target release. Resolves the version pointer from GitHub Releases, downloads + checksum-verifies the tarball, and atomically installs it. macOS arm64 binaries are ad-hoc-codesigned to avoid SIGKILL on first run.

--sdk Bump the SDK pin in this project's .sparkwing/go.mod via 'go get github.com/sparkwing-dev/sparkwing@', then 'go mod tidy'. Doesn't touch the running binary.

Exactly one of --cli or --sdk must be set; they conflict with each other so a typo can't update the wrong half. --version applies to whichever target is selected.

FlagsSection anchor link

FlagDescription
--cliSelf-update the sparkwing CLI binary
--sdkBump the SDK pin in this project's .sparkwing/go.mod
--version TAGTarget release tag (e.g. v0.17.0). Omit for latest.
--forceAllow downgrading to an older release (--cli only)

ExamplesSection anchor link

# Update the CLI to latest
sparkwing version update --cli

# Pin the CLI to a specific release
sparkwing version update --cli --version v0.44.0

# Downgrade the CLI
sparkwing version update --cli --version v0.40.0 --force

# Bump the SDK in this project to latest
sparkwing version update --sdk

# Pin the SDK to a specific release
sparkwing version update --sdk --version v0.44.0