Skip to content

Repository files navigation

jira-tui

A lazygit-style, panel-based terminal UI for browsing and managing Jira issues: issue list, multi-tab detail panel (overview / comments / worklog / history / transitions), commenting, worklogs, status transitions, assignment, description editing, and more — all from the keyboard.

jira-tui lang

Highlights

  • Keyboard-first, lazygit feel — panel layout, single-key actions, ? for an always-available help overlay.
  • Multiple list views — u/Tab cycles assigned-to-me issues, a custom JQL view (default: Test/UAT), and permanently hidden issues.
  • Open any issue into the list — o opens a known key (or pasted text with many keys) and pins them into Issues; Shift-o bulk-adds from the clipboard; Shift-d removes; Shift-h hides everything currently visible.
  • Local filter + server search — / narrows the on-screen list instantly (no network); s runs full-text search across Jira.
  • External editor — e edits the description in your configured editor (code --wait by default; nvim, Cursor, vim, … via config.editor / $EDITOR); save & close writes back to Jira when changed.
  • Attachments — download and open images/files; preload with Shift-i while on VPN, view offline later with i.
  • Offline cache — when the network/VPN is down, the last successful responses are shown from disk; each view/search keeps its own cache.
  • Clipboard & browser — copy the issue key (y) or description (d); open in the browser with w.

How it works

Application logic is written in Fennel (a Lisp that compiles to Lua). It runs on Fengari (a Lua VM in JavaScript) with fengari-interop bridging to real Node.js APIs (fs, child_process, fetch, …). The terminal UI uses blessed. Because npm has no official Fennel compiler package, the compiler itself (vendor/fennel.lua) is vendored; bin/jira-tui.js bootstraps by reading, compiling, and running the .fnl sources.

src/
  main.fnl     UI state, keybindings, panel/event wiring
  config.fnl   Loads ~/.config/jira-tui/config.json (keys, tabs, views)
  jira.fnl     Jira REST v2 client (search, issue, comment, worklog, transition,
               attachment download) + offline cache
  render.fnl   Pure functions: Jira JSON → (colored) panel text
  jsutil.fnl   Lua ↔ JS data conversion helpers
  format.fnl   String/date formatting helpers
  keymap.fnl   Keybinding help text (from config)

Install

Requirements: Node.js; a terminal/GUI editor for e (default code --wait; see editor in config); open / pbcopy on macOS for browser and clipboard shortcuts.

npm install jira-tui -g
yarn global add jira-tui

Credentials

The app looks for a .env in this order and uses the first it finds:

  1. .env in the current working directory
  2. ~/.config/jira-tui/.env (recommended for a global install)

See .env.example for a ready-to-copy template:

JIRA_BASE_URL=https://jira.example.com
JIRA_AUTH_MODE=bearer        # "bearer" (PAT) or "basic" (user/password)
JIRA_PAT=...
JIRA_USERNAME=...
JIRA_PASSWORD=...

.env holds secrets — it is in .gitignore; never commit it.

Run

jira-tui          # after global install, from any directory

Keybindings

Defaults are listed below. Remap them (and detail tabs / list views) in ~/.config/jira-tui/config.json — see Configuration. Press ? in the app for the live list (reflects your config).

Key Action
j/k Navigate the focused panel (list or detail scroll) — current detail tab is kept while moving in the list
Shift-Tab Toggle focus List ↔ Detail
[ / ], ←/→ Previous/next detail tab
1–5 Jump to a detail tab
c Add a comment (multiline: C-s submit; then optional clipboard image with y)
w Open issue in the default browser
Shift-w Log work (time + optional multiline comment)
t Transitions tab — j/k to pick, Enter to apply (optional multiline comment + assignee)
a Assign (empty = unassign; optional multiline comment)
Shift-a Assign to yourself
e Edit description in external editor — save & close writes to Jira if changed
h Hide selected issue (unhide in Hidden view) — stored in ~/.config/jira-tui/hidden.json
Shift-h Hide all currently visible issues (unhide all when in Hidden view)
y Copy issue key (e.g. PROJ-123) to clipboard
d Copy description to clipboard
Shift-d Remove selected issue from the list (unpins if added via o)
i Open attachments — prompts for a number if there are several; works offline if pre-downloaded with Shift-i
Shift-i Download attachments only (do not open)
l Open a link from description/comments — prompts for a number if there are several
u, Tab Cycle Issues ↔ custom view ↔ Hidden (see Configuration)
Shift-v Jump to Hidden (press again to return to Issues)
o Open a known issue key or browse URL. Empty Enter = read clipboard. If the input (or clipboard) has many PROJECT-N keys, all are pinned
Shift-o Bulk-add from clipboard (pbpaste) — copy the list first, then press Shift-o (do not paste into the terminal; multi-line paste breaks textbox input)
s Full-text search on the server
/ Locally filter the on-screen list by key/title/status (empty clears)
r Refresh list and selected issue
? Toggle help
q Close help/prompt if open; otherwise quit
Ctrl-c Quit immediately

Default JQL: assignee = currentUser() ORDER BY updated DESC.

Issues opened with o are OR'd into that query (key in (...)) so they stay in the Issues list across refresh and restart until you remove them with Shift-d.

Configuration

Optional file: ~/.config/jira-tui/config.json. Copy config.example.json and edit what you need; omitted fields keep the built-in defaults. Restart the app after changes.

mkdir -p ~/.config/jira-tui
cp config.example.json ~/.config/jira-tui/config.json
Field Purpose
editor Command used by e to edit the description. String ("code --wait", "nvim") or array (["code", "--wait"]). Falls back to $EDITOR, then code --wait. GUI editors need a wait flag so the TUI resumes after you close the file.
keys Remap actions to blessed key names ("c", "S-w", "C-c", "tab", …). Each value is a string or array of keys.
tabs Detail-tab order (subset/reorder of overview, comments, worklog, history, transitions). Jump keys still target fixed tab ids.
tabLabels Display labels for detail tabs.
views List-tab labels and JQL for mine / uat (and label for hidden).

Example — nvim as editor, custom Test/UAT JQL, and comment key:

{
  "editor": "nvim",
  "keys": { "comment": ["C"] },
  "views": {
    "uat": {
      "label": "QA",
      "jql": "status in (QA, Test) ORDER BY updated DESC"
    }
  }
}

Other editor examples (string or array — both work; use an array if the binary path has spaces):

  • "code --wait" / ["code", "--wait"] (package default)
  • "cursor --wait" / ["cursor", "--wait"]
  • "nvim", "vim"

Prompt for AI agents

Ready-to-paste brief for coding agents: AGENTS.md.

In Cursor / similar tools you can also @AGENTS.md so the agent picks up local paths (hidden.json, attachments/, …), list views, and keybindings without guessing.

Offline cache

Successful search/issue/transitions responses are written under ~/.config/jira-tui/cache/. When Jira is unreachable at the network level (VPN off, DNS failure, etc. — not HTTP 401/404), the app serves the last cached data and shows (offline - from cache) in the status bar. Writes (comment / worklog / transition) still need the live server. Downloaded attachments live under ~/.config/jira-tui/attachments/.

Known limits

  • Comment/worklog lists are limited to the first page of the issue GET response.
  • Description is shown as Jira wiki markup (REST v2 / Data Center) with no rich rendering layer yet.
  • Only Jira Server/Data Center REST v2 (bearer/basic auth) is supported; Jira Cloud (OAuth, different endpoints) is not.

License

MIT Licence

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages