Skip to content

Sprig in the shell

Sprig has no plugins. It doesn’t need them, because every command can feed the tools already on your machine:

  • --plain prints tab-separated lines whose first field is always a ref that another command accepts.
  • --json prints the tree format.
  • Exit codes mean something: next exits 1 when nothing is ready, find when nothing matches, and check when a plan is broken.

The recipes below run in the bakery example. CI runs each one that needs no keyboard, so they stay true. The columns of each --plain command are listed in the tools document.

Choose from what’s ready, and tick what you chose:

Terminal window
sprig next --plain | fzf | cut -f1 | sprig tick -

tick - reads refs from standard input, one per line, so fzf --multi ticks several at once.

The file is the truth, so most changes are a line typed in an editor. The one that is fiddly by hand has a command: ticking, which moves a recurring item to its next date and can set any mark.

Terminal window
sprig tick ^logo
sprig tick ^design --mark '~'

Each prints the line it changed, and then, on standard error, the items that stopped waiting on it. fmt writes typed dates out, so due:fri typed in an editor lands in the file as a date.

A Starship custom module, shown in folders with a PLAN.sprig:

[custom.sprig]
command = "sprig next --who me --limit 1 --plain | cut -f3"
when = "test -f PLAN.sprig"

The command on its own:

Terminal window
sprig next --who teo --limit 1 --plain | cut -f3

tree --summary --oneline fits in tmux’s status line, and exits 1 when anything is late, for a prompt that wants to turn red:

Terminal window
set -g status-right '#(cd ~/plans && sprig tree --summary --oneline)'
Terminal window
sprig tree --summary --oneline

A pre-commit hook that refuses a commit that breaks a plan it touches, and reads only the files that changed. Save it as .git/hooks/pre-commit and make it executable:

#!/bin/sh
git diff --cached --quiet -- '*.sprig' ||
git diff --cached -z --name-only --diff-filter=ACMR -- '*.sprig' |
xargs -0 sprig check --strict

In CI, the Sprig action checks the plans too, and writes a summary of what the pull request did to them.

find takes words and filters (@who, #tag, is:blocked, due:<fri). With --json, each item carries what it waits on:

Terminal window
sprig find is:blocked --json |
jq -r '.[] | select(.node.waits_on)
| "\(.node.label)\t\([.node.waits_on[] | .label // "starts \(.start)"] | join(", "))"'

A wait is either something the item is after:, with its label, or a start: date that hasn’t come yet.

export --format ics writes the dated work as an iCalendar file. Regenerate it on a timer, and point a calendar at the file:

Terminal window
sprig export --format ics > plans.ics
Terminal window
# crontab -e: every hour, into a folder your calendar can subscribe to
0 * * * * cd ~/plans && sprig export --format ics > ~/Sync/plans.ics

Each event’s UID comes from the item’s anchor when it has one, so renaming an item moves its event rather than adding another. In the terminal, sprig find is:open 'due:<=+2w' lists the same work, and sprig tui shows it by day.

Graphviz does the drawing:

Terminal window
sprig export --format dot | dot -Tsvg > plan.svg

--format mermaid writes the same graph for a Markdown file on GitHub, inside a ```mermaid block.

import converts a Markdown checklist, a todo.txt file, or GitHub issues from the gh command, and prints Sprig:

Terminal window
sprig import TODO.md > PLAN.sprig
gh issue list --json number,title,state,stateReason,labels,assignees,milestone > issues.json
sprig import issues.json --from github > issues.sprig