Agent-ready command-line interface for Drone CI (builds, logs, repos, secrets, crons, usage reporting). Installs the `drone-cli` command.
Project description
drone-cli — the agent-ready Drone CI CLI
A fast, scriptable Drone CI CLI for builds, pipeline logs, repositories, promotions and deployments — and the first Drone command-line tool designed to be driven by AI agents (Claude, Cursor, LLM tool-loops) as well as humans.
Install: pipx install agent-tool-drone-cli — then run drone-cli guide.
agent-tool-drone-cli (the
installed command is drone-cli) is a Python command-line interface for the
Drone CI REST API. It covers the day-to-day pipeline
workflow — waiting on a commit's build, reading just the failing step's
logs, listing and triggering builds, restart/cancel/approve,
promotions and rollbacks, repositories, and "what is actually live on prod" —
all with first-class JSON output so it slots straight into automation and AI
agents.
Why this Drone CLI?
- 🎯 Address builds by COMMIT, not by build number.
drone-cli wait --commit HEADanswers "did the thing I just pushed pass?" Build numbers are racy — if a colleague pushes while you do, "the latest build" is a coin flip and you'd report their failure as yours. You already know your SHA.--commit HEADreads it from the local checkout. Nothing else in the ecosystem works this way. - 🔬
drone-cli log failed— the failing step, and nothing else. Doing this by hand means: GET the build, walkstages[], find the failed step, know that stage/step are 1-based ordinals (not names, not ids), GETlogs/{stage}/{step}, then strip the{pos,out,time}envelope. One command instead,--tail-bounded — so an agent spends its context on the fix rather than onapt-getnoise. - 🤖 Agent-ready — structured JSON on stdout, structured errors on stderr,
stable exit codes, and a built-in
drone-cli guideplaybook so an agent can learn the tool from the tool itself. See AGENTS.md. - 🚀 Deployments as first-class questions —
drone-cli promote --commit HEAD,drone-cli deploy status --to prod(which commit is on prod right now?),drone-cli deploy of --commit HEAD(has my commit shipped?). The API exposes the data; nothing surfaces the answer. - ⏱️ Durations that don't exist upstream — Drone's API has no duration field
anywhere, only raw epochs. This CLI derives build time and queue latency for
you (and never mistakes
finished: 0for 1970). - 🖇️ Four output formats —
json(default),table,markdown,csv; pick per command with-o, trim to exact--fields, or--streamNDJSON. - 🧪 Safe by default —
--dry-runpreviews any write at the transport layer, the client retries genuinely transient failures (and pointedly not Drone's 500s), anddrone-cli contextgives sticky per-session defaults. - 🔐 Safe credentials — API token in the OS keyring (Secret Service / macOS
Keychain / Windows Credential Locker), with a
0600file fallback.DRONE_SERVER/DRONE_TOKENwork for CI. - 🧰 Escape hatch —
drone-cli rawcalls any endpoint the typed commands don't wrap. Drone's API is thinly and sometimes wrongly documented; this is how you check.
Docs: Full command reference · Agent guide · built-in: drone-cli guide
Keywords: Drone CI CLI, Drone command line, Drone API client, drone.io, pipeline automation, CI/CD CLI, build logs, continuous integration tooling, promote deployment, AI agent tool, LLM tooling, Claude, DevOps automation.
The command surface
Everything is discoverable from the binary — drone-cli --help, then
drone-cli guide for the playbook and drone-cli <group> --help for any group.
The top level:
Usage: drone-cli [OPTIONS] COMMAND [ARGS]...
Agent-friendly CLI for Drone CI (builds, logs, repos, secrets, crons,
deployments).
Output is JSON on stdout by default (errors are JSON on stderr with a non-zero
exit code); add `-o table` or trim with `--fields number,status`. Address builds
by COMMIT, not by number: `drone-cli wait --commit HEAD`.
New here / no context? Run `drone-cli guide` for the full playbook.
╭─ Commands ───────────────────────────────────────────────────────────────────────╮
│ guide Built-in operating guide — how to use this CLI without external docs. │
│ report Report a bug / missing feature — repo + pre-filled issue link. │
│ wait Wait for a commit's build to finish. `--commit HEAD` after a push. │
│ promote Promote a commit/build to a target (default: prod). │
│ auth Log in, log out, inspect credentials. │
│ repo Repositories: list, enable, sync, inspect. │
│ build Builds: list, inspect, run, restart, cancel, wait. │
│ log Build logs — including just the failing step. │
│ deploy Deployments: what is on prod, and what got it there. │
│ secret Repository secrets (values are write-only). │
│ orgsecret Organisation secrets, shared across a namespace's repos. │
│ cron Scheduled builds — with a guard for Drone's seconds-first cron. │
│ template Pipeline templates (namespaced). │
│ server Server version, health, queue — and `server doctor`. │
│ user Your build feed, and user administration (admin only). │
│ raw Escape hatch: call any API endpoint directly. │
│ settings View & change CLI settings. │
│ context Sticky session defaults (repo, etc.) reused across commands. │
│ install Integrate with other tools (e.g. `install claude`). │
╰──────────────────────────────────────────────────────────────────────────────────╯
Global options — -o/--output json|table|markdown|csv, --fields, --dry-run,
--stream, --no-context — are stripped from argv before parsing, so they work
anywhere on the line. Full reference: docs/COMMANDS.md.
The name: drone-cli, not drone
The installed command is drone-cli. The name drone belongs to the
official Go client that most Drone users already have on their PATH, and this
project deliberately does not claim it — the two are designed to coexist on
the same machine, and clobbering the binary everyone's muscle memory and existing
scripts point at would be a hostile way to install software.
drone-agent is refused for the same reason: in Drone's own vocabulary an
"agent" is the runner. Alias it yourself if you want it shorter:
alias dc=drone-cli.
Compatibility
- Drone: 2.x — the API is unversioned and mounted at
<server>/api. Verified live againstdrone/drone:2(2.28.x) with a Docker runner; Drone is in maintenance, so there is no version matrix to chase. - SCM: Gitea / Forgejo verified live; GitHub / GitLab / Bitbucket share the
same Drone API. The one SCM-shaped setting is the commit-URL pattern
(
drone-cli settings set-scm) — see the limitations below for why it can't be auto-detected. - Python: 3.10+.
Anything not wrapped is reachable with drone-cli raw <method> <path>.
Quick start
1. Install
a) pipx (recommended — isolated, puts drone-cli on your PATH)
pipx install agent-tool-drone-cli
b) pip
pip install agent-tool-drone-cli
# or, from a clone:
python3 -m venv .venv && . .venv/bin/activate && pip install -e .
c) Single self-contained binary (no Python on the target)
Download the prebuilt binary for your OS from the GitHub Releases page:
chmod +x drone-cli-linux-x86_64 && mv drone-cli-linux-x86_64 /usr/local/bin/drone-cli
drone-cli --help
Or build one yourself — a single file that bundles the interpreter, the deps and the OS keyring backends:
pip install -e '.[build]'
python scripts/build_binary.py # -> dist/drone-cli (.exe on Windows)
.github/workflows/release.yml builds Linux/macOS/Windows binaries on every v*
tag and attaches them to the release.
2. Log in
drone-cli auth login # asks for the server, then shows you
# exactly where to get a token
drone-cli auth whoami
login verifies the token before persisting anything, saves the connection
profile to ~/.config/drone-cli/config.json, and stores the token in your
keyring. Get a token at <your-drone-server>/account.
For headless/CI use, skip the keyring entirely — the ecosystem's own env vars are read as-is:
export DRONE_SERVER=https://drone.example.com
export DRONE_TOKEN=xxxxxxxx
drone-cli build ls --repo octocat/hello-world
Precedence hazard, stated plainly: env beats keyring. That is what makes the tool work in CI — but
DRONE_*is also the namespace the Drone runner injects into every build step, so an exportedDRONE_TOKENsilently overrides your keyring login.drone-cli auth statusalways names the token actually in use. Don't guess.
Use with Claude Code
drone-cli install claude # writes ~/.claude/skills/drone-ci/SKILL.md
drone-cli install claude --print # preview it first
The skill points Claude at drone-cli guide, so it learns the tool from the
tool. On the first interactive run, if Claude Code is detected, the CLI offers to
install it — once. Decline and nothing changes.
Command highlights
Run drone-cli <group> --help for full options, or drone-cli guide <topic>.
The whole point — wait
drone-cli wait --commit HEAD # did my push pass?
drone-cli wait --commit HEAD --timeout 20m
drone-cli wait --commit HEAD --exit-code && ./deploy.sh
Three outcomes an agent must distinguish, and this command keeps them apart: finished (the outcome is in the JSON), blocked (a human must approve — the approve command is included in the output), and never appeared (exit 10: the webhook may be broken or the repo not enabled — that is not "the tests failed").
Logs — drone-cli log
drone-cli log failed --commit HEAD --tail 80 # just the failing step
drone-cli log failed 42 --all # every failing step, not just the first
drone-cli log view 42 --stage 1 --step 2 # 1-based ordinals, not names
drone-cli log view 42 --grep "error"
Builds — drone-cli build
drone-cli build ls --repo octocat/hello-world --status failure
drone-cli build info --commit HEAD --links # stages[].steps[] + a real commit URL
drone-cli build run --branch main # NOTE: event = "custom", not "push"
drone-cli build restart 42 # -> creates a NEW build number
drone-cli build cancel 42
drone-cli build approve 42 --stage 2 # blocked builds
Deployments — drone-cli promote / drone-cli deploy
drone-cli promote --commit HEAD # --to defaults to `prod`
drone-cli promote --commit HEAD --to staging
drone-cli deploy status --to prod # which commit is live on prod?
drone-cli deploy of --commit HEAD # has my commit been promoted?
drone-cli settings set-promote-target staging # change the default target
Output, context, escape hatch
drone-cli build ls -o table
drone-cli build ls --fields number,status,after # trim the payload
drone-cli build ls --stream # NDJSON
drone-cli build restart 42 --dry-run # prints the request, sends nothing
drone-cli context set --repo octocat/hello-world # stop repeating --repo
drone-cli context show # incl. where each value came from
drone-cli --no-context build ls # ignore it for one command
drone-cli raw get repos/octocat/hello-world/builds
Output for agents
- Default output is JSON on stdout. Errors are JSON on stderr with a
non-zero exit code (
{"error": "...", "status": 404}). - Exception:
log view/log failedprint raw log text. Logs are prose, not records — don'tjson.loadsthem. - Exit codes:
0ok ·1generic ·3config ·4auth ·5not-found ·7validation ·8not-implemented-on-this-server ·9wait timed out ·10no build for that commit ·130interrupted. (6is reserved family-wide for conflicts; Drone has no optimistic locking and never conflicts.) wait --exit-codeopts into a separate 20–29 band so "the build failed" can never be confused with "the CLI failed".
Full contract: AGENTS.md.
Contributing / Development
You do not need Drone, Docker, a server, or a token to contribute. Clone it and run:
pip install -e '.[test]'
pytest # green on a clean checkout, ~2s, no server needed
That is the whole setup. The suite is green on a fresh clone with nothing
running: the tests that need a live instance detect there isn't one and skip with
a message telling you exactly what to set. make test-unit runs the same
hermetic set explicitly (pytest -m "not integration" — the marker is the source
of truth, never a file list).
Please add a test with your change; the hermetic suite is fast enough to run on every save.
The deeper tier (only if you're touching the client↔server seam)
A live Drone needs an SCM behind it (repos only enter Drone by syncing from
Gitea/Forgejo/GitHub), a runner to execute anything, and a token injected into
the DB. spike/docker-compose.spike.yml and spike/VERIFIED_FINDINGS.md document
a stack that was proven end-to-end. Point the suite at any live server with:
export DRONE_SERVER=http://localhost:8080
export DRONE_TOKEN=<your token>
pytest # the integration tests light up automatically
Unset those and they skip again. spike/VERIFIED_FINDINGS.md is the authoritative
record of what this API actually does — it is worth more than the official docs,
which are wrong in several documented places.
Security notes
- The API token is the only secret persisted, and it goes to the OS keyring by
default.
drone-cli auth statusshows which backend is in use. - On a headless box with no Secret Service, the token falls back to a
0600file under~/.config/drone-cli/and the CLI says so. DRONE_TOKEN/DRONECLI_TOKENin the environment always win (nothing is written to disk in that mode).- Tracebacks never show locals — they hold the token, and a pretty traceback would print it into your CI log.
Known limitations (Drone's API, not the CLI)
These are properties of Drone itself, verified live during a spike against a real server. The CLI works around what it can and is loud about what it can't.
- There is no duration field. Anywhere. Not on builds, not on stages, not on
steps — only raw
created/started/finishedepochs. Every duration you see here is derived client-side. (Also whyfinished: 0means still running, not 1970.) - Secret values can never be read back. Every read and write handler returns
the secret without its data, by design —
GET .../secrets/{name}yields{id, repo_id, name}. There is no--show-valuethat could ever exist, and no export, copy-between-repos, or value drift-check. That a read-back returns no value is not a failure. - No cross-repo build search. No endpoint filters builds by status, event,
author or date across repos; even within a repo only
branch/tagare server-side. Anything else is a client-side scan under a page budget — which is why a search can honestly report "I stopped looking", never "nothing found". - Cron is seconds-first. Drone uses a 6-field parser
(
Second Minute Hour Dom Month Dow). A normal 5-field crontab"0 3 * * *"parses fine and means every hour at :03 — not 03:00 daily. Silent, 24× wrong, no error. The API also can't preview a schedule:nextis only computed after the cron is persisted. build.linkis not a commit link. For apushit's a compare URL (/compare/before...after); for an API-triggered build it's an API URL that renders as JSON. Drone passes through whatever the SCM handed it and never normalises.--linksderives a real one from{repo.link}/commit/{sha}— and sincerepo.scmis an empty string even on a synced repo, the provider is not discoverable, so the pattern is a setting (settings set-scm) rather than a guess.- A 500 saying
Unauthorizedis not about your token. It means the server's link to the git provider is broken. The CLI maps it to a real auth error that says so, and never retries it. - Some endpoints in the docs don't exist:
POST .../lintandPOST .../verifyare 404s, andGET /api/versionis a 404 (the real one isGET /versionon the web root). Others are documented with the wrong ACL. Seespike/VERIFIED_FINDINGS.md.
Part of the family
Built on agent-tool-shared-cli —
the chassis every tool in this family shares: JSON on stdout, JSON errors on
stderr, a stable cross-tool exit-code contract, --dry-run, four output formats,
and a built-in guide so an agent can learn each tool from the tool itself.
| Tool | Install | For |
|---|---|---|
| drone-cli | pipx install agent-tool-drone-cli |
Drone CI — builds, failing-step logs, promotions |
| grafana-cli | pipx install agent-tool-grafana-cli |
Grafana — log discovery, health scan, alert routing |
| openproject | pipx install agent-tool-openproject-cli |
OpenProject — work packages, time, invoicing |
| lexware-office | pipx install agent-tool-lexware-office-cli |
Lexware Office — invoices, contacts, AR-aging |
They compose over the shared contract:
drone-cli wait --commit HEAD && grafana-cli scan --since 10m answers "my commit
built — is it healthy in production?"
License
MIT — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_tool_drone_cli-0.1.3.tar.gz.
File metadata
- Download URL: agent_tool_drone_cli-0.1.3.tar.gz
- Upload date:
- Size: 160.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58927cd1b7f820908bb361a8f886a18b3f2951630fdabecfb684e5af4853328a
|
|
| MD5 |
f22567df26c992d74c7ec97fc8326f2d
|
|
| BLAKE2b-256 |
39b9663ffed3395ce9949865f6e63245c8b4575ad8db1f26a4f877e48ec19f38
|
Provenance
The following attestation bundles were made for agent_tool_drone_cli-0.1.3.tar.gz:
Publisher:
release.yml on alexander-zierhut/agent-tool-drone-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_tool_drone_cli-0.1.3.tar.gz -
Subject digest:
58927cd1b7f820908bb361a8f886a18b3f2951630fdabecfb684e5af4853328a - Sigstore transparency entry: 2206456400
- Sigstore integration time:
-
Permalink:
alexander-zierhut/agent-tool-drone-cli@11668c48a999f58067efd4cbee9ea74fc7104940 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/alexander-zierhut
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@11668c48a999f58067efd4cbee9ea74fc7104940 -
Trigger Event:
push
-
Statement type:
File details
Details for the file agent_tool_drone_cli-0.1.3-py3-none-any.whl.
File metadata
- Download URL: agent_tool_drone_cli-0.1.3-py3-none-any.whl
- Upload date:
- Size: 115.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80ea42c1b03ab0be127b41ddd00e11f6d495d19c8254d7cc3752354af602c7c3
|
|
| MD5 |
6c5edd2d80f97aa67a6aa54c587c4256
|
|
| BLAKE2b-256 |
9a5186644effcf12c118131bcec75b77ab111e5742439d269f0962407cc857b8
|
Provenance
The following attestation bundles were made for agent_tool_drone_cli-0.1.3-py3-none-any.whl:
Publisher:
release.yml on alexander-zierhut/agent-tool-drone-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_tool_drone_cli-0.1.3-py3-none-any.whl -
Subject digest:
80ea42c1b03ab0be127b41ddd00e11f6d495d19c8254d7cc3752354af602c7c3 - Sigstore transparency entry: 2206456520
- Sigstore integration time:
-
Permalink:
alexander-zierhut/agent-tool-drone-cli@11668c48a999f58067efd4cbee9ea74fc7104940 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/alexander-zierhut
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@11668c48a999f58067efd4cbee9ea74fc7104940 -
Trigger Event:
push
-
Statement type: