Jira CLI

Repository: ankitpokhrel/jira-cli

Jira CLI lets you create, view, and manage Jira tickets from the command line. It is useful before you have full web access, and it opens the door to scripting — for example, automating ticket transitions or generating peer-review sub-tasks (see the workspace create-jira-stories.sh and review-build.sh helpers).

Using the Jira CLI requires a Crowd username and a Jira personal access token (PAT).

If you do not yet have a Crowd account, the onboarding team will provide a temporary token to use until your own credentials are ready. When you switch to your own account, update JIRA_API_TOKEN and re-run jira init (see Token Checklist).

Prerequisites

  • Homebrew (macOS) — or see the repo for other install methods.

  • A Jira personal access token and the username it belongs to (see the note above).

  • Network access to https://issues.mobilehealth.va.gov (VPN if you are off-network).

Installation

1. Install the CLI

brew install jira-cli
jira version   # confirm it is on your PATH

2. Configure your token

Jira CLI reads your PAT from the JIRA_API_TOKEN environment variable. Add it to ~/.zshrc (or ~/.bashrc):

export JIRA_API_TOKEN="<your Jira PAT>"

Then reload your shell:

source ~/.zshrc

Treat the PAT like a password — never commit it or paste it into shared docs. Keeping it in an environment variable means it stays out of your shell history and the generated config file.

3. Initialize

Run jira init and answer the prompts with the values below:

Installation type   > Local
Authentication type > Bearer
Link to Jira server > https://issues.mobilehealth.va.gov
Login username      > <your username>
Default project     > CKM
Default board       > Greenfield

On success, you should see:

Configuration generated: /Users/<you>/.config/.jira/.config.yml

To skip the prompts (in a script, for example), pass the answers as flags. The board’s name in Jira ends with a space, so include it:

jira init --installation local --server https://issues.mobilehealth.va.gov \
  --login <your username> --auth-type bearer --project CKM --board "Greenfield "

4. Verify

jira me                       # prints the account you are authenticated as
jira issue view CKM-31229     # confirms read access to the CKM project

Enable shell completion so commands, flags, and issue types tab-complete:

# zsh
echo 'source <(jira completion zsh)' >> ~/.zshrc && source ~/.zshrc

# bash
echo 'source <(jira completion bash)' >> ~/.bashrc && source ~/.bashrc

Configuration notes

  • The config lives at ~/.config/.jira/.config.yml and records your server, username, default project (CKM), and default board (Greenfield).

  • Re-run jira init any time those values change (new credentials, different default project, etc.).

  • Most commands accept overrides — e.g. --project, --board — so you rarely need to edit the file by hand.

Viewing and searching issues

# View a single issue (add --comments N to include the latest comments).
jira issue view CKM-31229
jira issue view CKM-31229 --comments 5

# Open an issue in your browser.
jira open CKM-31229

# Issues assigned to you that are not done.
jira issue list -a $(jira me) -s ~Done

# Filter by status, type, or who reported it.
jira issue list -s "In Progress"
jira issue list -t Bug
jira issue list -r $(jira me)

# Anything updated in the last 7 days, newest first.
jira issue list --updated -7d --order-by updated --reverse

# Full control with JQL.
jira issue list -q "assignee = currentUser() AND status = Open"
jira issue list -q "component = 'callback-service' AND status != Done"

Add --plain for clean output and --no-headers --columns key,status,summary to make results easy to pipe into scripts:

jira issue list -a $(jira me) -s ~Done --plain --no-headers --columns key,status,summary

Creating issues

Use jira issue create to create a Story, Technical Debt, or Task. The --no-input flag skips the interactive prompts so the whole ticket can be created in one command.

jira issue create \
  --project CKM \
  --type "Story" \
  --summary "Add retry logic to the callback dispatcher" \
  --body "As a service owner, I want failed callbacks to be retried with backoff so that transient downstream errors do not drop notifications." \
  --component "callback-service" \
  --no-input

The command prints the new ticket key (e.g. CKM-31299). Change --type to create a different issue type:

  • --type "Story"

  • --type "Technical Debt"

  • --type "Task"

  • --type "Bug"

You can set more fields at creation time:

