Skip to content

osodevops/jira-cli

jira-cli

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.

CI Release Homebrew Scoop License: MIT

Install

# 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 --version

Quick Start

jira 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.

Agent Contract

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

Core Commands

Authentication

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 prod

Configuration

jira 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 yaml

Issues

jira 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-input

JQL 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

Comments

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-input

Worklogs

jira 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-input

Attachments

jira 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-input

Metadata

jira 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:abc123

Cache And Dynamic Completions

jira 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.

Agile

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-123

Bulk Operations

jira 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-input

Bulk commands accept positional issue keys, --keys, --file, --jsonl, or --jql, and report per-issue success or failure.

Output Formats

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.name

Supported formats: auto, table, json, jsonl, csv, tsv, yaml, plain.

Automation Patterns

# 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 json

More examples are in docs/examples.md, and a compact command index is in docs/commands.md.

Configuration

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.

Environment Variables

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

Shell Completions And Man Pages

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.

GitHub Actions

The CI workflow runs:

  • workflow linting with actionlint
  • cargo fmt --all -- --check
  • cargo 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_TOKEN with push access to osodevops/homebrew-tap
  • SCOOP_BUCKET_TOKEN with push access to osodevops/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.

Project Governance

Development

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-man

Current Scope

Implemented now:

  • API-token auth with secure storage
  • profile config
  • Jira REST API v3 client
  • /rest/api/3/search/jql cursor 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.

Security

See SECURITY.md for vulnerability reporting. Secrets are redacted from status, diagnostics, and debug curl output.

License

MIT. See LICENSE.

About

Fast, agent-friendly Jira Cloud CLI with JSON output, OAuth/API-token auth, cache, bulk ops, Agile commands, completions, and man pages.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages