The format

A plan is a plan/ directory in a git repository, and there is no database anywhere in this product. A block is a piece of roadmap; a feature hangs off a block and is what a release note names; a ticket is a task, a bug or a spike that somebody picks up on a Tuesday. Parentage is the only structure.

Every document is one file with a frontmatter block and a body, every document carries a ULID, and every reference is ck: plus that ULID. A ticket owns a directory whose name never changes, including through a retitle, because a rename plus an edit is the worst input a three-way merge can be handed. State is one line in one file, so moving a ticket is a one-line diff git attributes to a person and a minute.

Nothing stores a date, an author or a percentage. Git holds the first two and the third is counted from the tickets, because a stored copy of a derivable fact drifts the first time somebody edits a file in their editor. There is no delete either: status: dropped is the archive and the history holds the rest.

The bar

Press : anywhere. One line, three parts: :<verb> [<term>] [<name>=<value> …]. The first word says what to do, the rest says what to do it to, and anything shaped like name=value is an argument wherever it appears. Tab completes and never guesses; Enter acts on the one thing that is selected, and nothing is selected while more than one thing matched.

Commands

TypeWhat it doesRuns onArguments
plan.validate Check for problems Plan

Places

TypeWhere it goesSection
plan Overview Plan
roadmap Roadmap Plan
features Features Plan
write Write Plan
tickets Tickets Work
boards Boards Work
docs Docs Reference
repositories Repositories Account
settings Settings Account
help Help Account

Things

TypeHow one is found
block A block is found by typing part of its name.
feature A feature is found by typing part of its name.
ticket A ticket is found by typing part of its name.
board A board is found by typing part of its name.
doc A doc is found by typing part of its name.
plan There is one plan, and this command runs on it. Type its name to name it: plan.
The CLI

ckplan runs against the same working tree and finds the plan by climbing to the nearest plan/, the way git finds .git. It is the same library this application uses, which is what keeps the two from disagreeing about what a plan file means.

ckplan init
ckplan new <type> "<title>" [--parent id] [--assignee who]
ckplan ls [--type t] [--status s] [--assignee a] [--label l] [--parent id] [--text q]
ckplan show <id>
ckplan status <id> <status>
ckplan assign <id> <who>
ckplan comment <id> -m "<text>"
ckplan board [<name>]
ckplan roadmap
ckplan next [--assignee me]
ckplan validate
ckplan open <id>

ckplan validate exits non-zero on any problem, which is what a plan repository puts in its own pre-commit hook.

Tab choose Enter go Esc close