Skip to content

Repository files navigation

devtree — tree-shaped development planning that lives inside your repository

English · Русский · 中文 · Deutsch · Français

CI Release Container Go Reference License: MIT

Your plan is a file — .devtree/tree.yaml — that sits next to the code. It is versioned with the code, reviewed in the pull request, and merged line by line. From it, devtree draws a Mermaid diagram into TREE.md or straight into your README.md, and a picture of its own into .svg — as a tree, or as a board. GitHub and GitLab render both natively. No browser extension, no image to regenerate by hand, nothing to host.


Why keep the plan in the repository

Three reasons: it gets reviewed, it gets merged, it stays honest

A roadmap in a tracker drifts away from the branch it describes. A roadmap in a wiki is read once and never again. A roadmap in the repository is a file people already have habits for.


How it works

The loop: edit tree.yaml, run devtree render, files are rewritten, GitHub draws them

What it looks like

A sample plan drawn by devtree

Cards, progress rolled up per milestone, and the branch, issue and owner behind each task. Light and dark, following the theme you are reading in.

The same plan in your terminal:

Storefront

◐ MVP  (mvp)  [4/13]
├─ ◐ Backend  (backend)  [3/7]
│  ├─ ◐ Authentication  (auth)  feat/auth  #12  @ann  [1/2]
│  │  ├─ ✔ Sessions and refresh tokens  (sessions)
│  │  └─ ⛔ Password reset  (password-reset)
│  ├─ ◐ API architecture  (api)  @ann  [1/2]
│  │  ├─ ✔ Resources and pagination  (resources)
│  │  └─ ☐ Versioning and error shape  (versioning)  #24
│  └─ ✔ Docker image  (docker)  @bob
└─ ◐ Frontend  (frontend)  [1/4]
   ├─ ✔ Framework: React or Vue  (stack)
   ├─ ◐ Catalog pages  (catalog)  feat/catalog  @ann
   ├─ ☐ Checkout  (checkout)  #51
   └─ ☐ nginx and static hosting  (nginx)  @bob

█████░░░░░░░░░░░░░░░  4/14

devtree also writes a Mermaid block, which GitHub and GitLab draw natively with no image files at all — that is what an .md output gets. This repository's own is in TREE.md.


What the diagrams are made of

Every picture devtree draws — the tree above, the board, the interactive page — comes out of one vocabulary of twenty components.

Twenty drawing components, each shown once
Card a panel, with described lines when needed Cluster a dashed box around a region Callout a bordered note Swimlane a labelled band
ColumnHead a board column heading Stat one number, said loudly Chip a small labelled tag Badge a count
Pill a state, in a wash of its colour Avatar an owner as initials Milestone a point, not a span Legend the key to a drawing
Bar progress along a line Ring the same, in a circle Sparkline which way it is going Timeline an axis with ticks
Divider a hairline Connector a rounded elbow Arrow a connector with a direction Brace these belong together

A component knows nothing about development plans. There is no status here and no task: a Pill takes a colour and a label, and the renderer above decides that "blocked" is red. That is what lets the illustrations in the documentation and the diagrams in your repository come out of one library rather than two.

The gallery moves because movement is its subject — the rings and the sparkline draw themselves on, the meters fill, the count arrives. Your plan diagrams stay restrained on purpose: there, motion is spent on the four things worth noticing — the live path, work in flight, work blocked, progress gained — and everything else holds still. Nothing moves at all under prefers-reduced-motion, or on paper.

Can you click it? Not here, and not because of a shortcut we took: GitHub serves a repository's SVG as an image under default-src 'none'; sandbox, so it gets no script, no navigation and not even a hover. The same is true of its Mermaid, which ignores click. Where clicking does work is the HTML export — name an output .html and every task becomes a link to its pull request, issue or branch, with filters that need no JavaScript — and in the editor, where the drawing is the editing surface.


Drawing with them

p := theme.Palette()

parts.Card(&b, box, p, parts.CardStyle{
    Accent: theme.Blocked,
    Title:  "Authentication",
    Meta:   "feat/auth · ann · #12",
    Glyph:  "lock-circle",
    Motion: draw.ClassPulse,          // blocked work breathes; settled work does not
    Trailer: func(b *strings.Builder, r draw.Rect) {
        parts.Bar(b, r, p, 3, 7, theme.Done, draw.ClassGrow)
    },
})

They are placed with a Rect that splits rather than with four numbers recomputed at every use:

head, body := card.SplitTop(34)     // a band off the top, and what is left
inner      := body.InsetXY(12, 8)
cols       := inner.Columns(3, 10)  // three columns with a gap between them

The gallery is generated by walking the component list, so a component added without a demo fails the build rather than quietly going undocumented. More: docs/components.md.


Install

brew install SergeyLubivui-dev/tap/devtree     # macOS and Linux
go install github.com/SergeyLubivui-dev/devtree@latest

Prebuilt binaries for Linux, macOS, and Windows are attached to every release, with checksums. Or run it without installing anything:

docker run --rm -v "$PWD:/work" ghcr.io/sergeylubivui-dev/devtree render

Building from source needs Go 1.22 and nothing else. Details, and a shell alias that makes the container disappear into the background: docs/container.md.


Quickstart

cd your-project

devtree init --project "Storefront" --repo https://github.com/acme/storefront --hook --action

devtree add "Backend"        -p mvp -s wip
devtree add "Authentication" -p backend -b feat/auth -i 12 -o ann -s wip
devtree add "Docker image"   -p backend -o bob
devtree add "Frontend"       -p mvp -s wip
devtree add "Checkout"       -p frontend -i 51

devtree ls                                   # the tree, in your terminal
devtree done docker-image
git add . && git commit -m "feat: docker"    # the hook refreshes the diagram for you

IDs are derived from titles — "Docker image" becomes docker-image, and non-Latin titles are transliterated so the ID stays typeable. Pass --id when you want to choose one yourself.

A longer walk through the same ground: docs/getting-started.md.


The editor

devtree serve --open      # http://127.0.0.1:9312
The editor: a rail of sections, the plan as a list, and the same plan drawn beside it

A real capture of the page, in both themes: the editor is dark by default and follows your system setting.

The plan on the left, drawn on the right, live. The drawing is the editing surface — every card carries the id of the task it draws, so clicking one opens it and hovering one offers a + that adds work underneath it. Five views behind the dropdown in the header — tree, board, page, Mermaid, YAML — rendered on demand, with nothing written to disk until you press Write outputs.

A second section lists the documents: every destination in outputs, each showing what its name says it holds — tree or board, light or dark, page or Mermaid block. Naming a new one there is how you add an output; the name is what decides the drawing.

It binds to the loopback interface, stores nothing of its own, and every change lands in the same .devtree/tree.yaml the command line writes: keep the editor in one window and a terminal in the other, and neither loses an edit. More: docs/editor.md.


Everyday recipes

Short, real things people do with a plan. Copy one and change the words.

Start a feature, finish a feature. The task and the branch are named together, so anyone reading the diagram knows where the code is:

devtree add "Search filters" -p mvp -b feat/search -i 214 -o you -s wip
git switch -c feat/search
# ...write the code...
devtree done search-filters
git commit -am "feat: search filters"        # the hook refreshes the diagram

Break something big into something doable. Parents count their children automatically, so the milestone reports progress you never have to update by hand:

devtree add "Billing" -s wip
devtree add "Invoices" -p billing
devtree add "Refunds"  -p billing
devtree add "Dunning"  -p billing -s blocked -n "needs the payments API"
devtree ls
◐ Billing  (billing)  [0/3]
├─ ☐ Invoices  (invoices)
├─ ☐ Refunds  (refunds)
└─ ⛔ Dunning  (dunning)

Pick up a ticket. Give it the issue number and it becomes a link in the table under the diagram:

devtree add "Fix timezone drift" -i 512 -o ann -s wip --tags bug

Park what you cannot finish. A blocked task with no note is the one thing check complains about, because "blocked" without a reason is a task nobody can pick up:

devtree set password-reset -s blocked -n "waiting on the SMTP contract"
devtree board -s blocked

Monday morning, in three commands:

devtree board          # what is in flight, what is stuck, what is waiting
devtree ls -s blocked  # only the branches that need a decision
devtree check          # anything marked done that still has open work under it?

