Analyzing CI
usage, top, time, why, and labels — attribute cost, rank hotspots, decompose wall-clock, and diagnose failures
Five commands that answer analytical questions rather than listing records. Each is a first-class product surface, not a dashboard export.
sling usage
sling usage [--org <slug> | --repo <owner/name>] [--group-by <axis>] [--order-by <col>]
[--asc | --desc] [window] [--json | --agent]Attributes StarSling runner minutes and dollar cost over a time window.
| Flag | Meaning |
|---|---|
--org, --repo | Scope. --repo owner/name narrows to one repo; mutually exclusive. Defaults to your default org. |
--group-by | label (default) · workflow · job · repo · day |
--order-by | cost (default) · minutes · jobs · key |
--asc / --desc | Sort direction, default --desc. Naming both is a usage error. Not valid with --group-by day. |
--window <n>d | Trailing window, e.g. 30d. Defaults to 30 days. |
--month <YYYY-MM> | A calendar month. |
--from / --to | An explicit half-open range [from, to). Both required together. |
--json, --agent | Machine mode. |
sling usage --org mastra-ai --window 7d --group-by repo
StarSling usage — by repo
2026-07-07 → 2026-07-14
KEY RUNNER MIN JOBS COST $ % TOTAL
mastra-ai/mastra 25459.0 10784 $202.85 89.3%
mastra-ai/docs 3040.2 1120 $24.22 10.7%The window flags are mutually exclusive — passing two is a usage error, not a silent precedence rule. A single-row result omits % TOTAL, since a lone row's share is always 100%. --group-by day renders a burn-down chart instead of a table.
Cost is minutes × vCPU × $0.002, where minutes are billed minutes — max(1, ceil(duration / 60s)) per job. A five-second job still costs a minute.
The plan block
Every response carries a top-level plan describing the caller's billing state, which shapes both the window and the human chrome on any --group-by axis:
| Field | Meaning |
|---|---|
status | paid · free · blocked. Paid orgs get no bar or banner. |
period_source | stripe · install_cycle · calendar_month · explicit — labels the window. |
free_minutes_limit / free_minutes_used | Free orgs only — the remaining lifetime grant, drawn as a bar. |
blocked_reason | Blocked orgs only — why jobs will not dispatch, shown as a red banner. |
Fields that do not apply are omitted, not null. Machine mode passes the whole block through verbatim.
Exit codes: 0 ok · 2 usage error · 4 not signed in · 5 control-plane failure. Calls GET /api/usage.
sling top
sling top [--by <axis>] [--metric <col>] [--asc | --desc] [--org | --repo]
[-n <count>] [window] [--json | --agent]Ranks what burns the most runner time and money — the hotspots worth optimizing. Groups the same facts as usage, but sorts by a chosen metric and adds a period-over-period trend so a regression stands out.
| Flag | Meaning |
|---|---|
--by | workflow (default) · job · label · repo · branch |
--metric | runner-minutes · cost · jobs · p95-duration · p99-duration · queue-wait |
--asc / --desc | Sort direction, default --desc. |
--org, --repo | Scope; mutually exclusive. |
-n, --limit | Row count. |
--json, --agent | Machine mode — ranked rows plus a local block. |
sling top --by workflow --metric cost --window 30d
sling top — by workflow · cost · last 30d
KEY · WORKFLOW REPO COST TREND
Prebuild acme/api $528.35 ↑55.2%
Test (multiple) $203.11 ↓12.3%
Lint acme/web $44.90 —(multiple) marks a key spanning several repos. TREND compares against the prior equal-length window, or shows — when there is no prior data. Calls GET /api/top.
sling time
sling time <run|job|attempt id | URL>
sling time --repo <owner/name> [window]Decomposes CI wall-clock into phases — so you can see whether time goes to infrastructure or to your workload. Polymorphic, with a different analysis at each level:
- A job or attempt splits wall-clock into the phase enum, with a per-step breakdown inside
steps. - A run adds DAG analysis: the critical path, parallelism efficiency (busy-runner-seconds ÷ wall-clock × width), and the blocking job — the single job whose speedup most reduces run wall-clock, so optimization effort lands where it pays.
--repoaggregates p50/p95 per phase, per runner label, over a window — answering whether a repo's time goes to queue, provisioning, cache, or actual work.
| Flag | Meaning |
|---|---|
<id | URL> | A run, job, or attempt id, or a pasted GitHub Actions URL. |
--repo <owner/name> | The repo aggregate instead of a single target. |
--window, --month, --from / --to | Only with --repo. Passing one alongside an id is a usage error — a single target already names its window. |
--json, --agent | Machine mode. |
sling time
Job Name: Lint, typecheck, test & spell · Wall-Clock: 58s · Queue-Wait: 2s
PHASES TIME %-SHARE TIMELINE
provision 4.0s 7.14% ██░░░░░░░░░░░░░░░░░░░░░░
checkout+patch 2.0s 3.57% ░░█░░░░░░░░░░░░░░░░░░░░░
steps 46.0s 82.14% ░░░███████████████████░░
Set up Bun 1.0s ░░░█░░░░░░░░░░░░░░░░░░░░
Set up mise tools 2.0s ░░░█░░░░░░░░░░░░░░░░░░░░
Install dependencies 1.0s ░░░░█░░░░░░░░░░░░░░░░░░░
Lint (Biome) 2.0s ░░░░█░░░░░░░░░░░░░░░░░░░
Lint shell (shellcheck) 14.0s ░░░░░██████░░░░░░░░░░░░░
Lint Dockerfiles (hadolint) 0.0s ░░░░░░░░░░░█░░░░░░░░░░░░
▸ Typecheck 18.0s ░░░░░░░░░░░████████░░░░░
Test 7.0s ░░░░░░░░░░░░░░░░░░░███░░
Catalog drift 1.0s ░░░░░░░░░░░░░░░░░░░░░░█░
Spell (typos) 0.0s ░░░░░░░░░░░░░░░░░░░░░░█░
teardown 4.0s 7.14% ░░░░░░░░░░░░░░░░░░░░░░██
Top Steps
STEP TIME
Typecheck 18.0s
Lint shell (shellcheck) 14.0s
Test 7.0s
Set up mise tools 2.0s
Lint (Biome) 2.0sThe TIMELINE column places each phase and step on the job's wall-clock, so you can see what ran when and what overlapped — not just what was slow. ▸ marks the single largest contributor. Top Steps then ranks the steps outright, which is the list to optimize from: here Typecheck and Lint shell are 32 of the 46 seconds inside steps.
Phases come from a frozen vocabulary shared by the runner hooks and the facts store: queue_wait, provision, image_pull, cache_restore, checkout+patch, steps, cache_save, teardown. Only the phases with time recorded against them are shown. Percentages are share of phase time, so they sum across the phase rows — the nested steps are a breakdown of steps, not extra rows in that sum.
Exit codes: as elsewhere, plus 6 for partial — telemetry was incomplete, and the body is still emitted. Calls GET /api/time.
sling why
sling why <run | job | attempt id | URL> [--json | --agent]A server-authored diagnosis — why a CI job failed, so an agent can fix the failure instead of re-deriving it from logs. It is read straight from the facts store: the last failing step, a bounded ##[error] window, and run context. No LLM sits in the request path, so the same job always classifies the same way. A run id diagnoses that run's most-diagnosable job.
Every diagnosis carries a classification, evidence references, suggested actions with ready-to-run commands, and an agent-ready remediation prompt.
Classifications: step_failure · hang · oom · timeout · cancelled · terminated · infra · network_egress · unknown.
On a cancelled target, why identifies the canceller — a user, a concurrency group, or a merge-queue flush — so an external cancellation is not misdiagnosed as a code failure.
sling why job_88886665361
JobID: 88886665361 · JobName: test (3)
Failure Reason: The step 8 "Test" step failed (exit code 101).
Evidence
Classification: step_failure
Phase: step 8 "Test"
Logs:
##[error]Process completed with exit code 101
Suggestions:
1. Verify the logs
sling logs 88886665361 --grep '##\[error\]'Every diagnosis carries evidence, a suggested next step, and a ready-to-run prompt for a downstream agent. Calls GET /api/why.
sling labels list
sling labels list [--json | --agent]The catalog of available runner labels and their specs, so runs-on mapping and cost hints reference concrete options instead of hardcoded names. The catalog is static and global — identical for every caller — so the usual --org, --repo, and window flags are accepted but inert. list is the only subcommand.
sling labels list
StarSling runner labels
LABEL CPU MEM (GiB) ARCH $/MIN
starsling-ubuntu-24.04 4 16 x64 $0.008
starsling-ubuntu-24.04-2 2 8 x64 $0.004
starsling-ubuntu-24.04-8 8 32 x64 $0.016
starsling-ubuntu-24.04-16 16 64 x64 $0.032
starsling-ubuntu-24.04-32 32 128 x64 $0.064
starsling-ubuntu-24.04-64 64 256 x64 $0.128| Field | Meaning |
|---|---|
label | The runs-on runner label. |
cpu | vCPU count. |
memory_gb | RAM in GiB — a strict 4 GiB per vCPU. |
arch | CPU architecture; x64 today. |
price_per_min_usd | Per-minute cost, cpu × $0.002 — the same rate usage and bill charge. |
See Instance types for the same catalog in context. Calls GET /api/labels.