A terminal UI for Taskcluster, Mozilla's CI/task execution platform. Browse and act
on Taskcluster entities — worker pools, workers, tasks, task groups, artifacts, roles, clients, secrets, hooks,
GitHub builds and more — without leaving the terminal. Navigation is command-bar driven, in the spirit of
vim/k9s.
Requires Go 1.26.5+.
go install github.com/taskcluster/tc-tui@latestThis installs tc-tui into $GOBIN (or $GOPATH/bin when GOBIN is unset), which should be on your
PATH. Once versioned releases are available, replace @latest with a tag such as @v1.0.0 to install a
specific release.
To build or run the current checkout instead:
go build . # produces ./tc-tui
go run .tc-tui needs TASKCLUSTER_ROOT_URL set — it panics on startup otherwise, since the Taskcluster client SDK is
initialized via NewFromEnv():
export TASKCLUSTER_ROOT_URL=https://community-tc.services.mozilla.com/
go run .Optional credential env vars (TASKCLUSTER_CLIENT_ID, TASKCLUSTER_ACCESS_TOKEN, etc.) enable authenticated
calls (creating tasks, viewing secrets, ...). Without them the app runs anonymously — most read-only resources
on public instances (like community-tc) are still browsable.
You can jump straight to a view instead of the default/last session by passing positional args, the same way
:name scope would in the command bar:
tc-tui # resume the last session (or the command palette)
tc-tui wp proj-taskcluster/ci # open that worker pool directly
tc-tui pending proj-taskcluster/ci # open its pending tasks
tc-tui task <taskId> # open a task directly
tc-tui --help # full key + resource reference (no root URL needed)
tc-tui --version # client version and build hashThe view stack is persisted across restarts, so tc-tui reopens wherever you left off.
Open the command bar with : and type a resource name or alias (:wp, :workers <poolId>, :task <id>,
:help, :quit), or press Ctrl-A to pick from a filterable list of everything available. Move with
j/k or the arrows, Enter to drill in, Esc to go back.
| Key | Action |
|---|---|
: |
command bar — switch resource, e.g. :workerpools, :wp, :workers <poolId>, :quit |
Ctrl-A |
command palette — every command and its aliases (resources plus help/quit) as a filterable list; Enter runs the selected one (also :commands) |
/ |
filter the current list's rows, or a detail body's lines (including a live-streaming log), highlighting the match |
1-9 |
sort the current list by that column, numbered left to right (press again to reverse) |
Tab / Shift+Tab |
cycle the facet tab bar, for resources that have one (e.g. worker pools by provider, workers by state) |
j/k, arrows |
move selection / scroll |
Enter |
drill into the selected row |
r |
refresh the current view, bypassing the cache |
x |
on a list, toggle column truncation (then ←/→ to scroll columns); on a detail, toggle word-wrap |
n |
on a detail view, toggle a vim-like line-number gutter |
v |
on a detail view that masks its content by default (a secret's values), reveal it in the clear; press again to hide. Lasts for that visit only, and revealed content is never cached |
L |
load ALL rows of a truncated list (large lists fetch ~1000 rows up front, shown as N+ in the title) |
o |
open the current view in Taskcluster's web UI, if it has one |
s |
save the current view's content to a local file, if supported (e.g. an artifact) |
Esc |
go back |
? |
toggle the in-app help screen (full, always-up-to-date resource/key reference) |
q |
quit (also :quit / :q) |
In the footer input (command bar, filter, id prompt), Up/Down cycle through previously entered values,
scoped separately per input kind.
Detail views expose their own context keys as header hints — e.g. a task offers E rerun, T retrigger, plus
cancel/priority actions, l live log, a artifacts, R runs, D dependents; a worker pool offers w
workers, p pending, c claimed, l launch configs, e errors, P purge cache.
Addressed by name or alias in the command bar. Press ? inside the app for the full list with each resource's
columns and required scope, or Ctrl-A for the same list as a filterable, selectable palette.
A scoped resource opened without its scope (:workers, or picking it from the palette) asks for one. Where a
browsable parent list exists the prompt says worker pool id (blank to browse), so you can paste the id you
already have or press Enter on the empty field to browse and drill down instead. Where there's nothing to
browse — Taskcluster has no "list all tasks" API — the prompt just asks for the id.
Auth & secrets
roles(role) — IAM-style roles and the scopes they grantclients(client) — auth clients (credentials) and their scopessecrets(secret) — secret names; opening one shows its keys and structure with every value masked (••••••••). Pressvto reveal the values in the clear,vagain to hide them. A reveal lasts for that visit only — navigating away and back shows the masked view again — and revealed content is never cached.
Hooks
hooks(hook) — scheduled/triggered task templates across all hook groupshookfires(fires) — a hook's recent fires; select one to jump to its task
Worker pools & workers
workerpools(wp,pools) — provisioning config: provider, capacity, pending/claimed/error counts (faceted by provider)workers(w) — individual workers in a pool (faceted by state: running/requested/stopping/stopped)recenttasks— a worker's recent taskslaunchconfigs(lc,configs) — launch configurations for a pool (active/all)errors(err) — provisioning errors reported for a poolpurgecache(purge,cache) — open cache-purge requests for a pool
Tasks
task— a single task by id: definition, state, payload, runs, and rerun/retrigger/cancel/priority actionstaskgroup(g) — tasks belonging to a task group, by idtasks(t) — tasks in a task group (scoped list)dependencies/dependents— a task's dependencies, and tasks that depend on itruns— a task's runs; select one, thenwfor its workerartifacts— a task's artifacts across all runs; view/stream logs orsto downloadcreatetask(newtask) — create a task, edited in$EDITORindex(idx) — browse the task index by namespace, or resolve a full index path to its task
Queue
pending— tasks currently pending on a worker pool's task queueclaimed— tasks currently claimed (running) on a worker pool's task queue
GitHub
githubbuilds(builds) — a pull request's or commit's builds (org/repo/pull/<n>ororg/repo/sha/<sha>)githubrepo(repo) — a repository's Taskcluster integration status (org/repo)
Navigation
history(hist) — chronological log of visited resources; select a row to jump back
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Captured live against community-tc, Mozilla's public community
Taskcluster instance, running anonymously. To regenerate them, build the binary and run the capture tool
(it drives tc-tui inside a pty and renders frames with pyte/Pillow):
go build .
TASKCLUSTER_ROOT_URL=https://community-tc.services.mozilla.com/ python3 scripts/screenshot.pyFour packages, in strict dependency order — taskcluster → resource → shell → controller:
taskcluster/— thin wrapper around the generated Taskcluster Go clients (github.com/taskcluster/taskcluster/v101). Handles pagination and caps artifact-content fetches.resource/— one file per entity type, each implementing a commonResourceinterface (List/Describe/Columns/Aliases/...). Optional marker interfaces opt a resource into extra shell behavior — scoped/faceted lists, direct-by-id lookup, progressive row augmentation, web links, downloads, live-log streaming. The shell is entirely generic over this interface.shell/— thetview/tcellUI: table view, detail view, command bar, filter, facets, sort, help, a short-TTL list cache, anEsc-based navigation stack, and persisted UI state.controller/— wires ataskcluster.Taskclusterclient into aresource.Registryand starts theshell.Shell; also restores/persists navigation state.
Adding a resource is just a new resource/<name>.go (plus any new API method on the taskcluster interface)
registered in controller.NewController() — the shell needs no changes. See CLAUDE.md for the full guide.
resource/ and shell/ are covered by unit tests (go test ./...); there is no CI configured for this repo
currently.









