OPPENHEIMER is a Taskell-inspired hierarchical listboard app, perfect for terminal lovers who hope to make the world a better place.
Whether you're plotting world domination or just trying to get through Monday, this listboard app will help you stay on track - or not.
A board is a folder - one plain markdown file per task, with a board.toml next to them recording which list each task is in and in what order.
- π Hierarchical Listboards: Because sometimes simple listboards just don't cut it.
- π Plain files: One markdown file per task, one
board.tomlper board. Grep it, edit it, commit it. - π€ Agent-friendly: A command line to add, list, claim and close tasks, plus a Claude Code skill and slash commands to go with it.
- π Lean & Simple: Less bells, less whistles.
- β‘ Fast & Efficient: Built for the keyboard-oriented mad scientist.
- π οΈ Customizable?: Yes! just tweak the code to suit your style or theme of the day.
- π Terminal-based: For those who live and breathe the terminal.
Install it from crates.io:
cargo install oppenheimer
Or build it from source:
- Clone the Repo:
git clone https://github.com/rlofc/oppenheimer.git - Build It: Navigate to the directory and run
cargo build --release - Create Your First Board:
cargo run --release my_project- this creates amy_project/folder in the current directory to hold your board.
Keep a board inside the project you work on and use it as the shared memory between you and Claude Code. Claude writes what it notices to the board while working on the code. You open the board in the TUI, decide what actually matters, and hand a task back to be implemented.
Three commands set this up. Run them from your project directory, with the name of the board folder you want to use:
oppenheimer my_project install-skill
oppenheimer my_project install-templates
oppenheimer my_project install-commands
install-skillwrites the Claude Code skill to.claude/skills/oppenheimer/SKILL.md, wired to your board's name.install-templateswrites.templates/default.md, the shape every new task starts from.install-commandswrites the/nextand/specifyslash commands to.claude/commands/.
Re-run install-skill and install-commands after upgrading oppenheimer to regenerate them. install-templates leaves an existing default.md alone.
You jot tasks down in the TUI with o, and Claude writes its own with add. The skill tells it to capture a TODO, a gap or any deferred work it runs into while working on the code, without being asked. Both sides work independently, at any point.
Tag a task #spec-needed and run /specify. It looks for the tagged tasks and fills each one in following your template - Story and a Gherkin GIVEN/WHEN/THEN Specification in the default one - then drops the tag. It only writes the spec. It doesn't claim, implement or close anything.
/next picks up the first OPEN, unclaimed task on the board and claims it, lighting up a red CLAIMED on the board. Claude works on it in a dedicated git worktree branched off master, and from there follows whatever other skills and guidelines your project carries. The branch is left for review. Nothing is merged, rebased or pushed unless you ask.
oppenheimer <board_name>opens the board in the TUI, creating the folder if it doesn't exist yet.oppenheimer <board_name> add "title #tag1 #tag2"adds a task to the board's first list.--template=customseeds its content from.templates/custom.md.oppenheimer <board_name> printprints one labeled line per task.--list=nameand--opennarrow it down.oppenheimer <board_name> claim <task_id_or_path> --id=<agent_id>marks a task as claimed by that agent.oppenheimer <board_name> close --id=<task_id_or_path>marks a task done. Idempotent.oppenheimer <board_name> next [--list=name]prints the first OPEN, unclaimed task in "next" or "todo".oppenheimer <board_name> migrate <old_board.md>converts a pre-0.6 single-file board into a board folder. See Moving from 0.5.x to 0.6.oppenheimer <board_name> install-skillinstalls the Claude Code skill, wired to this board.oppenheimer <board_name> install-templatesinstalls.templates/default.mdwith the Story and Specification skeleton.oppenheimer <board_name> install-commandsinstalls the/nextand/specifyslash commands.
Every one of these prints the path (or paths) it wrote. print and next are read-only and need the board to exist already - next exits non-zero when nothing is eligible. claim and close take either the bare 8-character id or any path ending in <id>.md.
If a .templates folder exists in the current directory, its default.md is used as the initial content - the freeform section below the title - for every new task, both the ones added with add and the ones you create in the TUI with o. --template=name on add picks .templates/name.md instead. If the file isn't there, whether it's the folder, the default.md or a named template that's missing, the task falls back to no initial content, exactly as if no template existed.
| Key Combination | Action |
|---|---|
Ctrl + o |
Insert list to board |
o |
Insert item after selection |
Shift + o |
Insert item before selection |
Ctrl + d |
Delete a list |
d |
Delete an item |
Down or j |
Move down |
Up or k |
Move up |
Right or l |
Move right |
Left or h |
Move left |
Ctrl + Left or Ctrl + h |
Move item to previous list |
Ctrl + Right or Ctrl + l |
Move item to next list |
Ctrl + Down or Ctrl + j |
Deprioritize selected item |
Ctrl + Up or Ctrl + k |
Prioritize selected item |
Shift + Left or Shift + h |
Shuffle list forward |
Shift + Right or Shift + l |
Shuffle list back |
Enter |
Edit current item |
Space |
Toggle current item selection |
Tab |
Open item sub-board |
Esc |
Go back to the previous board; clears a lingering search highlight |
/ |
Search |
y |
Yank selected item |
x |
Cut selected item |
p |
Paste item |
v |
View current item's file in a popup, via the configured viewer |
e |
Open current item's file in an external editor, via the configured editor |
c |
Copy current item's id to the system clipboard |
Shift + c or C |
Copy current item's title with its id in parentheses, e.g. Fix login bug #urgent (a1b2c3d4) |
j/k, Down/Up (in popup) |
Scroll the viewer popup |
Esc/q/Enter (in popup) |
Close the viewer popup |
u |
Undo action |
r |
Redo action |
? |
Help |
q |
Quit application |
Oppenheimer is configured with a config.toml file.
-
dim_tailing_items: Dims the trailing items in each list. Defaults tofalse. -
path_separator: The separator string used when rendering board paths. Defaults toγ. -
viewer_command: The command run by thevkey to render the selected item's file, with the file path appended as the last argument. Defaults tomdcat --ansi --theme catppuccin-mocha- set it to any command that takes a path and prints to stdout, e.g.glow -w 100 -n -s dark,bat --color=alwaysorcat. -
viewer_omit_metadata: Boolean, defaults totrue- the viewer only gets the task's title and content, with the TOML frontmatter left out. Set it tofalseto view the raw task file, frontmatter included. -
viewer_omit_header: Boolean, defaults totrue- the viewer popup's border has no title bar. Set it tofalseto show the task's title in the border. -
editor_command: The command run by theekey to open the selected item's file for editing, with the file path appended as the last argument. Defaults toemacsclient -n- set it to any non-blocking, window-reusing command your editor provides. -
Styles: Customizes the visual styles, see below.
Each style can have a foreground (fg) and a background (bg) color.
-
Named Colors: You can use predefined color names like
black,red,green,yellow,blue,magenta,cyan,white,darkgray,lightred,lightgreen,lightyellow,lightblue,lightmagenta,lightcyan,lightgray. -
Hex Colors: You can define colors using hex codes, e.g.,
#FF00FFfor magenta. -
Indexed Colors: Oppenheimer supports indexed colors. Use an integer to specify an indexed color.
-
header: Style for list headers. -
active_header: Style for the active list header. -
item: Style for list items. -
tag: Style for#tags. -
tag_hashsign: Style for the hash sign in tags, and for the[#N],[id]and[created_at]fragments of an item's header line. -
fringe_on: Style when an item fringe is set toon(when it has a sub-board). -
fringe_off: Style when the fringe is set tooff. -
selected: Style for selected items (usually used just to set the background). -
highlight_bg: Background color for items matching a committed search. Unlike the other entries this is a single color rather than anfg/bgpair, defaulting to a dark teal (24).
When not using an existing config.toml file, Oppenheimer will generate a default one.
migrate converts a pre-0.6 single-file board into a board folder. Point it at the old file and name the folder you want:
oppenheimer my_project migrate old_board.md
That reads old_board.md, creates my_project/, writes every task as its own <id>.md, records the lists and their order in board.toml, and turns each sub-board into a folder named after the task that owns it, recursively. It prints a summary of what it converted and then the full path of the new board folder.
The old file is only ever read. Nothing is written back to it and nothing is deleted, so keep it around until you've opened the new board and confirmed it looks right.
migrate creates the board folder itself and refuses to run if my_project/ already exists, rather than merging into it or overwriting anything. The same goes for a source file it can't make sense of - the parse happens before the folder is created, so a file with no ## headings in it fails with a message and leaves nothing behind.
Two things don't carry over, because the old format had nowhere to keep them. There are no timestamps, so every migrated task gets created_at and modified_at set to the moment you ran migrate, and a task that was already checked off gets the same value for closed_at. There's also no freeform content, so every migrated task is just a title with an empty body - which is what .templates/default.md and /specify are for, once you're on the new format. Tags do survive, since they've always lived in the title text as #hashtags.
OPPENHEIMER started out imitating Taskell by Mark Wales (@smallhadroncollider), and takes its one-file-per-task, agents-first half from kanban-md by Sergey Antopolskiy (@antopolskiy). Thank you both!
Fork the repo and send a PR.
OPPENHEIMER is licensed under the BSD License.

