Jenkins CLI
Read-only build visibility for Jenkins via af jenkins. Eight subcommands — jobs, job, branches, build, log, queue, stages, stage-log. Nothing here triggers, cancels, or mutates a build.
Setup
Jenkins uses its own credentials — Atlassian, Bitbucket, and Sonar tokens are not interchangeable. All three variables are required; there are no fallbacks, no CLI flags, and no af.json block for Jenkins.
Add to your project's .env:
JENKINS_BASE_URL— Jenkins instance URL (e.g.https://jenkins.example.com; a trailing slash is stripped)JENKINS_USER— Your Jenkins usernameJENKINS_API_TOKEN— API token from<jenkins>/user/<you>/configure
They are combined as HTTP Basic auth. Config is read lazily on the first API call, so a missing variable surfaces as a runtime error (JENKINS_USER is not set. Create a .env file in your project directory with: ..., exit 1), not as a startup error.
Run af jenkins from the repo root that holds the .env. af auto-loads .env from the current working directory only, and it never overwrites variables already set in the environment.
Job Paths
This is the single most error-prone part of the command — read it before writing any job path.
Job paths use / to separate folder / pipeline / branch segments. Every segment becomes its own Jenkins /job/ level, URL-encoded individually:
my-folder/my-pipeline/feature-branch → /job/my-folder/job/my-pipeline/job/feature-branch
my-pipeline/feature/auth → /job/my-pipeline/job/feature/job/auth
Consequences:
- For a multibranch pipeline, the branch is just the last segment:
af jenkins build my-app/maintargets themainbranch of themy-apppipeline. - A branch name that itself contains a slash is split into multiple
/job/levels.af jenkins build my-app/feature/AB-123becomes/job/my-app/job/feature/job/AB-123. af has no branch-name special-casing (request.tsjust splits on/), so this only resolves iffeaturereally is a folder in Jenkins. For a multibranch branch literally namedfeature/AB-123, Jenkins stores it as one item namedfeature%2FAB-123— pass it as a single segment:af jenkins build "my-app/feature%2FAB-123". - Do not pre-encode ordinary segments. Each segment is
encodeURIComponent-ed for you, so spaces and other specials inside a segment are handled. The one exception is a branch whose name contains a slash: pass it as a single%2F-escaped segment (my-app/feature%2FAB-123), which af re-encodes tofeature%252FAB-123— Jenkins' own form for that item. - Quote paths containing spaces so the shell keeps them as one argument.
Build Number Resolution
Shared by build, log, stages, and stage-log:
- Omitted → Jenkins
lastBuild - The literal string
latest→ JenkinslastBuild - Anything else → used verbatim as the build number (e.g.
142)
So af jenkins build my-app/main and af jenkins build my-app/main latest are exactly equivalent.
Quick Reference
Run bare af jenkins (no subcommand) for the full command reference; af jenkins --help is intercepted by af's router and prints only a short stub. --json is the only meaningful option — it works on every subcommand.
af jenkins jobs [folder]— List jobs; with a folder path, list that folder's childrenaf jenkins job <name>— Job detail + the 10 most recent builds (+ a Branches table for a multibranch pipeline)af jenkins branches <pipeline>— Per-branch build status for a multibranch pipelineaf jenkins build <name> [number|latest]— Build detail: status, duration, when, changesetaf jenkins log <name> [number|latest]— Full console output, raw to stdoutaf jenkins queue— Pending build queue (takes no arguments)af jenkins stages <name> [number|latest]— Pipeline stage breakdownaf jenkins stage-log <name> <stage> [number|latest]— Log for one pipeline stage
Note stage-log's argument order: the stage name is the second positional, the build number the third.
Required arguments
job, branches, build, log, and stages all require <name>; stage-log requires both <name> and <stage>. Omitting a required argument prints a usage error and exits 1. jobs and queue take no required arguments.
Status Vocabularies
Two different vocabularies — do not conflate them.
Build result (build, job, branches) — SUCCESS | FAILURE | UNSTABLE | ABORTED | NOT_BUILT | null. In markdown output a build that is still running renders as RUNNING, and a missing result as UNKNOWN. In --json, a running build has building: true and result: null.
Pipeline stage status (stages, from the Stage View plugin) — SUCCESS, FAILED, IN_PROGRESS, NOT_EXECUTED, etc. Note FAILED, not FAILURE.
af jenkins jobs and the Status row of af jenkins job show Jenkins' raw color field instead (blue, red, yellow, blue (building), …).
Output Formats
- Default: Markdown tables — except
logandstage-log, which write raw text straight to stdout (no wrapping, no trailing newline) so they pipe cleanly. - JSON: Add
--jsonfor the raw Jenkins API response.
Exit Codes
A failed build still exits 0. Only transport errors, usage errors, and unknown subcommands exit 1. The exit code tells you whether the query succeeded, never whether the build succeeded.
# WRONG — this is always true, even for a red build
if af jenkins build my-app/main; then echo "green"; fi
# RIGHT — read the result field
result=$(af jenkins build my-app/main --json | jq -r '.result')
[ "$result" = "SUCCESS" ] || exit 1
0— Command completed (regardless of build health)1— Usage error, auth/config error, HTTP error, unknown subcommand, orbranchesfinding no branches
Common Workflows
Diagnose a failing CI build
The core loop. Narrow from build → stage → stage log rather than reading the whole console.
# 1. Confirm it actually failed (and that it isn't still running)
af jenkins build my-app/main --json | jq '{number, building, result}'
# 2. Find which stage failed
af jenkins stages my-app/main
# | Stage | Status | Duration |
# | Build | SUCCESS | 1m 12s |
# | Test | FAILED | 3m 4s |
# 3. Read only that stage's log
af jenkins stage-log my-app/main "Test" | tail -100
If the stage breakdown isn't available (not a pipeline, or the Stage View plugin is missing), fall back to the console:
af jenkins log my-app/main | tail -100
Poll a running build to completion
result is null while a build is in progress — always gate on building first.
while true; do
status=$(af jenkins build my-app/main --json | jq -r 'if .building then "RUNNING" else (.result // "UNKNOWN") end')
[ "$status" = "RUNNING" ] || break
sleep 30
done
echo "Finished: $status"
"My push didn't trigger a build"
Before assuming the webhook is broken, check the queue — the build is probably queued, not missing.
# Still showing the old build number?
af jenkins build my-app/main --json | jq '.number'
# Then look at the queue
af jenkins queue
# | Job | Queued Since | Reason |
# | my-app | Jul 14, 2026, 10:04 AM | Waiting for next available executor |
Build queue is empty. (exit 0) means nothing is pending — at that point suspect the webhook or branch indexing.
Is the branch green?
# One branch
af jenkins build my-app/main
# Every branch of a multibranch pipeline at once
af jenkins branches my-app
Find the job path
# Top-level jobs
af jenkins jobs
# Drill into a folder
af jenkins jobs my-folder
# Job health + last 10 builds, and (for a multibranch pipeline) its branches
af jenkins job my-folder/my-app
af jenkins job is the best single "is this healthy" command — job status, last success/failure, the last 10 builds, and (for a multibranch pipeline) every branch. For what changed in a given build, you still need af jenkins build <name> [number], which is the only command that prints the changeset.
Search a console log
The log is fetched in full; there is no tail/head/limit flag. Pipe it.
af jenkins log my-app/main | tail -50
af jenkins log my-app/main | grep -i -A5 'error\|exception'
af jenkins log my-app/main 142 | grep -c 'FAILED'
Discover stage names
The "not found" error lists every available stage — use it deliberately.
af jenkins stage-log my-app/main x
# Error: Stage "x" not found. Available stages: Checkout, Build, Test, Deploy
Stage matching is case-insensitive, so "test" finds Test. Stage names with spaces must be quoted: af jenkins stage-log my-app/main "Unit Tests".
Tips
- Branch is a path segment, not a flag —
af jenkins build my-app/main, neveraf jenkins build my-app --branch main. stages→stage-logbeats reading the whole console — go straight to the failing stage instead of grepping thousands of lines.- Use
--jsonfor any decision logic — the markdown is for humans;result/buildingare what a script should branch on. - Don't
--jsona big console log —af jenkins log --jsonwraps the entire log in a single-line{"output": "..."}. Prefer the raw form plusgrep/tail. - The recent-build count is fixed at 10 in
af jenkins joband cannot be changed. - There is no unknown-flag error. A typo'd
--foo baris silently swallowed (and eatsbar, which then isn't treated as a positional argument); a trailing--foowith no value errors withOption --foo requires a value. Stick to--json.
Out of Scope
af jenkins is read-only by design. It cannot:
- Trigger, re-run, cancel, or abort a build
- Update job configuration, or create/delete jobs
- Manage credentials, nodes, or plugins
Error Handling
- Errors print to stderr. With
--json, only errors raised by the API layer (missingJENKINS_*config, HTTP errors,Stage "x" not found,Pipeline stages not available) are re-emitted to stdout as{"error": "message"}. Usage errors,Option --x requires a value,Unknown jenkins command, andNo branches foundstay plain-text on stderr even with--json— always check the exit code, not just stdout. - Exit codes:
0success,1error — never a build-health signal
Distinctive errors worth recognising:
Pipeline stages not available. The Pipeline Stage View plugin may not be installed, or this job may not be a pipeline.— fromstages/stage-logon any HTTP 404. af rewrites every 404 into this one message, so it may equally mean a wrong job path or a nonexistent build number. Confirm the path withaf jenkins job <name>first; if the path and build are right, it really is "not a pipeline / plugin missing" — fall back toaf jenkins log.No branches found. Is this a multibranch pipeline?— frombranchesagainst a job with no children (e.g. a freestyle job). This is a hard exit 1, not an empty table.Stage "<x>" not found. Available stages: ...— fromstage-log; the list is your discovery mechanism.HTTP 404: ...— usually a wrong job path. Re-read the Job Paths section and confirm withaf jenkins jobs.JENKINS_* is not set. ...— missing credential, or you are not in the directory holding the.env.