The TUI¶
Alpha
The dashboard is in alpha: actively developed, keybindings and configuration may still change between releases, and rough edges are expected. The headless CLI commands remain the stable surface for scripts and agents. Bug reports are very welcome.
jira tui (or jira -i) opens a persistent, full-screen dashboard for
working a Jira queue without leaving the terminal: tabbed views over JQL
queries, an always-visible issue preview, single-key triage verbs with
optimistic updates, multi-select bulk actions, and a JQL search
workbench. It is built on Bubble Tea.
Everything below is configurable in config.toml under [tui] โ see
Configuration for the full key reference and a complete
example, and Configuration docs for where the file lives.
Layout¶
Issues (6) Team (12) Search Settings jira v1.4.0
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
[Mine] Sprint Updated Reported assignee = currentUser()โฆ
2 selected ยท t/a/c act on all
TYPE KEY SUMMARY STATUS ASSIGNEE AGE
โ ๐ JCT-12 Fix login redirect To Do Matt 2h
โ โญ JCT-31 Add SSO support In Prog Ann 5m
... โ preview
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
profile ยท project ยท board enter open t transition a assign โฆ
From top to bottom:
| Region | What it does |
|---|---|
| Tab bar | One tab per section, with live result counts. tab/shift+tab or a mouse click switches. The brand/version sits right-aligned |
| Header row | Per-section: the lens chips on Issues, the JQL box on Search, the query title on configured sections |
| Status line | Transient feedback: filter input, action toasts, errors, loading spinner, facet chip, selection count, pagination state |
| List | The issue rows. The leading marker column shows โ (selected), a green โ (new since last refresh) or a yellow โ (updated) |
| Preview | The selected issue's detail beside or below the list; scrolls independently |
| Footer | Active profile/project/board plus a live hint line of the current view's key bindings |
The TUI is fully mouse-aware: click a tab to switch, a lens chip to change query, a row to select it (click again to open it), the detail sub-tab pills to switch, and scroll whichever pane is under the pointer.
Tabs and sections¶
Three built-in sections ship: Issues (the triage home), Search (the JQL workbench) and Settings (resolved config, always last). You can add your own sections โ each one a saved JQL query with its own tab and result count:
[[tui.sections]]
title = "Team board"
jql = "project = JCT AND statusCategory != Done ORDER BY updated DESC"
[[tui.sections]]
title = "Needs review"
jql = "status = 'In Review' ORDER BY updated DESC"
tui.tabs controls which tabs show and their order; tui.default_tab
names the landing view:
The resolution rules:
- A name matches a built-in section ID first (
issues,search,settings), then a configured section's title (case-insensitive) โ so a query titled "Search" can never hijackdefault_tab = "search". - Configured sections always show; defining one is the opt-in and
deleting it is how you hide it. Naming one in
tabsonly positions it explicitly; the rest slot in after Issues. - Settings always rides last unless
tabsplaced it somewhere. default_tabis honored only when that tab is visible.
Lenses¶
Lenses are the quick-filter chips on the Issues tab โ one keypress flips
the whole queue to a different query. The built-ins are Mine (your
open work, the landing query), Updated (last 7 days) and
Reported. Cycle with ] / [ or click a chip; the active lens's
JQL shows faint beside the chips.
Replace them with your own:
[[tui.lenses]]
title = "Team"
jql = "project = JCT AND statusCategory != Done ORDER BY updated DESC"
[[tui.lenses]]
title = "Blocked"
jql = "status = Blocked ORDER BY updated DESC"
[tui]
default_lens = "Team"
- Configured lenses replace the built-in set; omit
[[tui.lenses]]entirely to keep the defaults. default_lensnames the landing lens by title (case-insensitive); absent or unmatched lands on the first lens.- Entries missing a
titleorjqlare skipped. - The lens set is also the saved-query list on the Search tab
(
ctrl+pand]cycling), so one config drives both.
Lenses vs sections
A section is a separate tab with its own result count โ use it
for a queue you glance at. A lens re-points the Issues tab โ use
it for queries you flip between while triaging. They share the same
title/jql shape.
Filtering the list¶
Three narrowing tools compose on every list view:
/โ text filter. Live fuzzy narrowing over key and summary;enterkeeps it,escclears it.fโ facets. A type-to-filter picker over the distinct statuses, assignees and labels in the loaded set (with counts, including an "Unassigned" bucket). Pick one to narrow to it; reopen and pick theโ clearentry to drop it. The active facet shows as a chip in the status line and composes with the text filter.- Change markers. A background refresh marks rows it added (green
โ) or changed (yellowโ). Navigating onto a row clears its marker โ deliberate viewing, not refresh churn, is what counts.
Reading an issue¶
The preview pane always shows the selected row. enter opens the full
detail view: description and comments rendered as themed markdown, with
Overview and Comments sub-tabs (tab/shift+tab or click the
pills). It scrolls with โ/โ/the wheel, o opens the issue in the
browser, and esc/enter returns to the list. Issue keys render as
terminal hyperlinks where supported.
Recent issues โ the jumplist¶
ctrl+o opens a picker over every issue you've opened this session,
most recent first, across all tabs. Type to filter, enter to jump:
issues still in the current list select-and-open in place; anything else
opens directly by key. Capped at the 50 most recent.
Acting on issues¶
Single-key verbs drive the triage loop. Where the change is visible in the row (status, summary, assignee) it applies optimistically โ the row updates immediately, the write reconciles in the background, and a failure rolls the row back with an error toast.
| Key | Action | Notes |
|---|---|---|
t |
Transition | Type-to-filter picker over the workflow transitions Jira allows for this issue |
a |
Assign | Type a name or email โ resolved against Jira; none/unassigned (or empty) clears |
A |
Assign to me | One keypress, no prompt |
c |
Comment | Opens $JIRA_EDITOR/$EDITOR when set; otherwise an in-modal textarea (ctrl+s submits, enter is a newline). Markdown converts to ADF |
e |
Edit summary | Prefilled with the current summary |
w |
Log work | Accepts 2h, 30m, 1d etc. (workday_seconds scales d) |
o |
Open in browser | |
y / Y |
Copy issue key / URL | Via OSC 52, so it works over SSH |
Modal prompts share one input substrate: real cursor movement, word-wise
editing and bracketed paste everywhere. esc always cancels.
Bulk actions¶
Select multiple issues and the verbs escalate to the whole selection:
| Key | Selection |
|---|---|
space |
Toggle the current row (and set the range anchor) |
x |
Select from the anchor through the cursor |
X |
Invert the visible selection |
ctrl+a |
Select all visible rows โ or clear them all when everything is already selected |
Selections survive filter changes (mark, narrow, mark more, act on the union) and a refresh prunes marks for issues that left the result set.
With a selection active, t, a and c become bulk transition,
bulk assign and bulk comment. Every bulk write first shows a
confirmation that restates the verb, the count and the target keys โ
โ defaulting to No; any key other than y cancels and keeps the
selection. The batch then runs through a bounded worker pool, and
per-issue failures are reported by key instead of aborting the rest:
Bulk transition picks from the first selected issue's transitions and applies by name, resolving each issue's own transition id at apply time โ an issue whose workflow doesn't offer that name fails individually. Bulk assign resolves the user query once before any write.
The Search tab¶
A free-form JQL workbench. enter (or 2, or a click on the box)
starts editing; enter validates the query through Jira's parser โ
syntax errors surface inline instead of as a failed search โ and runs
it. Results get the full shared toolkit: filter, facets, verbs, bulk
mode, preview.
- Autocomplete. The editor completes the token you're typing,
context-aware, from your Jira instance's own JQL metadata (the same
API behind the web UI's query bar): field names โ including custom
fields โ at a field position, that field's operators after it, and
its live values after the operator (after
status =your actual statuses ghost in; a multi-word value likeIn Progresscompletes quoted when nothing โ or an opening quote โ has been typed yet, and afterin/not invalues complete parenthesised). JQL functions andAND/OR/ORDER BYcomplete in their places, and your saved queries complete as whole lines at the start. Everyday names (project,assignee,currentUser(), โฆ) rank ahead of plugin custom fields, and an empty editor offers only the saved queries โ token suggestions start once you type. The completion shows faint as you type;tabaccepts it. Offline or before the metadata loads, it falls back to the saved queries and common openings. - Presets.
ctrl+popens a type-to-filter dropdown over the saved queries โ matching on the name or the JQL text โ andentercommits and runs the pick.]/[cycle through them directly. - Scroll to the bottom of a large result set and the next page fetches automatically.
The preview pane¶
| Key | Action |
|---|---|
p |
Cycle the dock: right โ left โ bottom โ hidden |
+ / - |
Grow / shrink the preview's share of the split (5% steps) |
z |
Zoom the list to the full body (toggle; the split is restored on the next press) |
ctrl+u / ctrl+d |
Scroll the preview while it's visible |
Configure the resting state:
[tui]
preview = "right" # right | left | bottom | hidden | auto
preview_size = 40 # percent of the split, 20โ80
auto puts it right on wide terminals and bottom on narrow ones, and
side docks hide automatically when the window is too narrow for a
usable split.
Refresh¶
Every section refetches on a shared interval (tui.refresh_interval
seconds, default 60; 0 disables). r refreshes the current view now;
R pauses/resumes the automatic cycle. Regaining terminal focus also
triggers a refresh, so the dashboard is current when you switch back to
it. Background reloads never interrupt: a refresh is skipped while
you're typing in a filter or modal, and a refetch re-finds your selected
issue by key even if the ordering changed.
Keybindings¶
Every binding is rebindable under [tui.keys]: the value is a list of
keys, the first one becomes the help label, and removing an entry
restores the default. Unknown action names surface as a footer error
rather than breaking the dashboard.
| Action name | Default | Action name | Default |
|---|---|---|---|
up / down |
โ/k, โ/j |
transition |
t |
top / bottom |
g/home, G/end |
comment |
c |
page_up / page_down |
ctrl+u, ctrl+d |
assign |
a |
next_section / prev_section |
tab, shift+tab |
assign_me |
A |
open |
enter |
worklog |
w |
back |
esc |
edit |
e |
refresh |
r |
open_browse |
o |
toggle_pause |
R |
copy_key / copy_url |
y, Y |
filter |
/ |
select |
space |
facet |
f |
select_all |
ctrl+a |
jumplist |
ctrl+o |
select_invert |
X |
search |
2 |
select_range |
x |
presets |
ctrl+p |
toggle_preview |
p |
next_lens / prev_lens |
], [ |
grow_preview / shrink_preview |
+/=, - |
help |
? |
zoom |
z |
quit |
q, ctrl+c |
? opens a help sheet with the current bindings, grouped by purpose โ
the authoritative in-app reference after any rebinding.
Settings and hot-reload¶
The Settings tab shows the resolved configuration and the file it
came from. The TUI checks that file's mtime on the refresh heartbeat
and hot-applies edits to [tui] keys โ lenses, sections, tabs,
keybindings, preview, refresh interval โ without restarting. A reload
that changes a lens's JQL also refetches, so the rows always match the
header. Press r on the Settings tab to reload immediately (the only
path when auto-refresh is disabled).
Theme ([theme]) and credentials changes still need a restart.
Theming¶
The dashboard follows [theme] from your config (see
Configuration) โ including the markdown rendering in
the detail view, which derives its glamour style from the same palette
so issue bodies match the chrome. ANSI palette themes render with your
terminal's own colours.
Configuration¶
All keys live under [tui]:
| Key | Purpose | Default |
|---|---|---|
refresh_interval |
Auto-refresh cadence in seconds; 0 disables |
60 |
tabs |
Which tabs show, in order (built-in IDs or section titles) | built-ins |
default_tab |
The landing tab (must also be visible) | issues |
sections |
[[tui.sections]] โ your own JQL tabs (title + jql) |
none |
lenses |
[[tui.lenses]] โ replace the Issues quick-filters (title + jql) |
built-ins |
default_lens |
Landing lens by title, case-insensitive | first lens |
preview |
Preview dock: right, left, bottom, hidden, auto |
auto |
preview_size |
Preview share of the split, percent (20โ80) | 50 |
keys |
[tui.keys] โ rebind any action by name |
defaults above |
A complete example:
[tui]
refresh_interval = 30
default_tab = "issues"
default_lens = "Team"
preview = "right"
preview_size = 40
[[tui.lenses]]
title = "Team"
jql = "project = JCT AND statusCategory != Done ORDER BY updated DESC"
[[tui.lenses]]
title = "Blocked"
jql = "status = Blocked ORDER BY updated DESC"
[[tui.sections]]
title = "Needs review"
jql = "status = 'In Review' ORDER BY updated DESC"
[tui.keys]
transition = ["T"]
quit = ["q", "ctrl+c"]
See also¶
- Configuration: where
config.tomllives, profiles, themes. - JQL: the query language behind lenses, sections and search.
search saved: the CLI-side saved queries (.jqlfiles) โ separate from TUI lenses today.- Worklog: the duration formats
waccepts.