Files
terdut-tui/CLAUDE.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

4.0 KiB

terdut-tui

TUI client for terdut-server, a Prometheus Alertmanager receiver and incident manager. Requires server v0.4.0+.

Domain model

The server splits alerts from incidents, and this client mirrors it:

  • Alert — Alertmanager's record. Firing or resolved, read-only, no workflow state.
  • Incident — the work item: triggered → acknowledged → resolved, with an assignee, snooze, notes and an append-only timeline. Many alerts to one incident, correlated by Alertmanager's groupKey.

All user actions target incidents. Two server behaviours the UI has to respect: manual resolve is terminal (hence the confirmation prompt), and snooze is the non-destructive "not now" alternative.

Tech stack

  • Go 1.25+
  • Bubbletea — TUI framework (strict Elm architecture)
  • Lipgloss — styles (all in internal/tui/styles.go, never inline)
  • Bubbles — table, textinput, help components

Project layout

main.go                      CLI entry point: flags, config load, health check, start TUI
internal/api/client.go       REST API client — one method per endpoint
internal/config/config.go    Config loader (~/.config/terdut-tui/config.yaml)
internal/tui/                Bubbletea UI
  model.go                   Model struct, mode/section constants, Init(), tea.Cmd constructors
  update.go                  Update() — dispatch only, no API calls inline
  view.go                    View() — pure rendering
  keys.go                    keyMap (bubbles/key pattern)
  styles.go                  All lipgloss styles
internal/updater/updater.go  Self-update via GitHub Releases

Architecture rules

  1. Never call API inside Update() — return tea.Cmd instead; the runtime runs it async.
  2. View() is pure — no side effects, no state mutations.
  3. All state in Model — no globals.
  4. All styles in styles.go — never use lipgloss inline in view.go.

Config

Location: ~/.config/terdut-tui/config.yaml

server_url: https://terdut.example.com
api_key: <64-char hex key>
refresh_interval: 30  # seconds, optional, default 30

The API key is a one-time secret generated by terdut-server (POST /api/users/{id}/api-keys).

Running

go run .
go run . --version
go run . --self-update

Building

go build -ldflags="-X main.version=v0.1.0" -o terdut-tui .

Sections

Incidents (the queue, and the default) · Alerts (raw read-only feed) · Stats (MTTA/MTTR and alert frequency charts) · Archived (archived incidents) · Schedule · Users

Development stages

Stage Feature
1 Scaffold, config, health check, placeholder TUI
2 Alert dashboard with auto-refresh and stats
3 Alert detail: acknowledge, comment, statistics charts
4 On-call schedule calendar view
5 User management and API key lifecycle
6 Incidents: queue, timeline, ack/assign/snooze/resolve, MTTA/MTTR

Memory (GrayMatter)

This project has persistent agent memory via the graymatter MCP tools:

  • memory_search (agent_id, query) — call at the start of a task when prior context might matter.
  • memory_add (agent_id, text) — call whenever you learn something durable: user preferences, decisions, conventions, gotchas.
  • memory_reflect (action, agent, text/target) — update or forget stale facts. ⚠ takes agent, not agent_id.
  • checkpoint_save / checkpoint_resume (agent_id) — snapshot/restore session state before major refactors or across restarts.

Use a stable agent_id of the form <project>-<role> (e.g. myapp-backend). Store conclusions, not conversation logs. Err on the side of remembering.