Skip to the content.

forgetop

A fast, keyboard-driven command center for your pull requests, work items, and CI pipelines — across GitHub, GitLab, Azure DevOps, Bitbucket, Linear, and Jira — in one place. Triage and act on everything without tab-hopping between forges, as a terminal UI and a web dashboard.

This is the full reference. For install and a 60-second start, see the README.

Many sections below have a Terminal / Dashboard switch — pick the surface you’re using and the whole page follows, so you only read the instructions that apply to you. Your choice is remembered.

What forgetop does

Core concepts

Sections and bindings

forgetop has three sections: Pull Requests, Work Items, and Pipelines. Each is bound to one or more connections (a configured account on a forge). A section only shows data from the connections bound to it. You manage connections and bindings in the web dashboard — press C in the TUI to open it.

Providers and capabilities

Each provider advertises capabilities — which sections it can serve. A connection only ever offers what it can actually do, so the UI never dangles a dead option:

Provider Pull Requests Work Items Pipelines
GitHub yes yes (Issues) yes (Actions)
GitLab yes (MRs) yes (Issues) yes (CI)
Azure DevOps yes yes yes (Builds)
Bitbucket yes yes (Pipelines)
Linear yes
Jira yes

Cross-provider aggregation

Every section aggregates. Bind two or more connections to Pull Requests (or Work Items, or Pipelines) and their items merge into a single list with a Provider column so you can tell them apart. Filtering, sorting, and actions all work across the combined list — and each action targets the row’s own provider, so approving a GitLab MR and merging a GitHub PR just work from the same screen.

Try it live: forgetop --demo seeds two demo connections so you can see the merged lists immediately.

Security

Tokens are written to the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). The JSON config only stores a reference to each token — never the secret itself. For headless use you can supply a token via an environment variable instead (see Configuration).

The web dashboard is served on 127.0.0.1 only, gated by a per-session token carried in its URL. Because its API can act on your behalf (merge a PR, change a state), it never listens off-loopback and never accepts cross-origin requests; the token is never returned by the API, written to config, or logged.

Getting started

Try it with no setup — everything is in memory, nothing is written:

forgetop --demo

Then run it for real:

forgetop

This opens the terminal UI and the web dashboard together (the default). On first launch — before any connection has a token — the dashboard drops into a quick setup: pick a provider, paste a token, choose which sections it feeds. Tokens go to your OS keychain and are shared straight back to the terminal. Press C in the TUI (or open the dashboard’s Settings) to manage connections any time, and ? shows every keybinding. See Web dashboard for the run modes.

Diagnosing setup

If a connection isn’t working, run the diagnostic — it checks the config location, keychain access, and each connection’s token + connectivity, without opening the UI:

forgetop doctor

It prints a line per connection ( healthy, no token, token present but auth failed), so you can see at a glance whether it’s a missing token, a bad scope, or an expired credential.

Command-line options

Command What it does
forgetop Launch — the terminal UI and the web dashboard together (default)
forgetop --dashboard Serve only the web dashboard (headless — no TUI)
forgetop --demo (-d) Launch with built-in demo data (no setup)
forgetop doctor Diagnose config, keychain access, and connection health
forgetop --version (-V) Print the version and exit
forgetop --help (-h) Show usage and exit

Set FORGETOP_STARTUP = both / terminal_only / dashboard_only to override what launches for a single run (handy with --demo, whose config is in-memory).

Web dashboard

forgetop ships the same app as a local web dashboard — the Command Center, all three lists, PR review with an inline-comment diff viewer, the command palette, sort/filter, themes, and every write action (approve, merge, comment, submit a review, change a work-item state, approve a pipeline gate, retry a run, mark a notification read). It’s a React app built into the binary and served by forgetop itself — no separate install, no external network.

The terminal UI and the dashboard are two frontends over one core, so they show the same data, act through the same providers, and share the same config + keychain — a connection or a setting changed in one shows up in the other.

Opening it

When forgetop starts

A shared preference decides what launches — set it in the dashboard under Settings → When forgetop starts, or press , in the TUI:

Option Behaviour
Dashboard + terminal (default) Opens both together
Terminal only Just the TUI (the server still runs in the background, so B works)
Dashboard only Just the browser dashboard — same as forgetop --dashboard

The choice is stored in your config and shared between the two. For a one-off override (without changing the saved setting) use the FORGETOP_STARTUP env var above.

Connections & settings

Connection setup lives in the dashboard’s Settings page: add a provider from a form tailored to it, paste a token (stored in the OS keychain), tick which sections it feeds, and Test / Edit / Delete it. First launch with nothing set up opens this automatically. Pressing C in the TUI jumps straight here.

