RepoPilotOpen in app →

gizak/termui

Golang terminal dashboard

Mixed

Slowing — last commit 10mo ago

worst of 4 axes
Use as dependencyMixed

no tests detected; no CI workflows detected

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isMixed

last commit was 10mo ago; no CI workflows detected

  • Last commit 10mo ago
  • 10 active contributors
  • MIT licensed
Show 4 more →
  • Slowing — last commit 10mo ago
  • Concentrated ownership — top contributor handles 74% of recent commits
  • No CI workflows detected
  • No test directory detected
What would change the summary?
  • Use as dependency MixedHealthy if: add a test suite
  • Deploy as-is MixedHealthy if: 1 commit in the last 180 days

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/gizak/termui?axis=fork)](https://repopilot.app/r/gizak/termui)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/gizak/termui on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: gizak/termui

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/gizak/termui shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Slowing — last commit 10mo ago

  • Last commit 10mo ago
  • 10 active contributors
  • MIT licensed
  • ⚠ Slowing — last commit 10mo ago
  • ⚠ Concentrated ownership — top contributor handles 74% of recent commits
  • ⚠ No CI workflows detected
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live gizak/termui repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/gizak/termui.

What it runs against: a local clone of gizak/termui — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in gizak/termui | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 333 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>gizak/termui</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of gizak/termui. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/gizak/termui.git
#   cd termui
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of gizak/termui and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "gizak/termui(\\.git)?\\b" \\
  && ok "origin remote is gizak/termui" \\
  || miss "origin remote is not gizak/termui (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "backend.go" \\
  && ok "backend.go" \\
  || miss "missing critical file: backend.go"
test -f "buffer.go" \\
  && ok "buffer.go" \\
  || miss "missing critical file: buffer.go"
test -f "grid.go" \\
  && ok "grid.go" \\
  || miss "missing critical file: grid.go"
test -f "block.go" \\
  && ok "block.go" \\
  || miss "missing critical file: block.go"
test -f "render.go" \\
  && ok "render.go" \\
  || miss "missing critical file: render.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 333 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~303d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/gizak/termui"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

termui is a cross-platform terminal UI library written in Go that provides pre-built widgets (charts, gauges, tables, paragraphs, trees) and a grid-based layout system for building interactive terminal dashboards. It wraps termbox-go to handle low-level terminal rendering, events (keyboard, mouse, resize), and styling across Linux, macOS, and Windows. Monolithic package structure: core rendering in backend.go, buffer.go, render.go; base widget behavior in block.go, alignment.go, style.go; all pre-built widgets live in widgets/ subdirectory; examples in _examples/ paired with code (e.g., _examples/barchart.go demonstrates widgets/barchart.go). No pkg/ or internal/ isolation.

👥Who it's for

Go developers building CLI tools and monitoring dashboards (like dockdash for Docker stats or expvarmon for Go metrics) who need rich terminal UIs without reinventing text rendering, event handling, or widget layout logic.

🌱Maturity & risk

Actively maintained but with low-frequency updates (maintainer has 'fluctuating availability' per README). No visible CI/CD badges, test files are minimal (_test/log_events.go only), and go.mod targets Go 1.15+. Suitable for production but community-maintained; may have slower response to issues.

Single-maintainer (gizak) actively seeking new maintainers signals succession risk. Only 4 direct dependencies (termbox-go, go-runewidth, go-wordwrap, uniseg) keeps supply chain risk low. No visible test suite means widget behavior changes could break downstream projects silently. Library is stable (v3 branch exists) but new feature velocity is uncertain.

Active areas of work

Unknown from repo data alone (no visible commit log or issue tracker provided). README notes master branch receives changes first before merging to version branches. Maintainer availability is explicitly noted as inconsistent.

🚀Get running

git clone https://github.com/gizak/termui.git && cd termui && go mod download && go run _examples/hello_world.go

Daily commands: make run-examples runs all examples consecutively. Individual: go run _examples/{widget_name}.go (e.g., go run _examples/gauge.go). No dev server; examples are standalone terminal apps you exit with keyboard input (quit logic varies by example).

🗺️Map of the codebase

  • backend.go — Core abstraction for terminal rendering backend; all widget output flows through this—fundamental to understanding how termui interacts with termbox-go
  • buffer.go — Buffer management for cell-by-cell terminal drawing; critical for rendering pipeline and performance
  • grid.go — Layout engine that positions widgets on screen; essential for understanding spatial composition in dashboards
  • block.go — Base widget abstraction providing common properties (border, title, padding); all widgets inherit from this
  • render.go — Main render loop orchestrator; entry point for converting widget trees into terminal output
  • events.go — Event loop and keyboard/mouse input handling; critical for interactive dashboard functionality
  • style.go — Color and styling system; defines how all visual elements are rendered to terminal

🧩Components & responsibilities

  • backend.go (Backend Abstraction) (termbox-go, cgo) — Wraps termbox-go; initializes terminal, handles raw mode, syncs framebuffer, polls events

🛠️How to make changes

Add a New Widget Type

  1. Create a new file in widgets/ (e.g., widgets/customwidget.go) that defines a struct embedding block.Block (widgets/customwidget.go)
  2. Implement the Drawable interface by providing a Draw(buf *Buffer) method (widgets/customwidget.go)
  3. Use buffer.SetCell() to write characters and styles to the rendering buffer within your Draw method (buffer.go)
  4. Optionally handle events by implementing an OnEvent method that processes events.Event (events.go)
  5. Add a reference example in _examples/ demonstrating the new widget (_examples/customwidget.go)

Create a Custom Dashboard Layout

  1. Import the grid package and instantiate widgets (e.g., Bar, Gauge, Table from widgets/) (_examples/demo.go)
  2. Use grid.Grid to define a grid layout, setting rows and columns via grid.SetRect() (grid.go)
  3. Add widgets to the grid using grid.Items and grid.Append() with x, y, width, height positioning (grid.go)
  4. Call render.Render() in a loop within an event handler to refresh the display (render.go)

Customize Colors and Styling

  1. Define a custom Style using style.go (set Fg, Bg, Modifier properties) (style.go)
  2. Assign the style to widget properties (e.g., widget.Block.BorderStyle = customStyle) (block.go)
  3. Alternatively, use theme.go to swap a pre-defined theme globally for all widgets (theme.go)
  4. Parse style strings using style_parser.go if you want inline style definitions (style_parser.go)

Handle User Input

  1. Call events.PollEvent() in your main loop to retrieve keyboard/mouse events (events.go)
  2. Dispatch events to widgets; widgets implement OnEvent(e events.Event) to react (events.go)
  3. Update widget state based on events (e.g., list selection, tab switching) and re-render (_examples/list.go)

🔧Why these technologies

  • termbox-go — Cross-platform terminal backend abstraction; handles raw terminal I/O for Windows, macOS, Linux without ncurses dependency
  • Go 1.15+ — Minimal dependencies, fast compilation, single binary; ideal for terminal tools with no runtime overhead
  • Drawille algorithm (drawille/) — Enables high-resolution graphics (pixel-level) rendering using Unicode box characters in character-cell terminals
  • Cell-based buffer model (buffer.go) — Efficient dirty-region tracking and double-buffering to minimize terminal redraws and flicker

⚖️Trade-offs already made

  • Cell-based rendering instead of vector graphics

    • Why: Terminals are character-cell displays; abstraction must match hardware model
    • Consequence: Lower visual fidelity than GUI frameworks; layout grid-snapped; no subpixel rendering
  • Synchronous, blocking event loop instead of async

    • Why: Simpler API; termbox-go event polling is inherently blocking
    • Consequence: Dashboard freezes if a widget's Draw() or OnEvent() handler blocks; heavy computations must be off-thread
  • Embedded block.Block for common widget properties

    • Why: Code reuse; all widgets share border, title, padding logic
    • Consequence: Tight coupling; harder to implement radically different widget types without embedding
  • Global theme via theme.go instead of per-widget styles

    • Why: Unified dashboard appearance with minimal boilerplate
    • Consequence: Per-widget overrides require manual style assignment; no style inheritance chain

🚫Non-goals (don't propose these)

  • Real-time data streaming or live metric aggregation (widgets display data passed in; no built-in data pipelines)
  • Accessibility features (WCAG/screen readers; terminal-only)
  • Responsive mobile UI (character terminals are desktop/server-only)
  • Animation or frame-based timing (UI updates are event-driven, not time-driven)
  • Network or IPC communication (purely local rendering library)

🪤Traps & gotchas

  1. ui.Init() must be called before any rendering; ui.Close() is essential (defer it) to restore terminal state. 2) SetRect(x, y, x2, y2) uses exclusive max bounds (x2, y2 are not rendered); off-by-one a common mistake. 3) No explicit refresh needed; Render() must be called in event loop for updates (not automatic). 4) termbox-go has platform-specific quirks (Windows requires a modern terminal; xterm vs iTerm2 may render braille/Unicode differently). 5) Widgets are not automatically responsive; you must recalculate SetRect() on terminal resize events (ui.ResizeEvent).

