Sprig

The toolchain

A toolbelt, not an app.

Sprig is a file format first. The tools around it are small, read the same files, and agree with each other because they share one parser. None of them needs an account, a server or a config file.

No release is published yet, but the command line installs from source with Rust today. Commands marked Today are in it; the rest arrive milestone by milestone.

cargo install --locked --git https://github.com/oddurs/sprig sprig-cli
~/bakery
$ sprig next --limit 6 --today 2026-10-01
  ~ Break clause at year three      Oct 5 · in 4d  !!!
  ~ Equipment loan paperwork        Oct 7 · in 6d  !!
  ~ Ventilation plan with the eng…  Oct 12 · in 11d
  ~ Logo, second round              Oct 14 · in 13d
  ? Who pays for the grease trap?   Oct 5 · in 4d  !!!
  - Get a third quote               Oct 2 · in 1d  !!

6 of 20 ready · 12 waiting · 2 questions

One core, every surface.

The parser is a Rust library that touches no files, clock or network. It compiles to a native binary and to WebAssembly, so the terminal, your editor, a coding agent and this site give the same answer about the same file.

PlaygroundToday

Edit a plan and watch it compute, in this browser. It runs sprig-core, the same Rust parser as the sprig command, compiled to WebAssembly.

sprigToday

The command line: what’s next, what’s broken, what’s blocked, and one-line writes. It installs from source; the first release is v0.1.

EditorsToday

sprig lsp serves any editor that speaks LSP: problems as you type, completion, go to definition, hover and ticking. A VS Code extension and a Tree-sitter grammar follow in v0.2.

sprig mcpv0.3

Coding agents read the plan, find ready work and tick it, as file edits you review.

sprig tuiv0.4

A folder of plans on one terminal screen, with vim keys.

Small verbs, one question each.

Every command reads a folder of plans and answers one question, in text a person can read and a pipe can parse; writing is a line in your editor. The screens below are sprig-core’s output for the example bakery plans, with the date pinned by --today the way the tests will run.

Read

answer a question, change nothing

sprig nextToday
Open, unblocked work: in progress first, then priority, then due date.
sprig treeToday
The plan as Sprig reads it, grafts expanded, progress rolled up. --summary for the whole folder on one screen.
sprig why <ref>Today
What an item waits on, all the way down, with file and line.
sprig find <query>Today
Search by text, @who, #tag, is:blocked, due:<fri.

Check

fail loudly, fix nothing silently

sprig checkToday
Broken links, loops and unknown anchors as file:line:col. Exit 1 on any error.
sprig fmtToday
Two spaces per level, typed dates expanded to ISO. --check for CI.

Write

everything else is a line in your editor

sprig tick <ref>Today
Done, or reopen; --mark sets any status. A recurring item moves its due date instead.

Connect

other tools, other formats

sprig exportToday
The resolved tree as JSON, due dates as an iCalendar feed, the dependency graph for Graphviz or Mermaid.
sprig importToday
Markdown checkboxes in, a Sprig file out.
sprig lspToday
A language server for any editor: problems as you type, completion, go to definition, hover and ticking.
sprig mcpToday
The plans, served to coding agents.
sprig generateToday
Completion that knows your anchors and people, and a man page.
$ sprig tree kitchen.sprig
Kitchen fit-out                             1/10  █░░░░░░░░░
├─ - Design  1/2
│  ├─ x Layout sketch
│  └─ ~ Ventilation plan with the engineer  Oct 12
├─ # Equipment  0/3
│  ├─ - Deck oven, three decks  !!  0/2
│  │  ├─ - Get a third quote  Oct 2
│  │  └─ - Place the order  waits on Equipment loan paperwork
│  ├─ - Spiral mixer, 40 litres
│  ├─ / Proofing cabinet
│  └─ > Espresso machine
└─ - Build  waits on Design, Sign the lease  0/5
   ├─ - Strip out
   ├─ - Plumbing and drains
   ├─ - Three-phase electrics
   ├─ - Tiling
   └─ - Install equipment
$ sprig why Tiling
- Tiling                    kitchen.sprig:22
└─ inside Build, which waits on:
   ├─ - Design                    kitchen.sprig:3  @teo
   │  └─ 1 of 2 done, nothing blocks it
   └─ - Sign the lease            lease.sprig:13  @dana
      ├─ ~ Negotiate terms        lease.sprig:6  @dana
      │  └─ 1 of 3 done, nothing blocks it
      └─ - Change-of-use permit   lease.sprig:11  @dana
         └─ ready to start

Tiling isn’t blocked on its own. Its parent is, and the chain crosses into another file.

$ sprig check
bakery.sprig:19:3: error[S0101]: no file named kitchn.sprig
lease.sprig:13:42: error[S0201]: no item ^permt in lease.sprig

2 errors in 2 files · exit 1

Two mistakes planted in a copy of the plans. Editors and CI jump straight to file:line:col.

$ sprig tree --summary --today 2026-10-01
bakery     ██░░░░░░ 9/40   12 waiting  
groceries  ██░░░░░░ 3/10               
kitchen    █░░░░░░░ 1/10   6 waiting   
launch     ██░░░░░░ 4/19   4 waiting   
lease      ███░░░░░ 2/6    1 waiting   

$ sprig tree --summary --oneline
sprig 23% · 20 ready · 12 waiting

The rules every tool keeps.

These decide every command. Where a feature would break one, the feature loses.

The file is the truth

Tools compute progress and blockers; they never store them. Delete every tool and the plan still reads.

A write touches one line

tick, the TUI and the MCP server change only the bytes they mean to, so git diff shows exactly what happened.

Three kinds of output

Aligned for people, tab-separated with --plain, and the whole resolved tree as JSON from sprig export. The --plain columns are covered by the stability policy.

Exit codes mean something

0 fine, 1 the answer is no, 2 you asked wrong. Scripts branch on them.

Every answer is reproducible

--today pins the date, so any output can be tested, diffed and pasted into a bug report.

Nothing to set up

No config file, no daemon, no plugins, no network. Flags and environment variables only.

Why there’s no config file

Colour is a courtesy.

Every screen takes its colour from the nine marks and nothing else. Set NO_COLOR and nothing is lost, because the character already is the status.

colour
$ sprig tree lease.sprig
Lease                                       2/6  ███░░░░░░░
├─ x Shortlist three spaces
├─ ~ Negotiate terms  !!!  Oct 5  1/3
│  ├─ x Eight weeks rent-free for the fit-out
│  ├─ ~ Break clause at year three
│  └─ ? Who pays for the grease trap?
├─ - Change-of-use permit
└─ - Sign the lease  waits on Negotiate terms, Change-of-use permit
NO_COLOR=1
$ NO_COLOR=1 sprig tree lease.sprig
Lease                                       2/6  ███░░░░░░░
├─ x Shortlist three spaces
├─ ~ Negotiate terms  !!!  Oct 5  1/3
│  ├─ x Eight weeks rent-free for the fit-out
│  ├─ ~ Break clause at year three
│  └─ ? Who pays for the grease trap?
├─ - Change-of-use permit
└─ - Sign the lease  waits on Negotiate terms, Change-of-use permit

Pointing at an item from the shell.

Commands that act on one item take a ref. The forms run from exact to forgiving, and an ambiguous ref lists its candidates and exits 2 rather than guessing.

RefMeansExample
^signedAn anchor, searched across the foldersprig tick ^signed
lease^signedAn anchor in one filesprig why lease^signed
lease.sprig:13A line, the way compilers print onesprig tick lease.sprig:13
"grease trap"Words from exactly one item’s textsprig tick "grease trap"
-Refs on stdin, one per linesprig next --plain | cut -f1 | sprig tick -

The same verbs, on one screen.

sprig tui shows the tree, what’s next and the agenda, with vim keys. Its writes go through the same one-line edits as the commands, and it reloads when an editor or an agent changes a file underneath it. This one runs sprig-core in the browser: focus it and use the keys.

1 tree2 next up3 agenda~/bakery · Oct 1
›▾ # Money2/4
x Business plan v3
x Bank meeting
~ Equipment loan paperworkOct 7
- Supplier credit line ⧗
- Weekly numbers to the bankOct 2
▾ + Lease2/6
x Shortlist three spaces
▾ ~ Negotiate terms1/3
x Eight weeks rent-free for the fit-out
~ Break clause at year three
? Who pays for the grease trap?
- Change-of-use permit
- Sign the lease ⧗
▾ + Kitchen fit-out1/10
▾ - Design1/2
x Layout sketch

# Money

at bakery.sprig:9

status doing

owner @dana

progress 2 of 4 done

Budget is 180k. Anything over 10k needs a second quote.

bakery.sprig 9/40 done · 20 ready · 12 waiting? help

Ticks change this page’s copy of the plans, nothing on disk. The dates are pinned to 1 October 2026, like the screens above.

j k
move
h l
fold, unfold
x
tick
~
mark doing
1 2 3
tree, next up, agenda
/
filter
?
help

Pipes, not plugins.

Plain output and meaningful exit codes let Sprig work with the tools already on the machine, so it needs no plugin system.

Pick and tick with fzf

The first column of --plain is always a ref.

$ sprig next --plain | fzf | cut -f1 | sprig tick -

Gate a commit

A pre-commit hook that checks only the plans that changed.

$ git diff --cached --name-only -- '*.sprig' | xargs sprig check --strict

Deadlines in any calendar

Regenerate on a timer; the calendar subscribes to the file.

$ sprig export --format ics > ~/Sync/plans.ics

Your next task in the prompt

For Starship, tmux, or any prompt that runs a command.

$ sprig next @me --limit 1 --plain | cut -f2