jira issue create --project CKM --type "Bug" \
  --summary "NPE when callback URL is blank" \
  --body "Steps to reproduce..." \
  --component "callback-service" \
  --priority "High" \
  --label tech-debt --label needs-triage \
  --assignee <username> \
  --no-input

--type, --component, --priority, and label values must match exactly what is configured in Jira (including spaces and capitalization). Run jira issue create with no flags once to see the interactive pickers, or inspect an existing ticket to confirm valid names.

Adding the ticket to a sprint

jira issue create does not have a --sprint flag. Add the ticket to a sprint after it is created using the sprint command. First find the sprint ID, then add the issue:

# List sprints for the default board to find the sprint ID:
jira sprint list --table --plain --columns id,name,state

# Add one or more issues to that sprint (replace 1234 and the ticket key):
jira sprint add 1234 CKM-31299

Create the ticket and add it to the sprint in one line by capturing the new key:

KEY=$(jira issue create --project CKM --type "Task" \
  --summary "Bump mobile-framework to latest" \
  --body "Update the Mobile Framework version and resolve any resulting compiler warnings." \
  --component "callback-service" --no-input 2>/dev/null | grep -oE 'CKM-[0-9]+')
jira sprint add 1234 "$KEY"

Updating issues

# Transition an issue (the name must match a workflow transition).
jira issue move CKM-31229 "Start Progress"
jira issue move CKM-31229 "Done"

# Edit fields on an existing issue.
jira issue edit CKM-31229 --summary "New summary" --priority High
jira issue edit CKM-31229 --label tech-debt

# Assign / reassign (use your username, or "x" to unassign).
jira issue assign CKM-31229 <username>
jira issue assign CKM-31229 $(jira me)
jira issue assign CKM-31229 x

# Comment on an issue and read comments back.
jira issue comment add CKM-31229 "Deployed to SQA for verification."
jira issue comment list CKM-31229

# Link related issues.
jira issue link CKM-31229 CKM-31300 "Blocks"
jira issue unlink CKM-31229 CKM-31300

# Attach a file or watch an issue.
jira issue attach CKM-31229 verify.log
jira issue watch CKM-31229

Sub-tasks and peer review

Create a peer-review sub-task

jira issue create \
  --type "Sub-task" \
  --project CKM \
  --parent <parent CKM ticket> \
  --summary "Peer/Acceptance Review" \
  --assignee <peer reviewer username> \
  --component "<component>"

If you omit --no-input, the CLI will prompt for the description and a confirmation:

? Description <Received>   > (press enter to accept)
? What's next? Submit      > Submit

Jira automation webhook (auto-create review tickets)

We have Jira automations that automatically create and assign peer-review tickets to the designated CKM peer reviewer. Trigger the webhook with:

curl -X POST "https://issues.mobilehealth.va.gov/rest/cb-automation/latest/hooks/e2fa15903fa9773b21d929e2829b752bfce2d1a9/?issue/=<TICKET NUMBER OF STORY>"

The workspace review-build.sh helper wires this together — it reads .serviceinfo, runs service-lint, triggers a Jenkins build, and creates the peer-review sub-task — so you usually do not need to call the webhook by hand.

Sprints, boards, and epics

# Sprints on the default board.
jira sprint list --table --plain --columns id,name,state

# Show issues in the active sprint.
jira sprint list --current

# Epics, and the issues under one.
jira epic list
jira epic list <EPIC-KEY>

# Add existing issues to an epic.
jira epic add <EPIC-KEY> CKM-31299 CKM-31300

# List projects and boards.
jira project list
jira board list

Troubleshooting

Authentication errors (401 / "unauthorized")

Your PAT is wrong or expired. Generate a new one from your Jira profile, update JIRA_API_TOKEN, run source ~/.zshrc, and re-run jira init. Confirm with jira me.

Connection refused / timeouts

You are likely off-network. Connect to the VPN and confirm you can reach https://issues.mobilehealth.va.gov in a browser.

Invalid issue type / Invalid component

The value does not match Jira exactly. Drop --no-input to use the interactive pickers, or view an existing ticket to copy the exact name (including spaces and capitalization).

Wrong project or board defaults

Re-run jira init to regenerate ~/.config/.jira/.config.yml, or pass --project / --board per command.

Commands not tab-completing

Make sure the completion line from the install step is in your shell config and you have re-`source`d it.