Security

The server binds 127.0.0.1 only and gates its API with a per-session token in the URL — see Security.

Command Center

The Command Center is the screen forgetop opens on. Instead of browsing by type, it answers one question — what needs me right now? — by pulling every PR, work item, and pipeline across every connected provider into a single, prioritised page. The Pull Requests / Work Items / Pipelines views are still there as drill-downs.

It’s split into two columns:

Every row is laid out on one aligned grid so PRs, pipelines (CI), and work items (WI) read as siblings: a coloured type badge, a status signal (a PR shows its review state — ✓ ok, ○ review, ✗ changes, ◌ draft; a pipeline its run status; a work item its state), a short #ref, the title, one type-specific detail (PR +/-, pipeline branch, work-item type), the provider, and the age (which reddens once it’s stale). For pipelines the title is the pipeline name (e.g. CI Build) and the ref is the run/release (e.g. 10.1.100).

Getting around: the two columns scroll independently. Click a card to open it — a pull request opens its in-app review panel right here; work items and pipelines open in their provider (open them from the Work Items / Pipelines tabs for the in-app panel). When you act on an item — submit a review, approve, or merge — it drops off the Command Center straight away rather than waiting for the next poll. The sidebar Command Center badge counts only the items that actually need you.

Getting around:

Two touches make it feel live: when you act on an item — submit a review, approve, or merge a PR — it drops off the Command Center immediately rather than lingering until the next poll; and the selected row’s title scrolls horizontally when it’s too long to fit, so you can always read it in full. The Command Center (N) tab badge counts the items that actually need you (the reference sections don’t inflate it).

Pull Requests

The Pull Requests view is browse-and-open: the list is for finding a PR; every write action lives inside the PR panel.

On the list:

The meta bar under the title shows who opened the PR and the reviewers, each with a vote mark: approved, changes requested, · no vote yet. (These come from the provider’s review data — on GitHub/GitLab the votes are read from /reviews and /approvals, not just the requested-reviewer list, so an approver actually shows a tick.)

Inside the PR panel (three tabs):

Checks live on the action-bar badge (below), not a tab.

The Timeline (newest first) shows who did what: approvals, change-requests, merges, state changes and comments — assembled from each provider’s timeline/activity/history API (GitHub reviews + issue events, Bitbucket activity, GitLab resource-events + approvals, Azure reviewer votes, plus comments). A provider without a timeline API just shows the comment activity.

The header has an ↗ open-in-provider link. The action bar shows a checks badge on the left — green “All checks passed” or red “N checks failed”; click it for a popover listing every check (each links to the provider) — and Approve, Request changes, Merge on the right. Choosing an action closes the panel. Press Esc or click the backdrop to close.

Reviewing code with line comments

On the Files tab, click the + on a code line to write an inline comment. Comments are buffered as pending (shown in a blue pending box) so you can comment on several lines first, then submit them together as one review — Submit comments, Request changes, or Approve. If you try to close the panel with comments still pending, forgetop asks before discarding them.

Replying to a comment

Click ↳ Reply under any comment to answer it in-thread rather than starting a new top-level comment. forgetop uses each provider’s real reply API:

The Pull Requests tab is browse-and-open: the list is for finding a PR; every write action lives inside the PR view.

On the list:

Inside the PR view (four sub-tabs, switch with /):

Write actions from the view: a approve, x request changes, m merge (pick a strategy), c comment, r reply to a thread, o open in browser.

Reading the diff

Reviewing code with line comments

In the Diff tab’s line cursor, press c on a code line to write an inline comment. Comments are buffered locally — the line gets a marker — so you can comment on several lines first. Press s to submit them all as one review, choosing the verdict: Comment, Approve, or Request changes. If you press Esc or q to leave with comments still buffered, forgetop asks whether to submit or leave without submitting first, so you don’t lose them by accident.

Work Items

The Work Items view shows only items assigned to you — each provider resolves the current user from your token (@me, currentUser(), isMe, …), so there’s nothing to configure.

Browse-and-open; the write actions live in the item panel.

The list is browse-and-open; the write actions live in the item view:

Inside the item view (after Enter):

Pipelines

Each entry is a run, tagged with its pipeline (definition) name — e.g. CI Build or CD (Release) — and its own run name or release (e.g. 10.1.100, or its number when it has none).

The list shows a Pipeline column separate from the Run column; sort by Pipeline to group runs by their definition.

