jira
A fast, friendly Jira CLI for Jira Cloud and Jira Data Center / Server, built to feel natural for people and predictable for agents.
- Auto-JSON when stdout is not a TTY, so you can pipe it anywhere and get structured data
jira doctorverifies configuration, identity, project access, and write safety in one command- Command-scoped schema gives agents one complete command contract without loading the full tree
- Structured exit codes, so agents can branch on auth failures, rate limits, not-found, and input errors without parsing text
- Clean stdout/stderr split: data on stdout, messages on stderr,
--quietsuppresses all non-data output
$ jira issues list --project MYAPP --status "In Progress"
Key Status Assignee Type Summary
MYAPP-42 In Progress Alice Bug Fix login redirect loop
MYAPP-38 In Progress Bob Task Update password reset flow
$ jira issues list --project MYAPP --json
{"items": [...], "total": 2, "startAt": 0, "maxResults": 50}
Installation
Or via Cargo:
Or build from source:
Configuration
Run jira auth login (or the shorter jira init) for guided setup. It opens
Atlassian's token page when useful, discovers the Cloud ID required by scoped
tokens, hides token entry, verifies the account, and stores the token in your
operating-system keychain. Existing profile values are reused safely. If no OS
credential service is available, setup offers an explicit protected-file
fallback rather than silently weakening storage.
For Jira Data Center, setup can create a dedicated PAT through Jira's official
API using a one-time password or existing PAT. That bootstrap credential is
never saved. When no terminal is available, jira init --json returns setup
instructions; CI can use the environment variables below directly.
Default locations:
| Platform | Path |
|---|---|
| Linux / macOS | ~/.config/jira/config.toml (or $XDG_CONFIG_HOME/jira/config.toml) |
[]
= "mycompany.atlassian.net"
= "me@example.com"
= "keyring"
= "your-atlassian-cloud-id"
= "scoped"
= "2026-11-24"
= true
Get a Jira Cloud API token at: https://id.atlassian.com/manage-profile/security/api-tokens
Run jira auth status to verify the active credential, jira auth status --offline to inspect local credential state without a request, and jira doctor for the complete connection. jira config show displays resolved
settings and the credential source; jira config path prints the backing file.
Existing configs with inline tokens remain readable; move one into the keychain
with jira auth migrate.
Environment variables
All credentials can be set via environment variables, which is useful for CI and scripts:
| Variable | Description |
|---|---|
JIRA_HOST |
Atlassian domain (e.g. mycompany.atlassian.net) |
JIRA_EMAIL |
Account email |
JIRA_TOKEN |
API token or Personal Access Token |
JIRA_PROFILE |
Config profile name |
JIRA_AUTH_TYPE |
basic (default) or pat |
JIRA_API_VERSION |
3 (Cloud, default) or 2 (Data Center / Server) |
JIRA_CLOUD_ID |
Atlassian Cloud ID required by a scoped token |
JIRA_TOKEN_KIND |
scoped or classic |
JIRA_READ_ONLY |
Block write operations. On: 1, true, yes, on. Off: 0, false, no, off. Any other value is an error, not "off" |
JIRA_DEBUG_HTTP |
Include the raw Jira response body in API error messages (1, true, yes, on). Useful when the default summary is ambiguous. |
Values are matched case-insensitively. JIRA_AUTH_TYPE and JIRA_API_VERSION reject anything outside the values listed above rather than falling back to the default, so a typo surfaces as a config error instead of an unexplained authentication failure.
Multiple profiles
[]
= "mycompany.atlassian.net"
= "me@example.com"
= "keyring"
= "your-atlassian-cloud-id"
= "scoped"
[]
= "jira.corp.com"
= "keyring"
= "pat"
= 2
Switch with --profile dc or JIRA_PROFILE=dc jira <command>.
Jira Data Center / Server (PAT auth)
Data Center uses Personal Access Tokens instead of email + API token:
[]
= "jira.corp.com"
= "keyring"
= "pat"
= 2
Email is not required for PAT auth. jira auth login can create and save a
dedicated PAT automatically, or open the manual token page:
https://<your-host>/secure/ViewProfile.jspa. From there, choose
Personal access tokens. Jira's direct selected-tab URL varies by release.
Usage
Issues
# List
# Assigned to you
# Show
# Discover the create screen before choosing fields
# Create
# Preview normalized fields without making changes
# Update
# Transition
# Assign
# Comment
# Log work
# Attachments
# Links
# Move to sprint
# Bulk operations (use --dry-run to preview)
--epic KEY resolves the instance's Epic Link custom field or native parent
field using create metadata (edit metadata for updates). --parent KEY also
uses epic linkage when its target is an Epic; other targets retain normal
parent semantics. Metadata validates the parent/type hierarchy before creation
and lists the project's subtask types when needed. --epic and --parent
cannot be combined. issues update --clear-epic removes epic membership,
resolving the same native or custom field. It conflicts with --epic and
explicit relationship overrides. Subtasks belong under a Story or Task, not directly under
an epic. Jira's Cloud and Server/DC metadata formats are supported, including
older Server metadata.
Priority matching uses the allowed values for the project and issue type, or
the existing issue's edit metadata. Exact names and IDs take precedence, then
case-insensitive names, labels with a numeric rank removed (Medium matches
3 - Medium), and unique prefixes (Med). Invalid or ambiguous input lists
the valid choices without creating or updating an issue. Creation also resolves
issue type names case-insensitively or by ID. Omitting --priority keeps Jira's
default. If metadata endpoints are unavailable, names are passed through to
Jira and validation errors include guidance; explicit --field values retain
their override behavior. Epic linkage requires a discoverable field or native
Cloud parent support.
Components and fix versions accept exact names, IDs, case-insensitive names,
and unique prefixes from create/edit metadata. Invalid or ambiguous values list
valid options before writing. Required fields without a server default must be
provided when creating an issue. Updates leave omitted fields untouched and
reject explicit clears of required fields. --field ID=VALUE can supply required
custom values. Unavailable metadata endpoints retain the existing pass-through
behavior; authentication and server failures are still reported.
--assignee none and --assignee unassign explicitly leave a new issue unassigned
or clear an existing assignee. Omitting the flag preserves Jira's create default
or the existing assignee. These aliases also work with issues assign.
On issues create and issues move, sprint names and active are scoped to the
issue project's Scrum boards. --board ID overrides this scope. Exact names
win over substring matches; multiple matches list sprint and board IDs instead
of picking one. Numeric sprint IDs identify a sprint directly; if --board is
also supplied, membership on that board is checked.
Creation resolves the sprint and checks that it is active or future before
creating the issue. If the subsequent move fails, the CLI exits with code 8
and error kind partial_success. JSON stderr includes error.details.key,
url, created, sprintId, sprintMoved, and recoveryCommand. The error is
not retryable as a whole: use the returned jira issues move KEY --sprint ID
command to finish the operation. Rerunning issues create would create a duplicate.
Projects
Search
Write previews and bulk outcomes
Create and update previews include the exact normalized fields payload;
move previews identify the resolved sprint. steps lists the planned writes
in order, including the sprint move after creation. Previews share the real
write's normalization and preflight validation. Jira can still reject a later
write because permissions, workflow or plugin validators, or server state
changed. metadata and warnings identify checks that could not be completed.
issues create-meta lists types when --type is omitted. With a type it
returns the create screen's field definitions, including required fields,
defaults and allowed values, plus epic support. fields: null means the fields
were not requested or could not be discovered; warnings distinguish the
latter. Epic support describes evidence from that screen; when metadata is
unavailable, a write can still attempt the documented instance fallback.
Unsupported create-meta endpoints return error details with reason: "unsupported"
after confirming the project exists. allowedValues: null means unknown, while [] means no allowed values.
Transitions accept an exact ID, a case-insensitive action name, or a case-insensitive destination status, in that order. Ambiguity is an error; the structured error details list candidates and a discovery command.
Bulk commands emit a summary even for zero matches. Any per-issue failure
returns exit 9 (bulk_failure); stdout still contains the full summary.
total = succeeded + ready + failed + notAttempted, where ready counts
dry-run entries that passed available checks and succeeded counts completed
writes. Assignment previews resolve the assignee but do not check per-issue
assignability; transition previews resolve the transition for each issue. Issue-local
failures do not discard or replay completed work. Authentication/permission,
rate-limit, network, and server failures stop further requests and mark the
remaining issues notAttempted. Each failure includes errorKind and
retryable, plus the failed phase (lookup or write). Write timeouts,
connection failures, and server errors are marked outcome: "unknown": the
server may have applied the write. These count under failed because success
was not confirmed; check issue state before retrying them. Never blindly rerun a partially completed bulk command.
Boards and sprints
--project filters boards on the server. For sprint listing, a project and
board filter intersect; a numeric board ID without a project is fetched
directly. Kanban boards are skipped in broad discovery and rejected when
they are the only boards selected by a filter. Unknown board types are queried;
boards Jira explicitly reports as not supporting sprints are skipped, with
messages in the top-level warnings array. Other errors still fail the command. Shared sprints appear once, with every matching board in
boards; total counts unique sprints. The primary boardId/boardName is the
origin board when matched, otherwise the lowest matched ID. Results and board
context are ordered by ID. Repeat --state or comma-separate its values;
all disables the state filter.
Users and fields
Shell completions
# Install automatically (bash, zsh, fish)
# Or redirect manually
Config
Agent use
Use jira schema --command when an agent knows which operation it needs. The
compact response includes that command's arguments, effects, pagination,
output fields, global flags, and error contract. Use the full jira schema
document only for discovery across the complete command tree.
|
Argument types, enum values, conflicts_with, and requires reflect the CLI
parser. Commands with previews publish their conditional contract under
x-dry-run: arg, effects, and output_fields. Those fields describe the
preview; the command's ordinary output_fields describe the real result.
Create, update, and move also publish a complete stdout_schema covering both
results. Transitions are declared non-idempotent because repeating a workflow
action can trigger additional effects.
Bulk commands also declare x-output-on-error so consumers know to parse
stdout when the exit code is nonzero.
Read-only mode
Set JIRA_READ_ONLY=1 to block every command that writes to Jira. The CLI returns exit code 2 with a structured error for any blocked command, before it opens a connection. This is useful when giving an AI agent read access to Jira without the risk of unintended modifications.
--dry-run remains available for create, update, move, and both bulk commands in read-only mode. These commands resolve and validate inputs without writing to Jira; the HTTP client also blocks write requests as a second check.
The guard covers writes to Jira, not writes to your disk: jira init, jira config init, jira config remove and jira issues download-attachment still work, because they change local files only.
jira schema lists the blocked commands under read_only.blocked_commands, so an agent can see what it is allowed to do without trying:
|
A value the CLI does not recognise (JIRA_READ_ONLY=enabled, or a typo) is rejected as a config error rather than read as "off", so a mis-set guard fails loudly instead of quietly allowing writes.
You can set it in the config file:
[]
= true
Or per-profile:
[]
= true
When giving an AI agent access to the CLI, set the env var in the agent's configuration. For example, in Claude Code's .claude/settings.json:
Any agent that supports environment variable configuration can use the same approach.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Unexpected error |
| 2 | Bad input or config error |
| 3 | Authentication failed |
| 4 | Resource not found |
| 5 | Jira API error |
| 6 | Rate limited |
| 7 | Conflict, including a target file that already exists |
| 8 | Issue created, but sprint assignment failed; use the recovery command in the error details |
| 9 | Bulk operation has failures; parse the complete per-issue summary on stdout |
A downstream that stops reading, as in jira issues list | head -5, terminates
the CLI with SIGPIPE rather than any of these codes. That is what every other
member of a pipeline does, and shells report it as 141.
Output flags
| Flag | Effect |
|---|---|
--json |
Force JSON output (auto when stdout is not a TTY) |
--quiet |
Suppress counts, confirmations, and status messages |
--no-color |
Disable ANSI color (NO_COLOR is also honored) |
These flags are available on every command. --json is a compatibility alias for --output json; use --output text to force human-readable output in a pipeline.
Development
Running e2e tests
The e2e test suite runs against a real Jira instance. A Jira Data Center instance is required (Data Center license needed):
JIRA_E2E_HOST=http://localhost:8080 \
JIRA_E2E_EMAIL=admin \
JIRA_E2E_TOKEN=mytoken \
JIRA_E2E_PROJECT=TST \
All e2e tests tag created issues with [e2e-auto] for easy cleanup.
CI
GitHub Actions runs fmt → clippy → nextest on Ubuntu and macOS for every
push and pull request. The workflow is at .github/workflows/ci.yml.
License
MIT
Releasing
Vership owns versioning, changelog generation, release commits, and tags. See the release runbook for the verified workflow and recovery policy.