cac-jira

Jira CLI

A command-line interface for interacting with Jira.

This project uses UV for dependency management.

Installation

pip install cac-jira

Authentication

cac-jira supports two authentication methods: Basic Auth (default) and Personal Access Tokens (PAT).

Basic Auth (default)

On first-run, you’ll be prompted for a Jira API token; generate one here. This will be stored in your system credential store (e.g. Keychain on Mac OS) in an item called cac-jira.

Personal Access Token (PAT)

Some Jira Server/Data Center instances have disabled HTTP Basic Authentication; these require Personal Access Tokens, which use Bearer token authentication.

Note: PAT authentication is only supported on Jira Server/Data Center. Jira Cloud does not support PATs — use Basic Auth with an API token instead.

To use PAT authentication, set auth_method: pat in your config file. On the next run you’ll be prompted for your PAT, which is stored in your system credential store. username is optional when using PAT authentication.

server: https://your-jira-instance.example.com
project: YOUR_PROJECT_KEY
auth_method: pat

Configuration

On first-run, you’ll be prompted for your server, username (basic auth only), and default project, and a configuration file will be generated at ~/.config/cac_jira/config.yaml.

server: https://your-jira-instance.atlassian.net
project: YOUR_PROJECT_KEY  # Optional default project
username: your.email@example.com
auth_method: basic  # or 'pat' for Personal Access Token

Usage

The Jira CLI follows a command-action pattern for all operations:

jira <command> <action> [options]

Global Options

Commands exit 0 on success and non-zero on failure (invalid input, a not-found issue/project, or a Jira API error), so they compose safely in scripts. --help and argument parsing work offline and do not require credentials — the Jira connection is only established when a command runs.

Examples

Issue Commands

List issues in a project:

jira issue list --project PROJ

List only issues assigned to you (and optionally include completed ones):

jira issue list --project PROJ --mine
jira issue list --project PROJ --done   # include issues that are resolved

Create a new issue:

jira issue create --project PROJ --type Task --title "Fix login bug" --description "Users can't log in"

Create a new issue of a type that requires custom fields:

#
# This assumes the name of the custom fields is "Custom Field One" and "Custom Field Two";
# the field name will be swapped to lower-case, and spaces replaced with underscores
#
jira issue create --project PROJ --type Custom\ Issue\ Type --title "Issue Title" --description "Issue description" \
  --field custom_field_one custom_field_value \
  --field custom_field_two custom_field_value

Create and assign to yourself:

jira issue create --project PROJ --type Bug --title "Server crash" --assign

Create and immediately start work:

jira issue create --project PROJ --type Story --title "Add login feature" --begin

Add an issue to an epic:

jira issue create --project PROJ --type Task --title "Subtask" --epic PROJ-100

Label an issue:

jira issue label --issue ISSUE_KEY --labels label1,label2

Transition an issue:

jira issue begin --issue ISSUE_KEY    # Start work
jira issue block --issue ISSUE_KEY    # Mark as blocked
jira issue close --issue ISSUE_KEY    # Mark as complete

Delete an issue (prompts for confirmation; pass --force to skip it, e.g. in scripts):

jira issue delete --issue ISSUE_KEY
jira issue delete --issue ISSUE_KEY --force

Project Commands

List all projects:

jira project list

Filter projects by name or key (case-insensitive, partial match):

jira project list --name "Core"
jira project list --key COR

Show a single project by its key:

jira project show PROJ

Advanced Examples

Update an issue’s title or description:

jira issue update --issue ISSUE_KEY --title "New issue title" --description "new issue description"

Add a comment to an issue:

jira issue comment --issue ISSUE_KEY --comment "This is a comment."

List all issue IDs matching a label:

jira issue list --output json | jq -r '.[] | select(.Labels | contains("production")) | .ID'

Shell Completion

jira supports tab-completion of commands, actions, and options via argcomplete.

Enabling completion

The recommended approach is per-command registration. Add the appropriate line to your shell startup file:

# bash (~/.bashrc) or zsh (~/.zshrc)
eval "$(register-python-argcomplete jira)"

Then restart your shell (or source the file). Tab-completion works immediately:

jira <TAB>                 # -> issue  project
jira issue <TAB>           # -> assign attach begin ... show update
jira issue show --<TAB>    # -> --issue --output --project --verbose
Alternative: global activation To enable argcomplete for every marker-tagged program at once (instead of per-command), run this once and restart your shell: ```bash activate-global-python-argcomplete ```

Development

Setup Development Environment

# Install dependencies including dev dependencies
uv sync

# Activate the venv
source .venv/bin/activate

# Run tests
uv run pytest

Project Structure

Command discovery, argument parsing, shell completion, and dispatch are all provided by the shared runner in cac-core (cac_core.cli.run / make_main); this project only supplies the commands/ tree and its Jira client.

Adding New Commands

  1. Create a new action module in the appropriate command directory.
  2. Define a class that inherits from the command’s base class, following the {Command}{Action} naming convention (e.g. commands/issue/create.pyIssueCreate).
  3. Implement define_arguments() and execute() methods.

execute() contains the command’s logic and returns an exit code (0/None for success, non-zero for validation failures). It does not need to wrap Jira calls in try/except: the shared run() template (from cac-core) catches errors and maps them to a non-zero exit code, and JiraCommand.handle_exception renders JIRAErrors using their human-readable Jira message.