Inside the drill-in each node shows its duration, and failed jobs show a short failure reason (GitLab’s reason, Azure’s error/warning counts). Then:

For a connection that discovers many pipelines, open the config screen and press s on it to subscribe to just the definitions you care about.

Approvals

When a run is blocked on a manual gate — a GitHub environment required-reviewer, an Azure DevOps approval check, or a GitLab manual job — forgetop surfaces it, refreshed on the normal poll (and you can opt into a desktop notification when a gate first appears):

Acting is capability-scoped:

Filtering and sorting

Each list has a control bar across the top with three dropdowns, remembered per list in your browser:

All three compose, and all work across the aggregated (multi-provider) list.

Four complementary ways to cut a busy view down:

All of these compose, and all work across the aggregated (multi-provider) list.

Command palette

The command palette is a fuzzy jump across everything already loaded: every PR, work item, and pipeline, from every connected provider, in one list. Type to filter (matching the title, author, branch, identifier, or connection); each row carries a status dot in the usual green/blue/red/grey colours. It searches only what’s loaded — no network round-trip — so it’s instant.

Press ⌘K (Ctrl-K on Windows/Linux) from anywhere to open it; type to filter, click a result (or / then Enter) to open it, Esc to dismiss.

Press Ctrl-P (from the Command Center or any list) to open it; / (or Ctrl-n/Ctrl-p) to move, Enter to open the item’s full view, Esc to dismiss.

Notification inbox

The notification inbox is your notification stream aggregated across providers: review requests, @mentions, assignments, CI failures, comments, and state changes, newest first. It answers what just happened, where the Command Center answers what needs me now. A Notifications nav item carries an unread count that stands out when something’s waiting.

Press i (from the Command Center or any list) to open the Inbox. The Notifications (N) [i] nav item sits at the far right of the tab bar — dim grey at zero, bold yellow with the count when something’s waiting, accent while the Inbox is open. It’s a nav item, not part of the Tab cycle.

Provider support. The inbox is fed by the providers that expose a personal notification feed:

Provider Notification inbox
GitHub ✅ (notifications)
GitLab ✅ (todos)
Linear ✅ (notifications)
Azure DevOps — no personal feed
Bitbucket — no personal feed
Jira — no personal feed

Azure DevOps, Bitbucket, and Jira don’t offer a personal notification feed in their APIs, so connections for those providers simply don’t contribute to the inbox. (This is separate from desktop notifications, which is about which events fire an OS ping.)

Saved views

The dashboard doesn’t have named saved views — instead, each list remembers its own control-bar state (Sort, Connection, Show) in your browser, so a list comes back shaped the way you left it. For the named-view workflow with a switchable view bar, use the terminal (toggle above).

A saved view is a named bundle of a section’s shaping — its base filter, the quick-filter text, the sort, and (on Work Items) which states are hidden. Views live in a horizontal view bar above the list, gh-dash style, with the active one highlighted. The bar appears once a section has more than one view.

Every section starts with sensible defaults: Pull Requests get All, Mine, and Review; Work Items and Pipelines get a single All.

Switching a view re-applies the whole bundle at once, so a Mine view can pin a different sort and quick-filter than Review. Views are persisted per section, so they’re waiting next time — except in --demo, where the in-memory config means saved views last only for that session.

Notifications

forgetop raises native desktop notifications on the events you choose:

Press N anywhere to open a checklist and opt in/out of each event; the choice is persisted. Detection is seeded on load (no startup spam), de-duped, and re-seeded when you change settings — and enabling fires one confirmation notification so you can verify it works on your machine. Every event spans all bound providers, not just the first.

Keybindings

Terminal only — the dashboard is mouse-driven, with ⌘K for the command palette.

forgetop shows a context-aware key glossary along the bottom — it only lists the keys valid for where you are. Press ? for the full panel. The complete set:

Global

Key Action
/ , h / l, Tab, 14 Switch tab (1 = Command Center)
/ , k / j Move selection
Ctrl-P Command palette — fuzzy-jump to any PR, work item, or pipeline
i Notification inbox (review requests, mentions, CI failures, assignments)
/ Quick-filter the current list
S Sort by a column (re-pick flips direction)
o Open selected item in browser
B Open the web dashboard in your browser
F Open the public GitHub feedback issue form
, Settings — what forgetop opens on launch
v Choose which tabs are visible
C Open the connections page (in the web dashboard)
r Refresh · t cycle theme
N Notifications — choose which events ping you
? Show all keybindings (anywhere)
q / Ctrl-C Quit · Esc back / close

Command Center

