Files
terdut-tui/README.md
T
Niklas Ye 6fdb4bbbf8
CI / test (push) Successful in 13s
Release / test (push) Successful in 14s
Release / binaries (push) Successful in 1m37s
Move to Gitea: git.ryuvia.com/niklas/terdut-tui
The module path, the CI pipeline and the self-updater all named GitHub. They now
name the Gitea instance everything else already runs on.

The workflows are rewritten rather than translated, for the reason recorded in
ci.yaml: Gitea's runner image is ubuntu:22.04, whose nodejs is Node 12, so no JS
action runs there -- actions/checkout@v4 dies with a SyntaxError before doing
anything. Every step is shell and checkout is a plain clone, which this public
repo needs no credential for. upload-artifact/download-artifact are JS actions
too, and there is no artifact store here, so the job that builds the binaries is
the job that publishes them.

internal/updater keeps its release and asset types unchanged: Gitea's release
payload carries the same tag_name, and its attachments the same name and
browser_download_url, so only the URL, the Accept header and one error string
move. The asset naming in release.yaml is load-bearing for that matching.

This does strand already-installed binaries, which still poll api.github.com.
The GitHub repository is left in place and untouched, so they report themselves
up to date rather than erroring; its last release is the bridge, and crossing it
is a one-time manual download.
2026-08-19 20:41:05 +02:00

157 lines
5.3 KiB
Markdown

# 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 <user> (triggered)`
when ntfy accepted the page, and `Notification to <user> 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: <your-api-key>
refresh_interval: 30 # seconds, optional
```
The API key is generated in terdut-server. See the server documentation for how to bootstrap a user and issue an API key.
## 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 |