# terdut-tui A terminal user interface for [terdut-server](https://git.ryuvia.com/niklas/terdut-server). Communicates with the server over its REST API. Written in Go using [Bubbletea](https://github.com/charmbracelet/bubbletea). ## Features - **Incident queue** — open incidents with severity, status, assignee and age, auto-refreshing - **Incident actions** — acknowledge, assign, snooze, note, resolve and archive - **Timeline** — the full history of an incident, system events, pages and notes together - **Alert feed** — the raw read-only alerts underneath, each linked to its incident - **On-call schedule** — visual calendar of who is on duty, assign and remove entries - **Statistics** — MTTA and MTTR, plus alert frequency by name, hour and day - **User management** — add and remove users, manage API keys, set each user's ntfy topic > Requires terdut-server **v0.4.0 or later**. Earlier servers have no incidents API; > use terdut-tui v0.3.x with those. ## Alerts and incidents The server keeps two objects and this client follows that split: - An **alert** is Alertmanager's record — firing or resolved, and read-only here. - An **incident** is the work item. It is what you acknowledge, assign, snooze, discuss and resolve, and it is where all the actions live. Incidents are correlated by the `groupKey` Alertmanager already computed from your `group_by` configuration, so several alerts commonly share one incident. Two behaviours worth knowing before you press a key: - **Resolving is final.** The server treats a manual resolve as terminal: a later occurrence opens a *new* incident rather than reopening this one, and if the alert underneath never stops firing the incident stays closed. The TUI asks for confirmation before doing it. - **Snooze is the "not now" button.** It hides an incident from the default queue without closing it, and expires on its own. ## Push notifications When the server is configured for ntfy, an incident that opens pages whoever is on call. Each user has their own topic, shown as a column in the Users section and edited with `t`. A user with no topic falls back to the server's shared fallback topic, which carries **no Acknowledge button** — the topic is shared, so a button on it would let any subscriber acknowledge as somebody else. Every delivery lands on the incident's timeline: `Notified (triggered)` when ntfy accepted the page, and `Notification to failed` when it ran out of retries. That second one is the one to look for when nobody's phone rang. Editing topics needs terdut-server **v0.6.0 or later**; the timeline entries need **v0.7.0 or later**. Against an older server the topic column stays empty and editing one reports the server's 404. ## Installation Download the latest release binary for your platform from the [releases page](https://git.ryuvia.com/niklas/terdut-tui/releases), or build from source: ```bash go install git.ryuvia.com/niklas/terdut-tui@latest ``` ## Configuration Create `~/.config/terdut-tui/config.yaml`: ```yaml server_url: https://terdut.example.com api_key: refresh_interval: 30 # seconds, optional theme: gruvbox-dark # optional, this is the default ``` The API key is generated in terdut-server. See the server documentation for how to bootstrap a user and issue an API key. ## Themes Two themes ship with the client: `gruvbox-dark` (the default) and `gruvbox-light`. Both colour foregrounds only — the terminal supplies the background — so pick the one that matches the background you already run. To make your own, drop a file in `~/.config/terdut-tui/themes/` and name it in `theme:`. `extends` inherits a built-in, so a file only has to list what it changes: ```yaml # ~/.config/terdut-tui/themes/mine.yaml extends: gruvbox-dark primary: "#d3869b" accent: "#fabd2f" ``` A file may shadow a built-in name — `themes/gruvbox-dark.yaml` is how you tweak the default without renaming it. Without `extends`, every token must be set. The twelve are: | Token | Where it shows | |---|---| | `primary` | header, active tab, selected row, cursors | | `on_primary` | text drawn *on* `primary` — the active tab and selected row | | `text` | incident titles and other emphasis | | `muted` | secondary text, dividers, footer, table headers | | `accent` | status line, acknowledged incidents, the by-day chart | | `firing` | firing alerts, triggered incidents, the by-hour chart | | `resolved` | resolved alerts and incidents, the top-alerts chart | | `error` | error banners | | `sev_critical`, `sev_error`, `sev_warning`, `sev_info` | the `severity` label | Values are hex (`#83a598` or `#abc`) or an ANSI palette index (`0`–`255`) if you would rather follow your terminal's own colours. Colours are downsampled automatically on 256- and 16-colour terminals, and `NO_COLOR` is honoured. ## Usage ``` terdut-tui start the TUI terdut-tui --version print version terdut-tui --self-update update to the latest release ``` ### Keybindings Global: | Key | Action | |-----|--------| | `j` / `↓` | Move down | | `k` / `↑` | Move up | | `tab` / `shift+tab` | Next / previous section | | `enter` | Open detail | | `esc` | Go back | | `r` | Refresh | | `f` | Cycle filter | | `q` | Quit | The sections, in `tab` order: Incidents · Alerts · Stats · Archived · Schedule · Users. Incidents section: | Key | Action | |-----|--------| | `f` | Cycle: open → triggered → acknowledged → resolved → snoozed | | `x` | Archive (resolved incidents only) | Incident detail: | Key | Action | |-----|--------| | `a` / `A` | Acknowledge / clear acknowledgement | | `R` | Resolve — asks to confirm, and is final | | `s` | Assign to a user | | `z` / `Z` | Snooze for a duration / un-snooze | | `c` | Add a note | | `[` / `]` | Select a note | | `d` | Delete the selected note (your own only) | | `x` | Archive / un-archive | Alerts section (read-only): | Key | Action | |-----|--------| | `f` | Cycle: firing → resolved → all → archived | | `i` | In detail: jump to the alert's incident | Stats section: | Key | Action | |-----|--------| | `j` / `k`, `pgup` / `pgdn` | Scroll | Schedule section: | Key | Action | |-----|--------| | `+` / `W` | Assign a day / a whole week | | `d` | Remove the assignment | | `←` / `→` | Shift the week window | One person holds a given day. Assigning over days somebody else already has asks first — naming them and how many days are being taken — and moves the whole selection at once when you accept, so reassigning a week is one confirmation rather than seven deletions. Taking somebody's shift needs terdut-server **v0.8.0 or later**; against an older server the assignment is refused with `date already assigned`. Users section: | Key | Action | |-----|--------| | `n` | Create a user | | `t` | Edit the user's ntfy topic — submit empty to clear it | | `d` | Delete a user | | `k` | API keys for the selected user |