Claude
Skills
Sign in
Back

jira-cli

Included with Lifetime
$97 forever

Use when the user mentions Jira tickets, issues, tasks, stories, bugs, sprints, epics, boards, or any project management activity involving Jira. Also trigger when users say "my tickets", "what am I working on", "create a bug", "move this to done", "assign this to me", "log time", "sprint progress", or "what's in the backlog". Trigger even without explicit "Jira" mention if context involves issue tracking or agile project management.

Data & Analytics

What this skill does


# Jira CLI

Use `jira-cli` to interact with Jira from the terminal. This skill teaches you
how to pick the right commands, avoid interactive prompts that will hang, and
parse output reliably.

## When NOT to Use

- `jira-cli` is not installed or initialized (`jira serverinfo` fails) — set up prerequisites first
- The task requires Jira admin operations (project configuration, workflow editing, permission schemes) not supported by jira-cli
- The user wants to interact with the Jira web UI directly rather than the terminal

## Prerequisites

Before using jira-cli commands, verify your setup:

1. **Install jira-cli**: `brew install ankitpokhrel/jira-cli/jira-cli` (or see
   [install docs](https://github.com/ankitpokhrel/jira-cli#installation))
2. **Initialize**: Run `jira init` and follow prompts (server URL, auth type, project)
3. **Set API token**: Export `JIRA_API_TOKEN` in your shell profile
4. **Verify**: Run `jira serverinfo --plain` — should print your Jira server version

If `jira serverinfo` fails, check:
- Token is set: `echo $JIRA_API_TOKEN`
- Config exists: `cat ~/.config/.jira/.config.yml`
- Network access to your Jira instance

## Critical Rules

These rules prevent common failures when running jira-cli in a non-interactive
agent context:

1. **Always use `--plain` for list/view commands.** The default TUI output is
   interactive and unparseable. Add `--plain` to every `jira issue list`,
   `jira sprint list`, `jira epic list`, and `jira issue view` call.

2. **Always use `--no-input` for create/edit/comment/worklog commands.** Without
   it, jira-cli opens an interactive editor which hangs indefinitely. Add
   `--no-input` to: `issue create`, `issue edit`, `epic create`,
   `issue comment add`, `issue worklog add`. Do NOT use it on `link`, `move`,
   `assign`, or `delete` — those commands don't support it.

3. **Capture the current user early.** Run `jira me` at the start of any
   session that involves user-specific queries. Store the result and use it
   with `-a` flags instead of calling `jira me` inline with `$()` which can
   fail silently.

4. **Use `-p PROJECT` explicitly** when the user mentions a specific project,
   rather than relying on the default config.

## Common Pitfalls

**`-p` (project) vs `-P` (parent/epic link):** These are DIFFERENT flags.
Use lowercase `-p PROJ` for project. Uppercase `-P PARENT-KEY` links to a
parent issue or epic. Confusing them causes `Epic with key 'X' does not exist`.

**`-b -` does NOT read stdin.** It literally sets the body to the string `"-"`,
wiping the description. To pipe a description from stdin, omit `-b` entirely:

```bash
# WRONG — wipes description to "-"
cat description.txt | jira issue edit ISSUE-123 --no-input -b -

# CORRECT — reads body from stdin automatically
cat description.txt | jira issue edit ISSUE-123 --no-input
```

**`--no-input` only works on create/edit/comment/worklog commands.** Do NOT add
it to `jira issue link`, `jira issue move`, `jira issue assign`, or
`jira issue delete` — those commands don't support it and will error with
`unknown flag: --no-input`.

**`--body` only works on create/edit commands.** For comments, pass the body as
a positional argument or pipe to stdin with `--template -`:

```bash
# Positional argument
jira issue comment add ISSUE-123 "Comment text" --no-input

# Pipe from stdin
cat comment.txt | jira issue comment add ISSUE-123 --template - --no-input
```

## Choosing Your Approach: Flags vs JQL

jira-cli supports two filtering styles. Pick the right one:

**Use flags** when filtering on a single dimension or simple combinations:
```bash
jira issue list -a"[email protected]" -s"In Progress" --plain
```

**Use JQL (`-q`)** when you need complex logic, cross-project queries, OR
conditions, functions, or fields not covered by flags:
```bash
jira issue list -q "assignee = currentUser() AND status WAS 'In Progress' BEFORE '2024-01-01'" --plain
```

Common JQL patterns:
- Cross-project: `-q "project IN (PROJ1, PROJ2) AND assignee = currentUser()"`
- OR conditions: `-q "priority = High OR priority = Highest"`
- Text search: `-q "summary ~ 'login bug'"`
- Recently updated: `-q "updated >= -7d AND assignee = currentUser()"`
- Unassigned: `-q "assignee IS EMPTY AND project = PROJ"`
- Sub-tasks: `-q "parent = STORY-123"`
- Epic children: `-q "'Epic Link' = EPIC-123"`
- Linked issues: `-q "issue in linkedIssues('ISSUE-123')"`
- Linked issues (by type): `-q "issue in linkedIssues('ISSUE-123', 'is a parent of')"`

## Reading Output

Plain output (`--plain`) is tab-delimited with default columns:
`TYPE`, `KEY`, `SUMMARY`, `STATUS`, `ASSIGNEE`. Use `--no-headers` when parsing
programmatically. Use `--raw` for full JSON when you need fields not available
in plain mode. See `references/commands.md` for all output flags (`--columns`,
`--csv`, `--delimiter`, etc.).

### Parsing Plain Output

Plain output is tab-delimited. Extract specific fields with `awk`:

```bash
# Extract just issue keys (column 2)
jira issue list -a"$ME" --plain --no-headers | awk -F'\t' '{print $2}'

# Extract key and status (columns 2 and 4)
jira issue list --plain --no-headers | awk -F'\t' '{print $2, $4}'

# Filter rows by status
jira issue list --plain --no-headers | awk -F'\t' '$4 == "In Progress"'
```

### Parsing JSON Output

Use `--raw` with `jq` for structured data:

```bash
# Get issue description
jira issue view ISSUE-123 --raw | jq -r '.fields.description'

# Extract custom field value
jira issue view ISSUE-123 --raw | jq -r '.fields.customfield_10001'

# Get all issue keys from a list as JSON array
jira issue list -a"$ME" --raw | jq '[.[].key]'
```

### Special Characters

Summaries and descriptions may contain tabs, quotes, or newlines. When using
plain output for programmatic processing, prefer `--raw` (JSON) for fields that
may contain freeform text.

## Defensive Patterns

### Pagination

`jira issue list` returns at most 100 results by default. For larger result
sets, paginate explicitly:

```bash
# First 50 results
jira issue list -pPROJ --paginate 0:50 --plain

# Next 50
jira issue list -pPROJ --paginate 50:50 --plain
```

Stop paginating when the returned row count is less than the requested limit.

### Rate Limiting

Jira Cloud enforces API rate limits. When you receive a 429 response:

1. **Do not retry immediately.** Wait at least 5 seconds before the next call.
2. **Space sequential commands.** When running multiple commands in sequence
   (e.g., creating several issues), add `sleep 1` between calls.
3. **Prefer batch-capable flags** over loops — e.g., `jira epic add EPIC-1
   ISSUE-1 ISSUE-2 ISSUE-3` instead of three separate `epic add` calls.

### Retry on Transient Errors

Network timeouts and 5xx errors are transient. Retry up to 2 times with
increasing delay:

```bash
# Simple retry pattern
for i in 1 2 3; do
  jira issue view ISSUE-123 --plain && break
  sleep "$((i * 2))"
done
```

Do not retry 4xx errors (except 429) — they indicate a permanent problem.

## Discovery Patterns

Before running commands, you often need to discover IDs and names. Use these
patterns to find what you need.

### Project Keys

```bash
# List available projects with keys
jira project list --plain --no-headers | awk -F'\t' '{print $1, $2}'
```

If the user says "my project" without a key, list projects and ask which one.

### Sprint IDs

Sprint commands need numeric IDs. Extract from the sprint list:

```bash
# Get active sprint ID
SPRINT_ID=$(jira sprint list --state active --table --plain --no-headers | awk -F'\t' '{print $1}' | head -1)
if [ -z "$SPRINT_ID" ]; then
  echo "No active sprint found" >&2
  exit 1
fi
```

### Status Names

Status names are instance-specific and case-sensitive. When `jira issue move`
fails with "No transition found", check the current status first:

```bash
# Get current status
jira issue view ISSUE-123 --raw | jq -r '.fields.status.name'
```

Note: The standard `--raw` response may not include a `transitions` array
(it requires `?expand=transitions

Related in Data & Analytics