Jira without leaving your terminal.

Select issues. Track work. Generate branches. Stay in flow.

go install github.com/tutunak/jcli@latest

Why jcli exists

Every browser tab is a broken promise.
Open Jira. Find the ticket. Copy the key.
Switch back. Remember what you were doing.

jcli in action

terminal
$ jcli issue select
? Select an issue
> PROJ-123: Implement user authentication
  PROJ-124: Fix login redirect bug
  PROJ-125: Add password reset flow
✓ Selected PROJ-123

$ git checkout -b $(jcli issue branch)
Switched to a new branch 'PROJ-123-implement-user-authentication-847291'

$ jcli issue current
PROJ-123: Implement user authentication

What jcli does

SELECT

Interactive issue selection from your assigned tasks

jcli issue select

TRACK

Current issue tracking persists across sessions

jcli issue current

BRANCH

Smart branch names from issue key and summary

jcli issue branch

Get Started

# Install jcli
go install github.com/tutunak/jcli@latest

# Configure your Jira credentials
jcli config credentials

# Set your default project
jcli config project MYPROJ

Daily Workflow

  1. Start your day by selecting an issue

    jcli issue select
  2. Create a branch for your work

    git checkout -b $(jcli issue branch)
  3. Check your current issue anytime

    jcli issue current

Shell Aliases

Drop this in your ~/.bashrc or ~/.zshrc to branch off the issue you selected, in one word. These are functions rather than aliases on purpose: with no issue selected, jcli issue branch prints its hint on stdout, so a plain alias gcj='git checkout -b $(jcli issue branch)' hands that text straight to git and fails with a confusing error.

# Branch off the issue currently selected in jcli.
gcj() {
  local branch
  branch=$(jcli issue branch) || {
    printf '%s\n' "$branch" >&2
    return 1
  }
  git checkout -b "$branch"
}

# Go back to the branch you already made for the current issue,
# creating one only if it does not exist yet.
gsj() {
  local line key existing
  line=$(jcli issue current | head -n 1)
  case $line in
    "Current issue: "*) key=${line#Current issue: } ;;
    *) printf '%s\n' "$line" >&2; return 1 ;;
  esac
  existing=$(git branch --list "${key}-*" \
    --format='%(refname:short)' | head -n 1)
  if [ -n "$existing" ]; then
    git checkout "$existing"
  else
    gcj
  fi
}

# Shorthands for the two commands you type most.
alias jis='jcli issue select'
alias jic='jcli issue current'

Reload with source ~/.zshrc, then jis to pick an issue and gcj to branch. jcli issue branch appends a fresh random suffix on every call, so gcj always makes a new branch — gsj is the one that returns you to an existing one.

Command Reference

All jcli commands and what they do
CommandDescription
jcli issue selectInteractive selection from your assigned “In Progress” issues
jcli issue select <KEY>Select a specific issue by key, e.g. PROJ-123
jcli issue currentShow the currently selected issue
jcli issue branchGenerate a branch name for the current issue
jcli config credentialsSet Jira URL, email and API token interactively
jcli config project <KEY>Set the default project key
jcli config status <NAME>Set the default status filter
jcli versionPrint version information
jcli helpShow the help message

Configuration lives in ~/.config/jcli/config.yaml and the selected issue in ~/.local/state/jcli/state.json. The JIRA_API_TOKEN environment variable overrides the stored token. Full documentation is in the README on GitHub.