Two people, two branches, one plan. Both add tasks, both commit, and the merge is boring — the node list is flat and .gitattributes says merge=union. If two branches happen to pick the same ID, devtree check fails on the spot with the duplicate named.


The board

The tree says how the work is organized. The board says what state it is in this morning — same file, different question:

devtree board
Storefront

☐ not started · 3
  Versioning and error shape   API architecture  #24
  Checkout                     Frontend  #51
  nginx and static hosting     Frontend  @bob

◐ in progress · 1
  Catalog pages                Frontend  feat/catalog  @ann

⛔ blocked · 1
  Password reset               Authentication  — waiting on the SMTP account

✔ done · 4
  Sessions and refresh tokens  Authentication  !31
  Resources and pagination     API architecture
  Docker image                 Backend  !40  @bob
  Framework: React or Vue      Frontend  — React — the team already knows it

█████░░░░░░░░░░░░░░░  4/14

Only leaves appear — a milestone is a container, not a card — and each task carries its milestone as a breadcrumb. Name an output board.svg and the same thing is drawn as columns:

devtree's own board: columns of work by status

More: docs/board.md.


Finished work

A plan that keeps every task ever completed stops being a plan and becomes a log. Two commands handle that from opposite ends:

devtree archive          # what is finished and could move
devtree archive --all    # move it into .devtree/archive.yaml
devtree restore v1       # bring a branch of it back

devtree sync             # tasks whose branch git has already merged
devtree sync --apply     # mark them done

Nothing moves until you say so, and a node qualifies only when its whole subtree is done or dropped, so live work can never leave with the milestone above it. sync proposes rather than acts, because git knows which branches were merged but not which of them were merged finished.

More: docs/finished-work.md.


Commands

Command What it does
init [--project N] [--repo URL] [--outputs F] [--hook] [--action] [--empty] Creates .devtree/tree.yaml, .gitattributes, and the first diagram
add "Title" [-p ID] [-s STATUS] [-b BRANCH] [-i N] [--pr N] [-o WHO] [--tags a,b] [-n NOTE] [--id ID] Adds a task
set ID [--title T] [-s ...] [-p ...] [...] Changes fields; only the flags you pass are touched
done ID [ID...] Marks tasks done
mv ID PARENT|root Re-parents a task
rm ID [--cascade] Deletes a task; without --cascade its children move up to its parent
ls [-s STATUS] Prints the tree in the terminal
board [-s STATUS] Prints the work grouped by status
open ID [--issue|--pr|--branch] [--print] Opens what a task points at
archive [ID...] [--all] [--list] Moves finished branches of the plan into the archive
restore ID [ID...] Brings archived work back
sync [--apply] Closes tasks whose branch git has already merged
history [--limit N] Reads past versions of the plan out of git and shows how far along it was
serve [--port N] [--host H] [--open] Opens the local editor on 127.0.0.1
render [--file F] [--quiet] Regenerates every output
check [--strict] Validates the plan — for CI and hooks
install hook|action|gitlab|all Installs the pre-commit hook, the GitHub Action, or the GitLab job
outputs Prints the files the diagram is written to

Flags may come before or after the title, so both of these do the same thing:

devtree add "Authentication" -p mvp -s wip
devtree add -p mvp -s wip "Authentication"

Narrowing the view

ls and board take the same four filters, and they combine:

devtree ls -s blocked              # one status
devtree board -o ann               # one person's work
devtree ls --tag billing,payments  # any of these tags
devtree board --root mvp           # one branch of the plan

render takes --root too, so a milestone can have a picture of its own:

devtree render --root mvp --file docs/mvp.svg

And when you want the thing itself rather than the plan:

devtree open authentication          # its pull request, issue, or branch
devtree open authentication --print  # print the URL instead of opening it

Statuses

todo, in_progress, blocked, done, dropped — with the shorthand each one accepts

The canonical spelling is what lands in the file, whichever shorthand you type.


Where the diagram goes

The plan lists its own output files, and the name decides the drawing:

File name What gets written
TREE.md, README.md the Mermaid block, between <!-- devtree:begin --> and <!-- devtree:end --> markers
docs/tree.svg devtree's own drawing of the tree, light palette
docs/tree-dark.svg the same, dark palette
docs/board.svg the board
docs/plan.html a page you can click: links, filters, tooltips
outputs: "README.md, docs/tree.svg, docs/tree-dark.svg, docs/board.svg, docs/plan.html"

