Skip to content

Latest commit

Β 

History

58 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Oppenheimer logo

Github Actions CI Build Status crates.io

OPPENHEIMER

Earn your reputation, one task at a time

OPPENHEIMER

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.

Features

  • πŸ“‹ Hierarchical Listboards: Because sometimes simple listboards just don't cut it.
  • πŸ“„ Plain files: One markdown file per task, one board.toml per 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.

Get Started

Install it from crates.io:

cargo install oppenheimer

Or build it from source:

  1. Clone the Repo: git clone https://github.com/rlofc/oppenheimer.git
  2. Build It: Navigate to the directory and run cargo build --release
  3. Create Your First Board: cargo run --release my_project - this creates a my_project/ folder in the current directory to hold your board.

Working with Claude

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-skill writes the Claude Code skill to .claude/skills/oppenheimer/SKILL.md, wired to your board's name.
  • install-templates writes .templates/default.md, the shape every new task starts from.
  • install-commands writes the /next and /specify slash 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.

Capturing

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.

Specifying

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.

Picking up

/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.

Command line

  • 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=custom seeds its content from .templates/custom.md.
  • oppenheimer <board_name> print prints one labeled line per task. --list=name and --open narrow 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-skill installs the Claude Code skill, wired to this board.
  • oppenheimer <board_name> install-templates installs .templates/default.md with the Story and Specification skeleton.
  • oppenheimer <board_name> install-commands installs the /next and /specify slash 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.

Task templates

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.

The board in the TUI

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

Configuring using config.toml

Oppenheimer is configured with a config.toml file.

BoardConfig

Options

  • dim_tailing_items: Dims the trailing items in each list. Defaults to false.

  • path_separator: The separator string used when rendering board paths. Defaults to 〉.

  • viewer_command: The command run by the v key to render the selected item's file, with the file path appended as the last argument. Defaults to mdcat --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=always or cat.

  • viewer_omit_metadata: Boolean, defaults to true - the viewer only gets the task's title and content, with the TOML frontmatter left out. Set it to false to view the raw task file, frontmatter included.

  • viewer_omit_header: Boolean, defaults to true - the viewer popup's border has no title bar. Set it to false to show the task's title in the border.

  • editor_command: The command run by the e key to open the selected item's file for editing, with the file path appended as the last argument. Defaults to emacsclient -n - set it to any non-blocking, window-reusing command your editor provides.

  • Styles: Customizes the visual styles, see below.

Styles

Each style can have a foreground (fg) and a background (bg) color.

Color Specification

  • 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., #FF00FF for magenta.

  • Indexed Colors: Oppenheimer supports indexed colors. Use an integer to specify an indexed color.

Style Options

  • 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 to on (when it has a sub-board).

  • fringe_off: Style when the fringe is set to off.

  • 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 an fg/bg pair, defaulting to a dark teal (24).

Defaults

When not using an existing config.toml file, Oppenheimer will generate a default one.

Moving from 0.5.x to 0.6

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.

Credits

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!

Contribution

Fork the repo and send a PR.

License

OPPENHEIMER is licensed under the BSD License.

About

The atomic-age listboard

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages