A fast, agent-friendly command-line interface for Atlassian Jira Cloud, built on the Jira REST API v3.
Every command is designed for both humans and automation: tables in terminals, structured JSON when piped, deterministic exit codes, explicit stdin handling, dry-run support for mutations, and redacted diagnostics for debugging.
# Homebrew (macOS/Linux)
brew install osodevops/tap/jira-cli
# Scoop (Windows)
scoop bucket add osodevops https://github.com/osodevops/scoop-bucket
scoop install jira
# Pre-built binaries
# https://github.com/osodevops/jira-cli/releases
# From source
cargo install --git https://github.com/osodevops/jira-cli
# Local development build
cargo build --release
./target/release/jira --versionjira config init \
--site example.atlassian.net \
--email you@example.com \
--default-project ENG
jira auth setup-token --token "$JIRA_TOKEN"
# Or for interactive users with an Atlassian OAuth 3LO app:
jira auth login --client-id "$JIRA_OAUTH_CLIENT_ID" --client-secret "$JIRA_OAUTH_CLIENT_SECRET"
jira issue view ENG-123 --output json
jira issue list --jql 'project = ENG AND @open' --all --output jsonl
jira comment add ENG-123 --body 'Build passed'Jira API tokens are stored in the OS keychain when available, with an encrypted file fallback. Environment variables can override stored credentials for CI and agents.
Machine-readable output is wrapped in a stable envelope:
{
"ok": true,
"data": {
"key": "ENG-123",
"summary": "Ship Jira CLI"
},
"meta": {
"schema_version": "1",
"profile": "prod",
"site": "example.atlassian.net"
}
}Errors are written to stderr:
{
"ok": false,
"error": {
"code": "auth_failed",
"message": "authentication failed: no Jira API token found",
"hint": "run `jira auth setup-token` or set JIRA_TOKEN and JIRA_EMAIL"
}
}Exit codes:
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General, I/O, JSON, YAML, TOML, or CSV error |
| 2 | CLI usage error |
| 3 | Authentication failure |
| 4 | Permission denied |
| 5 | Resource not found |
| 6 | Conflict |
| 7 | Rate limited |
| 8 | Validation error |
| 9 | Network error |
| 10 | Configuration error |
jira auth setup-token --token "$JIRA_TOKEN"
jira auth setup-token --token-file ./jira-token.txt --email you@example.com --site example.atlassian.net
jira auth login --client-id "$JIRA_OAUTH_CLIENT_ID" --client-secret "$JIRA_OAUTH_CLIENT_SECRET"
jira auth refresh
jira auth status --output json
jira auth doctor --output json
jira auth list
jira auth logout --profile prodjira config init --profile prod --site example.atlassian.net --email you@example.com
jira config init --default-project ENG --default-board 42 --force
jira config show --output yamljira issue view ENG-123
jira issue body ENG-123 --plain
jira issue list --jql 'project = ENG AND statusCategory != Done' --all -o jsonl
jira issue create \
--project ENG \
--type Task \
--summary 'Add release smoke test' \
--description-file ./body.md \
--label cli \
--priority High
jira issue edit ENG-123 --summary 'Updated summary' --set customfield_10042='{"value":"Gold"}'
jira issue transitions ENG-123
jira issue transition ENG-123 'Done' --comment 'Released in v0.1.0'
jira issue assign ENG-123 --account-id 712020:abc123
jira issue link --type Blocks --inward ENG-123 --outward ENG-124
jira issue delete ENG-123 --yes --no-inputJQL macros currently supported by the CLI:
| Macro | Expands to |
|---|---|
@me |
currentUser() |
@open |
statusCategory != Done |
@mine |
(assignee = currentUser() OR reporter = currentUser()) |
@updated-today |
updated >= startOfDay() |
@current-sprint |
sprint = <active sprint id> resolved through board/profile context |
@next-sprint |
sprint = <future sprint id> resolved through board/profile context |
@previous-sprint |
sprint = <closed sprint id> resolved through board/profile context |
jira comment list ENG-123
jira comment view ENG-123 10001
jira comment add ENG-123 --body 'Investigating now'
jira comment add ENG-123 --body-file ./comment.md --visibility role:Developers
jira comment update ENG-123 10001 --body 'Updated note'
jira comment delete ENG-123 10001 --yes --no-inputjira worklog list ENG-123
jira worklog add ENG-123 --time-spent 1h30m --comment 'Implementation'
jira worklog update ENG-123 10001 --time-spent 45m
jira worklog total ENG-123 --output json
jira worklog delete ENG-123 10001 --yes --no-inputjira attachment list ENG-123
jira attachment upload ENG-123 ./report.pdf ./screenshot.png
jira attachment download --url "$ATTACHMENT_URL" --filename report.pdf --to ./downloads
jira attachment delete 10001 --yes --no-inputjira project list
jira project view ENG
jira project components ENG
jira project versions ENG
jira field list --output json
jira field view customfield_10042
jira user current
jira user search 'Ada Lovelace'
jira user view 712020:abc123jira cache path
jira cache info --output json
jira cache refresh projects
jira cache refresh fields
jira cache refresh boards --project ENG
jira cache refresh sprints --board 42
jira completions dynamic project EN
jira completions dynamic field 'Customer'The SQLite cache is namespaced by profile and site. Dynamic completion commands read only from the local cache and do not call Jira.
jira board list --project ENG
jira board backlog 42
jira sprint list --board 42 --state active
jira sprint current --board 42
jira sprint create --board 42 --name 'Sprint 87' --goal 'Ship CLI'
jira sprint add-issues 412 ENG-123 ENG-124
jira epic list --board 42
jira epic add-issues ENG-100 ENG-123jira bulk comment --jql 'project = ENG AND @open' --body 'Queued for triage' --dry-run
jira bulk assign --keys ENG-123,ENG-124 --account-id 712020:abc123
jira bulk transition ENG-123 ENG-124 --to Done --comment 'Released'
jira bulk edit --file issue-keys.txt --set 'Customer Tier=Gold'
jira issue bulk-delete --jql 'project = ENG AND labels = stale' --yes --no-inputBulk commands accept positional issue keys, --keys, --file, --jsonl, or --jql, and report per-issue success or failure.
jira issue view ENG-123 # table in a terminal, JSON when piped
jira issue view ENG-123 --output json
jira issue list --jql 'project = ENG' --all --output jsonl
jira field list --output csv
jira config show --output yaml
jira issue body ENG-123 --output plain
jira issue view ENG-123 --output json --compact
jira issue view ENG-123 --fields key,summary,status.nameSupported formats: auto, table, json, jsonl, csv, tsv, yaml, plain.
# Safe mutation preview
jira issue create --project ENG --type Task --summary 'Preview only' --dry-run -o json
# Agent-safe non-interactive delete
jira comment delete ENG-123 10001 --yes --no-input --output json
# Explicit stdin only
git log -1 --pretty=%B | jira comment add ENG-123 --body -
# Triage with jq
jira issue list --jql 'project = ENG AND @open' --all -o jsonl |
jq -r 'select(.data.priority.name == "High") | .data.key'
# Redacted curl for debugging
jira issue view ENG-123 --debug-curl --output jsonMore examples are in docs/examples.md, and a compact command index is in docs/commands.md.
Config file: ~/.config/jira-cli/config.toml on Linux, or the platform-specific config directory from dirs.
[default]
active_profile = "prod"
output_format = "auto"
page_size = 50
max_results = 1000
color = "auto"
no_input = false
[rate_limit]
calls_per_minute = 300
max_concurrent = 8
retry_max = 5
[auth]
callback_host = "127.0.0.1"
callback_port = 8080
[cache]
enabled = true
ttl_seconds = 86400
[bulk]
concurrency = 4
continue_on_error = true
[profiles.prod]
site = "example.atlassian.net"
auth_method = "token"
email = "you@example.com"
default_project = "ENG"
default_board = 42
default_sprint_strategy = "active-only"
scopes = ["read:jira-work", "write:jira-work", "read:jira-user"]Credential resolution order: explicit CLI flags, environment variables, stored token, config profile.
| Variable | Description |
|---|---|
JIRA_TOKEN |
API token override for the active profile |
JIRA_TOKEN_<PROFILE> |
Profile-specific API token override |
JIRA_EMAIL |
Jira account email for API-token auth |
JIRA_SITE |
Jira Cloud site, for example example.atlassian.net |
JIRA_PROFILE |
Named profile to use |
JIRA_OUTPUT |
Output format |
JIRA_CONFIG |
Config file path |
JIRA_API_BASE_URL |
Test/dev override for API base URL |
ATLASSIAN_AUTH_BASE_URL |
Test/dev override for OAuth token and authorize URLs |
ATLASSIAN_API_BASE_URL |
Test/dev override for OAuth accessible resources and gateway URLs |
JIRA_OAUTH_CLIENT_ID |
Atlassian OAuth 3LO client ID |
JIRA_OAUTH_CLIENT_SECRET |
Atlassian OAuth 3LO client secret |
JIRA_CACHE_PATH |
Override SQLite cache path |
JIRA_DISABLE_KEYRING |
Use encrypted file token storage only; useful for CI/tests |
RUST_LOG |
Tracing filter |
jira completions shell bash > ~/.bash_completion.d/jira
jira completions shell zsh > ~/.zfunc/_jira
jira completions shell fish > ~/.config/fish/completions/jira.fish
jira completions shell powershell > jira.ps1
jira completions shell nushell > jira.nu
jira completions man --dir docs/man
man docs/man/jira.1
man docs/man/jira-issue-create.1
jira completions dynamic project EN
jira completions dynamic sprint 'Sprint'The repository includes generated man pages for the root command and every subcommand under docs/man.
The CI workflow runs:
- workflow linting with
actionlint cargo fmt --all -- --checkcargo clippy --all-targets --all-features -- -D warnings- cross-platform
cargo test --all-targets --all-features cargo audit- release smoke checks for
--version,--help, and manpage generation
The release workflow builds release archives for macOS, Linux, and Windows targets, uploads checksums, publishes the GitHub Release, updates osodevops/homebrew-tap, and updates osodevops/scoop-bucket. It can be run from a semver tag or manually with a tag input. See docs/release.md.
Release publishing requires these repository or organization secrets:
HOMEBREW_TAP_TOKENwith push access toosodevops/homebrew-tapSCOOP_BUCKET_TOKENwith push access toosodevops/scoop-bucket
The separate Jira Cloud Smoke workflow validates a sandbox Jira site with real create/edit/comment/worklog/attachment/delete operations. See docs/sandbox-smoke.md.
cargo build
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo test --all-targets
cargo audit
cargo build --release
./target/release/jira completions man --dir /tmp/jira-manImplemented now:
- API-token auth with secure storage
- profile config
- Jira REST API v3 client
/rest/api/3/search/jqlcursor pagination- issue reads and mutations
- comment CRUD
- worklog CRUD
- attachment upload/download/list/delete
- project, field, and user metadata reads
- OAuth 2.0 3LO login/refresh with Atlassian gateway routing
- SQLite metadata cache and cache-backed dynamic completion candidates
- Jira Software board, sprint, and epic commands
- deterministic sprint JQL macros
- bounded-concurrency bulk operations with dry-run and partial-failure summaries
- shell completions and generated man pages
- JSON, JSONL, table, CSV, TSV, YAML, and plain output
Planned next:
- MCP server mode
See docs/jira-cli-implementation-plan.md and docs/next-phase-plan.md.
The completed release-blocking plan and final release-candidate gate are tracked in docs/pre-release-roadmap.md.
See SECURITY.md for vulnerability reporting. Secrets are redacted from status, diagnostics, and debug curl output.
MIT. See LICENSE.