Everything outside the markers is left exactly as you wrote it, and re-rendering an unchanged plan rewrites nothing at all. Point a <picture> at a light and dark pair and GitHub switches it with the reader's theme.

Three things in the drawing move, and each one is information: a dash travels down the edges leading into work in progress, a glyph turns while a task is in flight and breathes while it is blocked, and progress bars grow in once. Readers who ask their system for less motion — and anyone printing — get a still picture.

File naming rules, palettes, the animation vocabulary, and the content security policy all of it has to survive: docs/svg-output.md.

The one thing a diagram cannot do

Neither backend can carry a link: GitHub's Mermaid ignores click, and an SVG served as an image is sandboxed. So there is a third one. Name an output .html and devtree writes a page where every task that points somewhere is a link to its pull request, issue, or branch — with a tree view, a board view, filters by status, owner and tag, and notes as tooltips.

It is one self-contained file with no script, no fonts and no images: the whole interface is CSS built on :has(). Open it from a checkout, drop it on a shared drive, or point GitHub Pages at it. This repository's own is docs/plan.html — see docs/html-export.md.


Automation

devtree install hook      # validate and re-render before every commit
devtree install action    # fail a pull request whose diagram is out of date

The hook keeps your own commits honest; the Action keeps everyone else's honest without requiring them to install anything. A teammate without devtree is never blocked — the hook notices the binary is missing and steps aside. On GitLab, devtree install gitlab writes a job that runs the published container, so the pipeline needs no toolchain at all. Line by line: docs/automation.md.

Where you have been

The plan has been in the repository all along, so its own past is already recorded. Nothing had to be tracked to read it back:

devtree history
Storefront — 3 revision(s) of the plan

2026-08-14  ░░░░░░░░░░░░░░░░░░░░  0/2
2026-08-15  ██████░░░░░░░░░░░░░░  1/3  +1 done  +1 planned
2026-08-16  ████████░░░░░░░░░░░░  2/5  +1 done  +2 planned

2 of 5 done, up 2 since 2026-08-14
☐ 2 not started   ◐ 1 in progress   ✔ 2 done

Documentation

This page is the tour. docs/ is the detail underneath it.

Getting started A first plan, from an empty repository to a diagram in the README
The file format Every field, every rule, and what the parser refuses
The board Working by status instead of by structure
Finished work Archiving, restoring, closing tasks from merged branches
Automation The pre-commit hook and the GitHub Action, line by line
SVG output File naming, palettes, the animation vocabulary, the CSP it survives
The editor The local editor, the drawing you can edit, and the motion in it
Drawing components The twenty components every diagram is assembled from
The container Running devtree without installing anything
Architecture The layering, the rules that hold it, and how it is tested

Limitations

  • The storage format is a strict subset of YAML — a flat list of scalar fields. Anchors, multi-line block scalars, and nested mappings are rejected, with the line number.
  • Nothing rendered into a README is clickable: GitHub's Mermaid ignores click directives, and an SVG served as an image is sandboxed. Links live in the collapsed table under the Mermaid block.
  • Text in the SVG output is measured by estimate rather than by font metrics — shipping real metrics would mean shipping a font. Cards are sized a few pixels generously to compensate.
  • Very wide trees (hundreds of nodes) render slowly in the browser. Split them across several output files with --outputs.

devtree's own plan

Rendered from .devtree/tree.yaml in this repository, on every push:

devtree's own development tree

The same plan as a board — docs/assets/board.svg — as a page you can click — docs/plan.html — and as a Mermaid block, in TREE.md. One file, five renderings, none of them maintained by hand.


Contributing

Issues and pull requests are welcome. CONTRIBUTING.md covers the checks CI runs, which package new code belongs in, and the two rules the layering depends on.

License

MIT © SergeyLubivui-dev

The vector glyphs in internal/icons are vendored from Reicon, also MIT — see NOTICE.

About

Tree-shaped development planning that lives in your repository. One dependency-free Go binary turns .devtree/tree.yaml into a Mermaid diagram GitHub renders natively, with a pre-commit hook and a CI check that keep the diagram honest.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages