A modern, extensible command-line interface for Atlassian JIRA built with Factory pattern and Commander.js. Manage your issues, projects, and sprints directly from the terminal with a beautiful, user-friendly interface.
- 📋 Issue Management: Create, read, update, and delete JIRA issues with full CRUD operations
- 💬 Comment Management: Add, list, edit, and delete comments on issues with file support
- 📝 Markdown Support: Export issues to markdown files and create/update issues from markdown
- 📊 Project Information: View project details, statistics, and team insights
- 🏃 Sprint Management: Monitor sprint progress, burndown charts, and team velocity
- ⚙️ Smart Configuration: Environment variables and CLI options for flexible setup
- 📈 Advanced Analytics: Get insights into project health, user workload, and performance metrics
- 🤖 Automation-Friendly: Fully scriptable, non-interactive mode for CI/CD pipelines
- 🎨 Beautiful Output: Formatted tables, colored output, and progress indicators
- 🔍 Powerful Search: Filter issues with JQL-like queries and advanced search options
- 🏗️ Modern Architecture: Factory pattern, dependency injection, and extensible command structure
- 🛡️ Secure: Support for API tokens, environment variables, and secure credential storage
# Install globally via npm
npm install -g @pchuri/jira-cli
# Or use npx (no installation required)
npx @pchuri/jira-cli
# Or install locally for development
git clone https://github.com/pchuri/jira-cli.git
cd jira-cli
npm install
npm linkInstall the packaged Jira skill into the current project:
jira install-skillThis copies the skill to ./.claude/skills/jira/SKILL.md.
If the file already exists, the command errors by default. Use --force to overwrite:
jira install-skill --forceUse a custom destination directory if needed:
jira install-skill --dest ./custom/skills/jira-
Configure using CLI options (Bearer auth - recommended):
jira config --server https://your-jira-instance.atlassian.net \ --token your-api-token -
Or with username for Basic authentication:
jira config --server https://your-jira-instance.atlassian.net \ --username your-email@company.com \ --token your-api-token -
Or use environment variables:
# Bearer authentication (recommended) export JIRA_HOST=your-jira-instance.atlassian.net export JIRA_API_TOKEN=your-api-token export JIRA_API_VERSION=auto # optional: auto (default), 2, 3 # Basic authentication (optional) export JIRA_HOST=your-jira-instance.atlassian.net export JIRA_API_TOKEN=your-api-token export JIRA_USERNAME=your-email@company.com export JIRA_API_VERSION=auto # optional: auto (default), 2, 3 # Scoped API token (Atlassian Cloud) — also set Cloud ID export JIRA_CLOUD_ID=your-cloud-id # routes through Atlassian Platform API Gateway
-
Verify connection:
jira config --show jira issue view PROJ-123
-
Create a new issue:
jira issue create --project PROJ --type Bug --summary "Login fails" -
View project information:
jira project list
JIRA CLI supports the following authentication modes:
- Bearer Token Authentication (Recommended) - Uses API token directly
- Basic Authentication - Uses username + API token (legacy)
- Scoped API Token (Atlassian Cloud) - Basic auth + Cloud ID, routed through the Atlassian Platform API Gateway. Use this for Atlassian's newer scoped API tokens.
# Bearer authentication (server + token only)
jira config --server https://yourcompany.atlassian.net \
--token your-api-token
# Basic authentication (with username)
jira config --server https://yourcompany.atlassian.net \
--username your-email@company.com \
--token your-api-token
# Scoped API token (Atlassian Cloud) — set Cloud ID to route via the Platform API Gateway
jira config --server https://yourcompany.atlassian.net \
--username your-email@company.com \
--token your-scoped-api-token \
--cloud-id your-cloud-id
# Or set individual values
jira config set server https://yourcompany.atlassian.net
jira config set token your-api-token
jira config set username your-email@company.com # optional
jira config set cloudId your-cloud-id # optional, enables scoped tokens
jira config set apiVersion auto # optional: auto (default), 2, 3
# Show current configuration
jira config --showBy default, the CLI uses auto mode: it tries Jira REST API v3 first and automatically retries with v2 if needed. If a fallback happens, the CLI keeps using the working version for the rest of the process.
You can override the behavior:
- Config:
jira config set apiVersion auto|2|3 - Env:
JIRA_API_VERSION=auto|2|3
You can configure the CLI using environment variables in either a new or legacy format:
# Bearer authentication
export JIRA_HOST="your-jira-instance.atlassian.net"
export JIRA_API_TOKEN="your-api-token"
export JIRA_API_VERSION="auto" # optional: auto (default), 2, 3
# Basic authentication (add username)
export JIRA_HOST="your-jira-instance.atlassian.net"
export JIRA_API_TOKEN="your-api-token"
export JIRA_USERNAME="your-email@company.com"
export JIRA_API_VERSION="auto" # optional: auto (default), 2, 3export JIRA_DOMAIN="your-domain.atlassian.net"
export JIRA_USERNAME="your-email@company.com"
export JIRA_API_TOKEN="your-api-token"
export JIRA_API_VERSION="auto" # optional: auto (default), 2, 3Atlassian recommends using scoped API tokens over classic (unscoped) tokens. Scoped tokens require requests to go through the Atlassian Platform API Gateway at https://api.atlassian.com/ex/jira/{cloudId} instead of https://{your-site}.atlassian.net.
To use a scoped token, configure your Cloud ID in addition to the usual server, username, and token:
# Via flags
jira config --server https://yourcompany.atlassian.net \
--username your-email@company.com \
--token your-scoped-api-token \
--cloud-id your-cloud-id
# Or via env vars (works with both JIRA_HOST and JIRA_DOMAIN formats)
export JIRA_CLOUD_ID="your-cloud-id"When cloudId is set, all REST API and Agile API requests are automatically routed through the Platform API Gateway. Without it, requests use the configured server URL directly (compatible with classic tokens, Jira Data Center, and Jira Server).
You can fetch your Cloud ID without authentication by visiting (or curl-ing):
https://your-site.atlassian.net/_edge/tenant_info
The response contains a cloudId field. Copy it into --cloud-id or JIRA_CLOUD_ID.
For self-hosted or reverse-proxied JIRA deployments that authenticate at the TLS layer with client certificates:
jira config --server https://jira.example.com \
--auth-type mtls \
--tls-client-cert ~/.certs/client.pem \
--tls-client-key ~/.certs/client.key \
--tls-ca-cert ~/.certs/ca-chain.pemexport JIRA_HOST="jira.example.com"
export JIRA_AUTH_TYPE="mtls"
export JIRA_TLS_CLIENT_CERT="~/.certs/client.pem"
export JIRA_TLS_CLIENT_KEY="~/.certs/client.key"
export JIRA_TLS_CA_CERT="~/.certs/ca-chain.pem" # optionalNotes:
- mTLS mode does not send an
Authorizationheader; authentication happens at the TLS layer - The CA certificate is optional if your client certificate is signed by a well-known CA
- mTLS is commonly used in enterprise environments with private certificate authorities
- Paths beginning with
~/are expanded to your home directory; certificate files are read at startup, so update the cert paths if they change
- Go to Atlassian Account Settings
- Click "Create API token"
- Give it a label (e.g., "jira-cli")
- Copy the generated token
For scoped tokens, you can choose specific Jira scopes (e.g., read:jira-work, write:jira-work) when creating the token. Scoped tokens require Cloud ID configuration — see Scoped API Tokens (Atlassian Cloud).
# View in terminal
jira issue view PROJ-123
# View as markdown in terminal
jira issue view PROJ-123 --format markdown
# Export to markdown file
jira issue view PROJ-123 --output ./issue.md
# Export with explicit markdown format
jira issue view PROJ-123 --format markdown --output ./issue.md# List all recent issues
jira issue --list
# Filter by project
jira issue --list --project PROJ
# Filter by assignee
jira issue --list --assignee john.doe
# Filter by status
jira issue --list --status "In Progress"
# Combine filters
jira issue --list --project PROJ --assignee john.doe --status "To Do"# Create with required flags
jira issue create --project PROJ --type Bug --summary "Bug in login"
# With description
jira issue create --project PROJ --type Bug --summary "Bug in login" --description "User cannot login"
# With description from file
jira issue create --project PROJ --type Story --summary "Add feature" --description-file ./feature-spec.md
# With all options
jira issue create --project PROJ --type Bug --summary "Critical bug" \
--description "Details here" \
--assignee john.doe --priority High# Update summary
jira issue edit PROJ-123 --summary "Updated summary"
# Update specific fields
jira issue edit PROJ-123 --assignee john.doe --priority High
# Update description
jira issue edit PROJ-123 --description "Updated description"
# Update description from file
jira issue edit PROJ-123 --description-file ./updated-spec.md# Search issues with JQL filtering
jira issue list --jql "login bug"
jira issue list --jql "project = PROJ AND status = 'In Progress'"
# Limit results
jira issue list --jql "bug" --limit 5# Add a comment to an issue
jira issue comment add PROJ-123 "Review completed"
# Add multi-line comment
jira issue comment add PROJ-123 "Build status:
- Unit tests: ✓
- Integration tests: ✓
- Deployment: pending"
# Add comment from file
jira issue comment add PROJ-123 --file ./review-notes.md
# Add internal comment (visible only to team)
jira issue comment add PROJ-123 "Internal note" --internal
# List all comments on an issue
jira issue comment list PROJ-123
# List comments in JSON format
jira issue comment list PROJ-123 --format json
# Edit an existing comment
jira issue comment edit 12345 "Updated comment text"
# Edit comment from file
jira issue comment edit 12345 --file ./updated-notes.md
# Delete a comment (requires confirmation)
jira issue comment delete 12345 --force
# Using command alias
jira issue c add PROJ-123 "Quick comment"
jira issue c list PROJ-123Attach external resources (GitHub PRs, CI runs, dashboards, docs) to a Jira issue as Remote Links.
# List remote links on an issue
jira issue remote-link list PROJ-123
# List in JSON format
jira issue remote-link list PROJ-123 --format json
# Filter by globalId (useful to check if a link already exists)
jira issue remote-link list PROJ-123 --global-id https://github.com/org/repo/pull/42
# Add a remote link
jira issue remote-link add PROJ-123 \
--url https://github.com/org/repo/pull/42 \
--title "org/repo#42"
# Add with globalId for upsert behavior (Jira updates existing link with same globalId)
jira issue remote-link add PROJ-123 \
--url https://github.com/org/repo/pull/42 \
--title "org/repo#42" \
--global-id https://github.com/org/repo/pull/42 \
--relationship "relates to"
# Update an existing remote link
jira issue remote-link update PROJ-123 12345 --title "Updated title"
# Delete a remote link (requires --force)
jira issue remote-link delete PROJ-123 12345 --force
# Using command alias
jira issue rl list PROJ-123
jira issue rl add PROJ-123 --url https://example.com --title "Example"# List all projects
jira project list
# View project details
jira project view PROJ# List available boards first
jira sprint boards
# List sprints for specific board (required when multiple boards exist)
jira sprint list --board 123
# Show only active sprints
jira sprint active --board 123
# Filter by state
jira sprint list --board 123 --state active| Command | Description | Options |
|---|---|---|
config --server <url> --token <token> |
Configure CLI (Bearer auth) | Username optional; use --username <email> for Basic auth |
config --show |
Show current configuration | - |
config set <key> <value> |
Set individual config value | - |
issue view <key> |
View issue details (alias: show) | --format <terminal|markdown>, --output <path> |
issue list |
List issues | --project <key>, --assignee <user>, --reporter <user>, --status <status>, --type <type>, --priority <level>, --created <date>, --updated <date>, --jql <query>, --limit <number> |
issue create |
Create new issue | Required: --project <key>, --type <type>, --summary <text>Optional: --description <text>, --description-file <path>, --assignee <user>, --priority <level> |
issue edit <key> |
Edit an existing issue (alias: update) | At least one required:--summary <text>, --description <text>, --description-file <path>, --assignee <user>, --priority <level> |
issue delete <key> |
Delete issue | Required: --force |
issue comment add <key> [text] |
Add comment to issue (alias: c) | [text] or --file <path>Optional: --internal |
issue comment list <key> |
List comments on issue | --format <table|json> (default: table) |
issue comment edit <id> [text] |
Edit existing comment | [text] or --file <path> |
issue comment delete <id> |
Delete comment | Required: --force |
issue remote-link list <key> |
List remote links on issue (alias: rl) | --format <table|json> (default: table), --global-id <id> |
issue remote-link add <key> |
Add remote link to issue | Required: --url <url>, --title <title>Optional: --global-id <id>, --relationship <rel>, --summary <text>, --icon-url <url>, --icon-title <title> |
issue remote-link update <key> <linkId> |
Update an existing remote link | At least one required:--url <url>, --title <title>, --relationship <rel>, --summary <text>, --icon-url <url>, --icon-title <title> |
issue remote-link delete <key> <linkId> |
Delete remote link | Required: --force |
project list |
List all projects | --type <type>, --category <category> |
project view <key> |
View project details | - |
project components <key> |
List project components | - |
project versions <key> |
List project versions | - |
sprint list |
List sprints | --board <id> (required when multiple boards), --state <state>, --active |
sprint active |
List active sprints | --board <id> (required when multiple boards) |
sprint boards |
List available boards | - |
Configuration is stored using the conf package in your system's config directory:
- macOS:
~/Library/Preferences/jira-cli/config.json - Linux:
~/.config/jira-cli/config.json - Windows:
%APPDATA%\jira-cli\config.json
# Setup (Bearer auth - recommended)
jira config --server https://jira.company.com \
--token your-api-token
# Setup (Basic auth with username)
jira config --server https://jira.company.com \
--username user@company.com \
--token your-api-token
# View an issue in terminal
jira issue view PROJ-123
# View as markdown in terminal
jira issue view PROJ-123 --format markdown
# Export to markdown file
jira issue view PROJ-123 --output ./issue.md
# List issues with filters
jira issue list --project PROJ --status "In Progress" --limit 10
# Create new issue
jira issue create --project PROJ --type Bug --summary "Login fails"
# Create issue with description file
jira issue create --project PROJ --type Story \
--summary "Add feature" \
--description-file ./feature-spec.md
# Update issue
jira issue edit PROJ-123 --summary "Updated summary"
# Delete issue (requires --force)
jira issue delete PROJ-123 --force
# Add comment to an issue
jira issue comment add PROJ-123 "Review completed"
# Add comment from file
jira issue comment add PROJ-123 --file ./review-notes.md
# List all comments
jira issue comment list PROJ-123
# Edit a comment
jira issue comment edit 12345 "Updated comment"
# Delete a comment
jira issue comment delete 12345 --force
# Add a GitHub PR as a remote link
jira issue remote-link add PROJ-123 \
--url https://github.com/org/repo/pull/42 \
--title "org/repo#42" \
--global-id https://github.com/org/repo/pull/42 \
--relationship "relates to"
# List remote links
jira issue remote-link list PROJ-123
# Delete a remote link
jira issue remote-link delete PROJ-123 12345 --force
# List all projects
jira project list
# Show available boards
jira sprint boards
# Show active sprints
jira sprint active --board 123# Clone the repository
git clone https://github.com/pchuri/jira-cli.git
cd jira-cli
# Install dependencies
npm install
# Run locally
npm start -- --help
# Run tests
npm test
# Lint code
npm run lintjira-cli/
├── bin/
│ ├── index.js # Main CLI entry point
│ └── commands/ # Command implementations
│ ├── config.js # Configuration management
│ ├── issue.js # Issue operations
│ ├── project.js # Project operations
│ └── sprint.js # Sprint operations
├── lib/
│ ├── jira-client.js # JIRA API client
│ ├── config.js # Configuration management
│ ├── utils.js # Utility functions
│ └── analytics.js # Analytics and reporting
├── tests/
│ └── jira-client.test.js # Unit tests
├── docs/ # Documentation
├── examples/ # Usage examples
└── package.json
The CLI provides clear error messages for common issues:
- Authentication failures: Check your credentials with
jira config --show - Network errors: Verify your server URL and connection
- Permission errors: Ensure your account has the necessary permissions
- Invalid issue keys: Double-check the issue key format (PROJ-123)
-
"JIRA CLI is not configured"
- Run
jira config --server <url> --token <token>to set up your connection - Optionally add
--username <email>for Basic authentication - Or set environment variables (JIRA_HOST + JIRA_API_TOKEN required, JIRA_USERNAME optional)
- Run
-
"Authentication failed"
- Verify your username and API token with
jira config --show - Make sure you're using an API token, not your password
- Check if your token has expired
- Verify your username and API token with
-
"Network error"
- Check your server URL format:
https://yourcompany.atlassian.net - Ensure you can access JIRA from your network
- Try with
curlto test connectivity
- Check your server URL format:
-
"Resource not found"
- Verify the issue key or project key exists
- Check if you have permission to access the resource
- Use
jira searchto find the correct issue key
Set the DEBUG environment variable to get more detailed output:
DEBUG=jira-cli* jira issue --listOr disable analytics:
export JIRA_CLI_ANALYTICS=falseWe use Conventional Commits and Semantic Release for automated versioning and changelog generation.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes following our coding standards
- Write tests for new functionality
- Commit your changes using conventional commit format:
# Examples: git commit -m "feat: add issue filtering by labels" git commit -m "fix: resolve authentication timeout issue" git commit -m "docs: update installation instructions"
- Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
We follow the Conventional Commits specification:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Types: feat, fix, docs, style, refactor, perf, test, chore, ci
Examples:
feat(auth): add OAuth2 supportfix(cli): handle empty project names correctlydocs: update README with new examplestest: add unit tests for issue creation
- Push to
main: Triggers automated release based on commit types - Breaking changes: Use
feat!:orBREAKING CHANGE:in footer - Versioning: Automatically determined by semantic-release
- Changelog: Generated from conventional commits
- NPM publish: Automated via GitHub Actions
Read our full Contributing Guide for detailed guidelines.
This project is licensed under the ISC License - see the LICENSE file for details.
- Basic issue management (create, read, update, delete)
- Comment management (add, list, edit, delete)
- Project and sprint management
- Configuration management
- Non-interactive, automation-friendly CLI
- Analytics and reporting
- Export issues to markdown format
- Create/update issues from markdown files
- Issue templates
- Bulk operations
- Integration with other Atlassian tools
- Issue attachments management
- Workflows and transitions
- Custom fields support
- Time tracking
Your feedback helps make jira-cli better for everyone. Here's how you can share your thoughts:
- Check the Issues page
- Create a new bug report
- Create a feature request
- Join our Discussions to chat with the community
- Share your experience with a feedback issue
- Rate us on NPM
- Star the repo if you find it useful! ⭐
Check out our Contributing Guide - all contributions are welcome!
To help us understand how jira-cli is being used and improve it, we collect anonymous usage statistics. This includes:
- Command usage frequency (no personal data)
- Error patterns (to fix bugs faster)
- Feature adoption metrics
You can opt-out anytime by setting: export JIRA_CLI_ANALYTICS=false
Made with ❤️ for the JIRA community