🏗️Architecture

💡Concepts to learn

  • Drawable interface — Every renderable object (widget) in termui implements Drawable (Draw(Buffer) method); understanding this contract is required to create custom widgets.
  • Double-buffering — termui uses Buffer (in-memory pixel grid) before flushing to termbox; prevents flicker and enables efficient redraw on resize/input.
  • Termbox cell-based rendering — Terminal is treated as a 2D grid of cells (each cell: rune + foreground/background color + modifiers); core abstraction for cross-platform rendering.
  • Grid layout engine — grid.go enables responsive, relative positioning of widgets (rows/cols/span) without calculating absolute coordinates; critical for adaptive dashboards.
  • Braille dot graphics (Drawille) — drawille/ subdirectory implements Unicode braille characters for smooth curves in Canvas; enables line charts and scatterplots in terminal without ASCII blockyness.
  • Rune-width calculation — East Asian fullwidth characters (CJK) occupy 2 cells; dependency on go-runewidth handles width calculation so text alignment doesn't break with Unicode.
  • Event-driven polling loop — ui.PollEvents() is non-blocking iterator over keyboard/mouse/resize events; pattern for reactive CLI (must be called in main loop to respond to user input).
  • nsf/termbox-go — Low-level terminal abstraction that termui wraps; understanding termbox-go's Cell and Event types is essential for backend.go.
  • rivo/tview — Competing Go terminal UI library with similar widget set (Table, Boxes, Forms) and reactive paradigm; alternative if termui doesn't fit.
  • charmbracelet/lipgloss — Modern Go styling library often paired with termui alternatives (bubbletea); reference for declarative style composition.
  • charmbracelet/bubbletea — Event-driven terminal framework (Elm-inspired) that complements termui for complex interactive apps; many termui users migrate here.
  • fdehau/tui-rs — Rust equivalent that inspired termui's design (per README); study its architecture for layout and widget patterns in Rust.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for widgets package

The widgets/ directory contains 10 widget implementations (barchart, gauge, image, list, paragraph, piechart, plot, sparkline, stacked_barchart, table, tabs, tree) but there are no corresponding *_test.go files visible in the repo. This is a high-value addition that would improve code reliability and serve as usage documentation for contributors. Testing widget rendering, event handling, and state management would significantly increase maintainability.

  • [ ] Create widgets/barchart_test.go with tests for data updates, rendering, and boundary conditions
  • [ ] Create widgets/table_test.go testing cell rendering, column widths, and scroll behavior
  • [ ] Create widgets/tree_test.go testing node expansion, traversal, and keyboard navigation
  • [ ] Add tests for common widget behaviors (Focus, Blur, SetRect) across at least 3 widget types
  • [ ] Ensure tests cover the examples in _examples/ directory (e.g., validate barchart_test matches barchart.go example)

Add GitHub Actions CI workflow for cross-platform testing

The repo targets cross-platform Go development (Linux, macOS, Windows evidenced by symbols_windows.go and symbols_other.go) but lacks automated testing. A CI workflow would catch platform-specific bugs early, especially important for terminal UI code that behaves differently on Windows vs POSIX systems. Currently relying on manual testing increases risk of regressions.

  • [ ] Create .github/workflows/test.yml with matrix testing on ubuntu-latest, macos-latest, windows-latest
  • [ ] Run 'go test ./...' and 'go vet ./...' across all platforms
  • [ ] Add build verification for all examples in _examples/ directory to catch compilation errors
  • [ ] Run go fmt and go mod tidy checks to enforce code style
  • [ ] Set up workflow to test against Go 1.15 (minimum per go.mod) and current stable version

Add integration tests for event handling in events.go and input workflows