Key Action
/ , k / j Move within the focused column
/ , h / l Switch between the two columns
Enter Open the selected item in its full view
Esc (in the opened item) Return to the Command Center, same row selected

Saved views

Key Action
[ / ] Previous / next saved view
V Save the current filter + sort + states as a view
X Delete the current view

Pull Requests (list)

Key Action
Enter Open the PR view
f Filter by status (Open / Draft / Merged / Closed)
[ / ] Switch saved views (defaults All / Mine / Review-requested)

Inside the PR view

Key Action
/ Switch sub-tab
a / x Approve / request changes
m Merge (choose strategy)
c Comment (inline on a diff line, otherwise the PR)
[ / ] (Diff line cursor) Jump between existing comment threads
r Reply to a comment thread (under the diff cursor, or the Conversation thread)
Enter (Commits) Drill into that commit’s diff
Enter (Diff, on a file) Line cursor within the patch
s Submit buffered line comments as one review
Esc Step back (line cursor → file list → close)

Work Items

Key Action
Enter Open the item
f Choose which states to show
u (in the item view) Update state (choices pulled from the provider)
c (in the item view) Comment

Pipelines

Key Action
Enter Drill in (stages → jobs → steps)
Enter (in drill-in) Expand / collapse a node
L View the selected job’s logs
A (in drill-in) Approve / reject a waiting gate (GitHub, GitLab; Azure view-only)
o Open the selected job in the browser
T Trigger a run

Connections (terminal fallback)

Connection management lives in the web dashboardC opens it and also shows a connections list in the terminal. That list still supports the original keys as a fallback:

Key Action
a Add a connection
p / w Bind Pull Requests / Work Items (multi-select)
s Pipeline subscriptions
x Remove connection

Configuration

Config is a small JSON file, created and managed for you:

OS Path
macOS ~/Library/Application Support/forgetop/config.json
Linux ~/.config/forgetop/config.json
Windows %APPDATA%\forgetop\config.json

It never contains secrets — only a reference to each token in the keychain, plus your bindings and view preferences (saved views, sorts, hidden states, notification choices).

Tokens

You add connections and paste tokens in the dashboard’s Settings page (see Web dashboard); each token is stored in your OS keychain under the service name forgetop. In headless environments (CI, containers) you can instead supply a token via an environment variable named FORGETOP_PAT_<CONNECTION_ID> (uppercased; non-alphanumeric characters become _).

Logs & diagnostics

forgetop keeps rolling diagnostic files next to your config — forgetop.log and its numbered segments in the same directory (e.g. ~/.config/forgetop/). The retained history is limited to approximately the latest 24 hours and never more than 3 MiB; under heavy logging, the size limit wins. It records:

forgetop doctor prints the active log’s path. Logging is best-effort and redacts common credential headers, token fields, credential-bearing URLs, dashboard session tokens, and known provider-token formats. Request/response bodies and configuration contents are not intentionally logged, but you should still inspect diagnostics before sharing them manually. forgetop never attaches them to the GitHub feedback form.

The running version is shown in the header (▟ forgetop v…) and via forgetop --version, so it’s easy to include when reporting an issue.

Token scopes

Provider What to create Scopes
GitHub Personal access token repo (PRs, issues, checks); workflow / Actions read for pipelines
GitLab Personal access token (Settings → Access Tokens) api (merge requests, issues, pipelines)
Azure DevOps Personal access token Code Read, Work Items Read/Write, Build Read/Execute
Linear Personal API key (Settings → Security and access → API) default
Jira API token (id.atlassian.com) + your account email default (account access)
Bitbucket App password (Personal settings → App passwords) + your username Pull requests, Pipelines (read/write)

Themes

Four built-in themes — slate (default), dark, light, and matrix. In the terminal, cycle with t (256-colour palettes, so they render correctly on every terminal, including ones without truecolor); in the web dashboard, use the theme toggle in the sidebar footer. Each side remembers your choice (the dashboard’s per browser).

How it works (architecture)

forgetop is a Rust Cargo workspace:

Crate Responsibility
forgetop-core Domain model, capability-scoped provider traits, config, secrets, services
forgetop-providers GitHub, GitLab, Azure DevOps, Linear, Jira, Bitbucket, and Demo implementations
forgetop-tui The ratatui terminal UI
forgetop-server The web dashboard — an axum server + an embedded React SPA, over the same services
forgetop-cli The forgetop binary

A few design ideas hold it together:

Development

cargo test        # run the test suite
cargo clippy      # lint
cargo run -- --demo

Source: github.com/magna-nz/forgetop.