| name | jira-cli |
| description | WHAT: Command line tool for Atlassian Jira. WHEN: managing issues, adding comments, viewing tickets, sprint workflows. KEYWORDS: jira, ticket, issue, sprint, comment, cli, atlassian, backlog, story, epic. |
Jira CLI
Command line tool for Atlassian Jira. GitHub
Prerequisites
command -v jira >/dev/null 2>&1 || echo "ERROR: jira CLI not found"
test -f ~/.config/.jira/.config.yml || echo "ERROR: jira not configured"
Setup:
- Install:
brew install jira or download binary
- Configure:
jira init
- Cloud auth:
export JIRA_API_TOKEN=your_token
- On-premise PAT:
export JIRA_AUTH_TYPE=bearer JIRA_API_TOKEN=your_pat
Core Commands
jira issue view PROJ-123 --json
jira issue view PROJ-123 --comments 10 --json
jira issue comment add PROJ-123 "Comment text"
echo "Comment" | jira issue comment add PROJ-123
jira issue comment add PROJ-123 <<'EOF'
Content here
EOF
jira issue list --created -7d --json
jira issue list --jql "status = 'To Do'" --json
jira issue create -tBug -s"Summary" -b"Description" --no-input
jira issue create -tTask -s"Summary" --project=PROJ --no-input <<'EOF'
h2. Overview
Description content here
h2. Subtasks
* Task 1
* Task 2
EOF
Output Formats
--json - Structured JSON (use with jq)
--plain - Simple tabular output
--no-headers - Remove column headers
--columns key,summary - Select specific columns
Parsing Output
TICKET=$(jira issue view PROJ-123 --json)
SUMMARY=$(echo "$TICKET" | jq -r '.fields.summary')
DESCRIPTION=$(echo "$TICKET" | jq -r '.fields.description // "No description"')
COMMENTS=$(echo "$TICKET" | jq -r '.fields.comment.comments[].body')
jira issue list --plain --no-headers | while IFS=$'\t' read -r key summary; do
echo "$key: $summary"
done
ADF (Atlassian Document Format) Parsing
Jira stores descriptions and comments in ADF (nested JSON), not plain text.
Parser script: /scripts/parse-adf.js
Usage:
jira issue view PROJ-123 --json | jq '.fields.description' | node /scripts/parse-adf.js
echo "$COMMENT_JSON" | jq '.body' | node /scripts/parse-adf.js
jq -c '.fields.comment.comments[]' ticket.json | while IFS= read -r comment; do
AUTHOR=$(echo "$comment" | jq -r '.author.displayName')
BODY=$(echo "$comment" | jq '.body' | node /scripts/parse-adf.js)
echo "Comment by $AUTHOR:"
echo "$BODY"
echo "---"
done
Error Handling
if ! command -v jira &> /dev/null; then
echo "❌ jira CLI not installed"
exit 1
fi
if ! RESULT=$(jira issue view "$KEY" --json 2>&1); then
echo "❌ Failed to fetch $KEY"
echo "$RESULT"
exit 1
fi
Common Patterns
Fetch ticket for spec:
TICKET=$(jira issue view PROJ-123 --json)
SUMMARY=$(echo "$TICKET" | jq -r '.fields.summary')
Post questions:
jira issue comment add PROJ-123 <<'EOF'
1. Question one?
2. Question two?
EOF
Check for answers:
jira issue view PROJ-123 --comments 5 --json | jq -r '.fields.comment.comments[].body'
Key Points
- ✅ Always use
--json for scripting
- ✅ Check exit codes before parsing
- ✅ Use
jq with defaults: .field // "default"
- ✅ Quote heredocs:
<<'EOF' not <<EOF
- ✅ Use stdin (heredoc) for long descriptions, not
-b flag with heredoc
- ✅ For very long descriptions, use stdin directly instead of wrapping in
-b "$(cat <<'EOF' ...)"
- ❌ Don't parse interactive UI output
- ❌ Don't assume fields exist (use
// "default")
- ❌ Don't use
-b"$(cat <<'EOF' ... EOF)" pattern - it can cause hangs and syntax errors
Common Issues and Solutions
Issue 1: Command Hangs with Long Descriptions
Problem: Using -b"$(cat <<'EOF' ... EOF)" with very long descriptions causes the command to hang indefinitely.
Root Cause: Command substitution with heredocs in argument position can cause shell parsing issues and timeouts.
Solution: Use stdin directly instead of -b flag:
jira issue create -tTask -s"Summary" -b"$(cat <<'EOF'
Long description here...
EOF
)" --project=PROJ --no-input
jira issue create -tTask -s"Summary" --project=PROJ --no-input <<'EOF'
Long description here...
EOF
Issue 2: Syntax Errors with Nested Quotes in Heredocs
Problem: Syntax errors like "unexpected EOF while looking for matching ''" occur.
Root Cause: Mixing heredoc syntax with command substitution and quotes can create parsing ambiguities.
Solution: Use stdin directly without command substitution:
jira issue create -tTask -s"Summary" -b"$(cat <<'EOF'
Text with 'quotes' here
EOF
)" --project=PROJ --no-input
jira issue create -tTask -s"Summary" --project=PROJ --no-input <<'EOF'
Text with 'quotes' here
EOF
Issue 3: Creating Multiple Tickets Efficiently
Problem: Need to create many tickets with full descriptions from a structured document.
Solution: Break into individual commands with stdin for each:
jira issue create -tTask -s"[Project] Task 1: Title" --project=PROJ --no-input <<'EOF'
h2. Overview
Task 1 description
h2. Subtasks
* Subtask 1.1
* Subtask 1.2
EOF
echo "Created Task 1"
jira issue create -tTask -s"[Project] Task 2: Title" --project=PROJ --no-input <<'EOF'
h2. Overview
Task 2 description
h2. Subtasks
* Subtask 2.1
* Subtask 2.2
EOF
echo "Created Task 2"
Issue 4: Jira Wiki Markup Formatting
Best Practices for Jira Wiki Markup in descriptions:
jira issue create -tTask -s"Title" --project=PROJ --no-input <<'EOF'
h2. Main Heading
h3. Sub Heading
* Bullet point 1
* Bullet point 2
** Nested bullet
*bold text*
_italic text_
{{monospace code}}
{code}
code block
{code}
[Link text|https://example.com]
EOF
Common markup:
- Headers:
h1., h2., h3., h4., h5., h6.
- Bold:
*bold*
- Italic:
_italic_
- Monospace:
{{text}}
- Code blocks:
{code}...{code}
- Bullets:
*, ** (nested)
- Numbered:
#, ## (nested)
- Links:
[text|url]
Multiple Configs
JIRA_CONFIG_FILE=/path/to/config.yml jira issue view PROJ-123 --json
jira issue view PROJ-123 --json --config /path/to/config.yml
Attachments via REST API
Note: jira-cli does NOT support attachments. Use the provided script instead.
Script: ./scripts/jira-attach.sh
./scripts/jira-attach.sh PROJ-123 /path/to/spec.md
The script reads server and login from existing jira-cli config (~/.config/.jira/.config.yml) and uses JIRA_API_TOKEN for authentication.
Handling Long Content
For large documents (>32KB or >1000 lines), attach the full file and post a summary:
./scripts/jira-attach.sh PROJ-123 spec.md
jira issue comment add PROJ-123 <<'EOF'
h2. Implementation Spec
Summary of key components and requirements.
h3. Full Specification
See attached: [^spec.md]
EOF
Attachment links: Use [^filename.ext] to link to attachments in Jira.
Markdown to Jira Wiki Conversion
Jira uses Wiki markup, not Markdown. Convert before posting:
| Markdown | Jira Wiki |
|---|
# H1 | h1. H1 |
## H2 | h2. H2 |
**bold** | *bold* |
_italic_ | _italic_ |
[text](url) | [text|url] |
`code` | {{code}} |
```lang ``` | {code:lang}...{code} |
- item | * item |
1. item | # item |
| table | | || header || then | cell | |
External References Warning
When posting to Jira, ensure all references are accessible:
- ❌ Never reference local filesystem paths (e.g.,
/Users/foo/spec.md)
- ❌ Never reference internal URLs inaccessible from Jira
- ✅ Use
[^filename.ext] to reference Jira attachments
- ✅ Use Confluence/GitHub URLs for external docs
- ✅ Attach files instead of referencing local paths
Best Practices for Bulk Ticket Creation
When creating multiple tickets with detailed descriptions:
- Use stdin for descriptions: Always use heredoc via stdin, never
-b "$(cat <<'EOF' ...)"
- One command per ticket: Don't try to batch multiple creates in complex scripts
- Add progress indicators: Use
echo "Created Task N" between commands
- Handle timeouts: Set appropriate timeout values for long operations
- Test first: Create one ticket manually to verify format before bulk operations
- Quote properly: Use
<<'EOF' (quoted) to prevent variable expansion in heredocs
Example workflow:
jira issue create -tTask -s"[Test] Task 1" --project=PROJ --no-input <<'EOF'
h2. Overview
Test description
EOF
jira issue create -tTask -s"[Test] Task 2" --project=PROJ --no-input <<'EOF'
h2. Overview
Real description
EOF
echo "Created Task 2"
Documentation