The events.go file defines the event system core but lacks visible test coverage for event polling, key parsing, and mouse handling. Given termbox-go is the underlying event system and platform differences are significant, integration tests validating the event pipeline would prevent subtle bugs. This is particularly critical since the event layer is fundamental to all interactive widgets.

  • [ ] Create events_test.go with tests for PollEvent() behavior and event type assertions
  • [ ] Add tests in events_test.go validating keyboard event parsing for special keys (arrow keys, Enter, Escape)
  • [ ] Create tests for mouse event coordinate translation across different terminal sizes
  • [ ] Add integration test validating event flow through a simple widget (e.g., using List widget from _examples/list.go)
  • [ ] Test platform-specific behavior by verifying symbols_windows.go and symbols_other.go usage in event contexts

🌿Good first issues

  • Add unit tests for buffer.go (Cell merging logic, CellBuffer allocation) and grid.go (layout calculations); currently no tests exist for core rendering.
  • Document the Drawable interface contract and provide a worked example (custom_widget.go) showing how to implement it; helps onboard new widget authors.
  • Add keyboard shortcut reference to README or wiki (e.g., table navigation, list scrolling, tree expand/collapse); currently unclear without reading widget source code.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 3ee54a0 — Merge pull request #337 from hamzausmani302/fix/negative-values-barchart (gizak)
  • cbb827e — added < 0 check while drawing bar (hamzausmani302)
  • 2b8f0c7 — Merge pull request #328 from pgagnidze/updo (gizak)
  • 9955117 — Update README.md (pgagnidze)
  • b3569a6 — Merge pull request #327 from Spelchure/master (gizak)
  • 6b701f2 — Update deps and readme (gizak)
  • 780c93d — feat: limit sparkline bar height to the MaxHeight (Spelchure)
  • f976fe6 — Merge pull request #288 from gizak/v3 (gizak)
  • 0b52bac — Move sub /v3 to repo root (gizak)
  • 4cca61d — v3.1.0 (cjbassi)

🔒Security observations

The termui codebase is a terminal UI library with moderate security posture. Primary concerns include the outdated Go 1.15 requirement, potentially unmaintained termbox-go dependency, and lack of visible input validation documentation. The project itself doesn't appear to handle sensitive data or network operations, limiting attack surface. No hardcoded credentials, SQL injection, or obvious injection vectors detected in the file structure. Main recommendations: (1) modernize Go version target, (2) audit and potentially replace termbox-go with actively maintained alternative, (3) implement explicit input validation for all widgets, and (4) integrate automated dependency vulnerability scanning into the build pipeline.

  • Medium · Outdated Go Version Requirement — go.mod. The project targets Go 1.15 as minimum version, which was released in August 2020 and reached end-of-life in December 2021. This version lacks security patches and bug fixes from newer Go releases. Modern Go versions include important security improvements. Fix: Update go.mod to require Go 1.19 or later (preferably 1.21+). This aligns with current security best practices and ensures access to modern security patches.
  • Medium · Outdated Dependency: termbox-go — go.mod - github.com/nsf/termbox-go v1.1.1. The termbox-go library (v1.1.1) is used directly for terminal control. This is an older dependency that may have security issues or lack modern terminal safety features. No recent maintenance indicators are visible. Fix: Audit termbox-go for known CVEs. Consider evaluating modern alternatives like tcell or Bubble Tea if security updates are not available. At minimum, add dependency scanning to CI/CD pipeline.
  • Low · Indirect Dependency Management — go.mod - github.com/rivo/uniseg v0.4.4. The go.mod file marks rivo/uniseg as an indirect dependency with a comment, but it's a transitive dependency through go-runewidth. Indirect dependencies may not receive the same security scrutiny as direct dependencies. Fix: Run 'go mod tidy' and 'go mod verify' regularly. Implement automated dependency scanning tools (e.g., 'go list -json -m all' in CI/CD) and use GitHub Dependabot or similar for vulnerability alerts.
  • Low · Missing Input Validation Documentation — widgets/ directory (all widget implementations). The project contains multiple widget types (list, table, tree, etc.) that accept user input or display user-provided data. Without visible input sanitization patterns, there's potential for display injection or buffer issues. Fix: Implement comprehensive input validation and sanitization for all user-facing widgets. Add security documentation outlining safe usage patterns. Ensure terminal escape sequences cannot be injected through user data.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · gizak/termui — RepoPilot