A fast, keyboard-driven terminal UI for tracking your competitive-programming progress — what you've solved, what you're stuck on, what to revisit, and how you're improving over time.
Built in Go with Bubble Tea.
This is completely vibe-coded code, I use it for my CP practice. Apart from this line nothing is written by me. Use it at your own risk!
If you grind LeetCode / Codeforces / AtCoder regularly, you accumulate a lot of context that's painful to retrieve later: which problems you actually understood, which ones you brute-forced and should redo, which topics you keep fumbling. upsolve gives that a single keyboard-only home that lives next to your shell.
List view:
upsolve · 4 questions tracked
╭─────╮ ╭──────╮ ╭────────╮ ╭───────╮ ╭────────╮
│ all │ │ todo │ │ solved │ │ stuck │ │ review │
╰─────╯ ╰──────╯ ╰────────╯ ╰───────╯ ╰────────╯
search: (/) tag: (f)
ID STATUS PLATFORM DIFF TITLE TAGS UPDATED
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
3 todo codeforces 1200 Codeforces Round 900 B greedy,math 13h ago
2 stuck atcoder 1400 Dijkstra warmup graph,shortest-path 1d ago
4 review codeforces - Segment tree lazy propagation review segment-tree,data... 3d ago
1 solved leetcode easy Two Sum array,hashmap 5d ago
a:add ⏎:open s:solve u:stuck r:review n:note e:edit d:del /:search f:tag F:status S:stats ?:help q:quit
Stats view (press S):
╭────────────────────────────────────────────────────────────────────╮
│ progress overview │
│ │
│ total: 4 solved: 1 (25%) last 7d: 1 │
│ │
│ by status │
│ solved ██████░░░░░░░░░░░░░░░░░░ 1 │
│ todo ██████░░░░░░░░░░░░░░░░░░ 1 │
│ stuck ██████░░░░░░░░░░░░░░░░░░ 1 │
│ review ██████░░░░░░░░░░░░░░░░░░ 1 │
│ │
│ by platform │
│ codeforces ████████████░░░░░░░░░░░░ 2 │
│ leetcode ██████░░░░░░░░░░░░░░░░░░ 1 │
│ atcoder ██████░░░░░░░░░░░░░░░░░░ 1 │
│ │
│ by tag (solved / total) │
│ array 1 / 1 │
│ hashmap 1 / 1 │
│ graph 0 / 1 │
│ shortest-path 0 / 1 │
│ greedy 0 / 1 │
│ math 0 / 1 │
╰────────────────────────────────────────────────────────────────────╯
- Four states per question —
todo,solved,stuck,review— switched with single keystrokes. - Tag-based topic tracking (
dp,graph,greedy, …) with per-tag solved-vs-total breakdown. - Per-question timestamped notes — capture the trick, the bug, what to revisit. Stored as a list, never overwritten.
- Live filters — by status (chip bar), by tag, and free-text title search.
- Progress stats — totals, per-status / per-platform / per-tag bars, plus a rolling "solved last 7 days" counter.
- One JSON file at
~/.upsolve/data.json— easy to sync via git, Syncthing, iCloud, whatever. - Single static binary — only build-time deps; no runtime requirements.
git clone https://github.com/<you>/upsolve.git
cd upsolve
go build -o upsolve ./cmd/upsolve
mv upsolve ~/.local/bin/ # or /usr/local/binRequires Go 1.22+.
go run ./cmd/upsolveLaunch the TUI:
upsolvePrint the data-file path:
upsolve whereShow usage:
upsolve helpInside the TUI press ? at any time for a full keyboard reference.
List view
| Key | Action |
|---|---|
↑ / ↓ / j / k |
Move cursor |
enter |
Open question detail |
a |
Add new question |
e |
Edit highlighted question |
d |
Delete (with confirmation) |
n |
Attach a note |
s / u / r / t |
Mark solved / stuck / review / todo |
/ |
Search by title |
f |
Filter by tag |
F |
Cycle status filter chips |
x |
Clear all filters |
S |
Open stats screen |
? |
Help |
q |
Quit |
Form (add / edit)
| Key | Action |
|---|---|
tab / shift+tab |
Next / previous field |
← / → |
Cycle status (on status field) |
ctrl+s |
Save |
esc |
Cancel |
Note editor
| Key | Action |
|---|---|
ctrl+s |
Save note |
esc |
Cancel |
Detail view
| Key | Action |
|---|---|
e |
Edit |
n |
Add note |
s / u / r / t |
Change status |
d |
Delete |
esc / q |
Back to list |
upsolve persists everything to a single JSON file:
~/.upsolve/data.json
Override the location with the UPSOLVE_DATA environment variable:
UPSOLVE_DATA=$HOME/dropbox/upsolve.json upsolveThe file is human-readable and append-friendly, so syncing it across machines via git, Syncthing, or a cloud drive works fine. Every write is atomic (temp-file + rename), so a crash mid-write won't corrupt your data.
upsolve/
├── cmd/
│ └── upsolve/ entry point (main package)
├── internal/
│ ├── model/ domain types: Question, Status, Note, DB
│ ├── store/ JSON load / atomic save / data-file path
│ ├── stats/ filtering, sorting, aggregates
│ └── tui/ Bubble Tea Model, screens, styles
├── go.mod
├── go.sum
├── LICENSE
└── README.md
The TUI depends on model, store, and stats. None of the inner packages
depend on tui, so swapping in a different frontend (web, CLI, plugin) is a
matter of writing a new entry point against the same internal API.
- Spaced-repetition queue: surface
review-tagged questions on a schedule. - Per-question time-tracking and streaks.
- Markdown / CSV export.
- Import from LeetCode / Codeforces submission history.