Skip to content

project

A project is something rigger keeps a record of: almost always a repository, sometimes a folder of work with no repository, and once in a while a place the record keeps for itself. Versions, tasks, events and documents attach to it whichever it is; what differs is whether git is asked.

Kind What it is git
repo a checkout on disk sync reads its tags and commits
folder a directory of work with no repository - texts, notes, anything made of files never asked; the line’s skill offers it like any product
service a place the record keeps for itself (project service) never asked; not offered to work on
rigger project add <PATH> [--name <NAME>]

Records the repository at PATH. The name is the directory name, because that is what a project is called in conversation - a manifest often declares something else, such as the crate sample-cli for the product sample, or a *-workspace root. Pass --name when the directory is not it either. The origin remote is read from the repository’s git config when there is one.

Terminal window
$ rigger project add C:\dev\sample
Recorded 'sample' at C:\dev\sample
remote: https://github.com/acme/sample.git

A directory with no .git is recorded as a folder: work made of files, with no repository. sync and doctor do not ask git about it, and nothing nags about a sync it cannot have; the line’s skill lists it, and its own skill is written from the folder template. The registry export --line publishes leaves it out - a folder has no public repository to point at.

Terminal window
$ rigger project add C:\notes\stories
Recorded 'stories' at C:\notes\stories
no repository: a folder of work, and sync will not ask git about it
nothing says what it is; give it a line with `rigger project set stories --about "<text>"`

The kind is read from the directory rather than asked for, so it cannot disagree with the disk when it is written. When git arrives in a folder later, record the same path again and it becomes a repository - the same project, with its history:

Terminal window
$ rigger project add C:\notes\stories
'stories' has a repository now: recorded as one, and sync reads it from here on

Otherwise a path recorded before, or a name already taken, is refused with the existing project named in the message.

rigger project list [--json]
Terminal window
$ rigger project list
sample C:\dev\sample

A retired project is listed with the day it left: attic C:\dev\attic (retired 2026-10-13). With --json, an array of the objects project show --json prints, the retired among them.

Field Type Meaning
[] object One project per element, shaped as in project show.
[].id integer The project’s id in the record.
[].name string The name the project is called by.
[].path string The repository’s or the folder’s directory, or the name itself for a service project.
[].remote string or null The origin remote from git config; null when there is none.
[].created_at string When the project was recorded, in RFC 3339 UTC.
[].tier string or null The release tier: A, B, C or out; null until project tier sets one.
[].rhythm_weeks integer or null Weeks meant to go between releases; null until a tier or --rhythm sets it.
[].kind string repo for a repository, folder for a directory of work with no repository, service for a place the record keeps for itself.
[].hub_path string or null The directory of the project’s hub; null until a hub is imported or exported.
[].gate string or null The command that says the project is fit to commit; null when none is set.
[].mark_code string or null The two-lowercase-letter code of the mark, unique across the line; null when no mark is recorded.
[].accent string or null The colour the product owns, as #RRGGBB; null when not recorded.
[].accent2 string or null The second colour, as #RRGGBB; null when not recorded.
[].form string or null What shape of thing the product is: cli, desktop, web, library or service; null when not recorded.
[].docs_url string or null Where the documentation lives; null when there is no site.
[].on_session_end string or null The command run when a sitting closes; null when none is set.
[].retired_at string or null When the project was retired, in RFC 3339 UTC; null while it is in the work.
[].retired_by integer or null The id of the decision that retired it, which rigger event reads; null while it is in the work.
[].about string or null The line the record holds about the project, written by project set --about where no manifest describes it; null otherwise.
rigger project show <NAME> [--json]
Terminal window
$ rigger project show sample
sample
path: C:\dev\sample
remote: https://github.com/acme/sample.git
since: 2026-09-04T07:41:10Z
$ rigger project show sample --json
{
"id": 1,
"name": "sample",
"path": "C:\\dev\\sample",
"remote": "https://github.com/acme/sample.git",
"created_at": "2026-09-04T07:41:10Z",
"tier": "A",
"rhythm_weeks": 2
}

Timestamps are UTC in RFC 3339. tier and rhythm_weeks are null until project tier sets them.

The commands that record or change a project - add, service, set, mark, tier, retire and unretire - print the same object under --json.

Field Type Meaning
id integer The project’s id in the record.
name string The name the project is called by.
path string The repository’s or the folder’s directory, or the name itself for a service project.
remote string or null The origin remote from git config; null when there is none.
created_at string When the project was recorded, in RFC 3339 UTC.
tier string or null The release tier: A, B, C or out; null until project tier sets one.
rhythm_weeks integer or null Weeks meant to go between releases; null until a tier or --rhythm sets it.
kind string repo for a repository, folder for a directory of work with no repository, service for a place the record keeps for itself.
hub_path string or null The directory of the project’s hub; null until a hub is imported or exported.
gate string or null The command that says the project is fit to commit; null when none is set.
mark_code string or null The two-lowercase-letter code of the mark, unique across the line; null when no mark is recorded.
accent string or null The colour the product owns, as #RRGGBB; null when not recorded.
accent2 string or null The second colour, as #RRGGBB; null when not recorded.
form string or null What shape of thing the product is: cli, desktop, web, library or service; null when not recorded.
docs_url string or null Where the documentation lives; null when there is no site.
on_session_end string or null The command run when a sitting closes; null when none is set.
retired_at string or null When the project was retired, in RFC 3339 UTC; null while it is in the work.
retired_by integer or null The id of the decision that retired it, which rigger event reads; null while it is in the work.
about string or null The line the record holds about the project, written by project set --about where no manifest describes it; null otherwise.
rigger project tier <NAME> <A|B|C|out> [--rhythm <WEEKS>]
rigger project tier --suggest [<NAME>] [--json]

Where a project sits in the release rotation, and how often it should ship. The tiers are the ones the line already works to: A carrying products that are released and used every day, B growing ones whose code works but whose circuit is not closed, C declared ones with a name and a plan and no product yet.

Terminal window
$ rigger project tier sample A
sample is tier A - carrying - released, in the registries, used every day
a release every 2 weeks

Each tier carries a rhythm of its own - two weeks for A, four for B, six for C - so setting one is a single word in the common case. --rhythm is for the project that keeps its tier’s company but not its pace.

out is for a project deliberately outside the rotation: it is worked on when asked, and next never says it is behind. That is a decision, not an omission - a project given out and a rhythm is still left alone.

A project with no tier at all is out by omission, and is equally left alone: rigger does not invent a schedule that nobody asked for.

rigger project tier --suggest [<NAME>] [--json]

A tier for each project, read from the releases of the last cycle (seven weeks, as retro --cycle counts them). It sets nothing: each line that would move prints the project tier command to paste.

Terminal window
$ rigger project tier --suggest
From 2026-W33 to 2026-W39 (7 weeks) - nothing is set until you run the command
idle stalled in B - 0 shipped, B asks 1
rigger project tier idle C
racing outgrew C - 12 shipped, C asks 1
rigger project tier racing A
fresh no tier yet - 2 shipped
rigger project tier fresh B
steady holds A - 3 shipped, A asks 3
aside out by decision - 4 shipped
Verdict What the numbers say Suggested
stalled the tier asked for releases and none came one tier down; C goes out
outgrown twice the tier’s pace or more the tier the pace describes; a racing A keeps A with a shorter --rhythm
holds the tier describes what happened the same tier
out out of the rotation by decision left out - the numbers are not held against it
untiered no tier yet the slowest tier whose rhythm the pace keeps; with nothing shipped, C if it has a plan and out if not

A stall moves one step and a race as far as the pace goes, on purpose: stalling is a fact about the last weeks rather than a verdict on the product, and a product shipping forty times what its tier asks is not one step away from its tier. What would move is listed first, stalls before the rest. --json gives each project’s verdict, suggested, current, rhythm_weeks, shipped and expected.

With --suggest, --json prints the window and one suggestion per project.

Field Type Meaning
from string The first week of the window, as YYYY-Www.
to string The last week of the window, as YYYY-Www.
weeks integer How many weeks the window spans.
suggestions array One element per project, the ones that would move first.
suggestions[] object One project’s suggestion.
suggestions[].project string The project’s name.
suggestions[].current string or null The tier now: A, B, C or out; null when none is set.
suggestions[].verdict string What the numbers say: stalled, outgrown, holds, out or untiered.
suggestions[].suggested string The tier suggested: A, B, C or out.
suggestions[].rhythm_weeks integer or null A rhythm to go with the tier when its own would not fit; null otherwise.
suggestions[].shipped integer Versions shipped in the window.
suggestions[].expected integer or null Releases the current tier asks for over the window; null when it asks for none.
rigger project set <NAME> [--gate <COMMAND>] [--no-gate]
[--on-session-end <COMMAND>] [--no-on-session-end]
[--about <TEXT>] [--no-about]

Sets what the record keeps about a project beyond what git can tell it.

The command that says a project is fit to commit: what CI runs, spelt for a shell.

Terminal window
$ rigger project set sample --gate "cargo fmt --all --check && cargo clippy --all-targets -- -D warnings && cargo test"
sample: gate is `cargo fmt --all --check && cargo clippy --all-targets -- -D warnings && cargo test`
Run it with: rigger gate sample

It lived in seventeen skill files before, one copy each, and drifted from the workflow it was supposed to mirror. Stated once, it is printed by the context packet and run by rigger gate.

With neither flag, set says what the gate is rather than doing nothing quietly:

Terminal window
$ rigger project set sample
sample: gate is `cargo test`

--no-gate takes it off. An empty --gate is refused: an empty gate is not a gate.

The command to run when a sitting on this project closes.

Terminal window
$ rigger project set rhapsod --on-session-end "pnpm publish:novellas"
rhapsod: a closing session runs `pnpm publish:novellas`
It runs after the sitting is written down, and its outcome is recorded.

Some projects end a session by doing something: publishing what was written, running a linter over it, pushing a stand. That belonged to a list in a skill file which the assistant had to remember at exactly the moment it was running out of context - which is when it is least likely to remember anything. Stated here, it happens.

It runs after the session is written down, because what it does belongs to the sitting that has just been recorded. The outcome is recorded as a change, with the command and how long it took.

A red result does not fail the close. The session is already over and already written down; refusing to end it would leave a sitting open for ever because a publish step could not reach the network. So it is said out loud and listed among what the ritual still asks for - visible, not fatal:

Terminal window
$ rigger session end rhapsod
Session on rhapsod closed, open since 2026-09-19T08:12:04Z.
...
pnpm publish:novellas: red (exit 1) in 4 seconds
before you stop:
`pnpm publish:novellas` came back red (exit 1) in 4 seconds

--no-on-session-end takes it off. It is a field of the project rather than a setting of the profile: what has to happen when a sitting on one project ends has nothing to do with the others.

One line about the project, for a project whose manifest says nothing.

Terminal window
$ rigger project set stories --about "A library of short stories, one idea each"
stories: "A library of short stories, one idea each"

What a project is has always come from the manifest that publishes it: the description of a manifest at the root - a Cargo.toml’s [package], then its [workspace.package], then a package.json - and only when the root says nothing, the workspace member that ships (the crate or package named after the project, or <project>-cli). A root speaks for the repository and a member for its part: read the other way round, a desktop app was described as its command-line crate. A folder of texts has no manifest, and its skill told every session it was “a project recorded in rigger”. The line is what the project’s skill says in its description, what the line’s skill lists beside its name, and what show prints under it.

It is refused where a manifest already describes the project, and the refusal quotes it: the manifest is what the registries publish, and a second line in the record would be a second truth that the first edit to either would make disagree. Should a manifest gain a description later, the manifest’s is the one in force.

Terminal window
$ rigger project set sample --about "Something else"
error: sample is described by its manifest: "A sample product"
Change the description there; a second line in the record would be a second truth.

The line is one line, and angle brackets are refused - it goes into a skill’s description, and a < there breaks the catalogue an assistant parses for every skill around it. With no flags, set says which line is in force and where it comes from. --no-about takes it off.

rigger project mark <NAME> [--code <XX>] [--accent <#RRGGBB>] [--accent2 <#RRGGBB>]
[--form <FORM>] [--docs <URL>] [--clear]

How a product looks from outside: the two-letter code of its mark, the colour it owns, what shape of thing it is, and where its documentation lives.

Terminal window
$ rigger project mark sample --code sa --accent "#3FA873" --form cli --docs https://example.github.io/sample/
sample: mark recorded.
code sa
accent #3FA873
form cli
docs https://example.github.io/sample/

This existed in three places and agreed in none: a table in a notes vault, a constant in the project generator, and whatever a README happened to say. A hardcoded list does not know it is stale. Recorded here, it is published by export --line and read by everything that needs it.

The forms are cli, desktop, web, library and service - a closed list, because a generator switches on it and a form spelt two ways is a branch that silently does not run. A code is two lowercase letters and unique across the line, which the schema holds rather than the habit. A colour is #RRGGBB.

What is not named keeps what it had, so --form cli states the form and not the whole mark; --clear takes the mark off. With no flags, mark says what is recorded.

rigger project retire <NAME> --why <TEXT>
rigger project unretire <NAME> [--why <TEXT>]

Takes a project out of the work for good, keeping everything it has done readable.

Terminal window
$ rigger project retire attic --why "Folded into sample; nobody climbs up there any more."
attic is retired, as of 2026-10-13: Folded into sample; nobody climbs up there any more.
left as they were: 1 question, 1 wish, 1 open task - kept in its history, gone from the inbox and the plan
gone from the line's skill, the registry, the calendar, the rotation, the inbox and sync
`rigger show attic` still reads it; nothing new is recorded against it
`rigger project unretire attic` brings it back
C:\Users\you\.claude\skills\line\SKILL.md now lists 1 project

The tier out is not this. out is a project worked on when asked: the line’s skill goes on offering it, the calendar goes on giving it a row, the inbox goes on asking its questions. A retired project is one nobody will work on, and every list that looks ahead leaves it out:

Leaves it out Still reads it by name
the line’s skill - an installed one is written again on the spot show, which says so in place of the tier, and the context packet, which opens with the day it was retired and the decision that says why
the registry export --line publishes event, why, find and export
calendar and its --ics, next, week, release-day retro - what it shipped happened, and what it planned before it left was planned; a version aimed at a week after it left is not counted missed, and no tier is held against it
the tier signals, project tier --suggest, and the pairs link warns have parted link list <name>
inbox - its questions wait for nobody now - and digest digest with its name; its questions and wishes in its own packet
sync, adopt and doctor --hubs project list, which marks it (retired YYYY-MM-DD); doctor counts it
the resources the MCP server lists every MCP tool that reads

--why is required: a retirement is a decision, and it is recorded as one against the project before the door closes. What the project leaves open - questions, wishes, tasks - is counted and left as it was, part of its history rather than tidied away on its behalf.

Nothing new is recorded against it afterwards. note, wish, session start, open, gate, version add and plan, project tier, link add, doc add, skill, sync and import refuse it by name; so do the MCP tools that write. Below them the database refuses on its own: new events, sittings, stages and tasks of a retired project are rejected by the schema, whatever writes them. What it already holds can still be edited - a wish sorted with resolve, a task closed - so that it can be tidied; an answer to one of its questions is a new decision, and is refused.

Terminal window
$ rigger note attic --kind decision "Paint it after all"
error: attic is retired since 2026-10-13: its history reads, but nothing new is recorded against it; `rigger project unretire attic` brings it back

A sitting still open on the project is refused first - close it with session end. A place the record keeps for itself (project service) is not in the work and cannot be retired. Retiring a retired project changes nothing and says so.

unretire brings it back, with the tier and rhythm it had. --why is optional there; the return is recorded as a decision either way.

Terminal window
$ rigger project unretire attic --why "The ladder arrived"
attic is back in the work
its tier is A, as it was; `rigger project tier` moves it

Under --json, both print the project as project show does.

Records a place the record keeps for itself: a project with no repository, and none coming.

Terminal window
$ rigger project service line
Recorded 'line' as a place the record keeps for itself
no repository: sync will not ask git about it

There is one thing this exists for. A retro is about every project at once, so its summary belongs to none of them - filing it under one would make it findable from the wrong place and invisible from the rest.

Such a place is not a repository that happens to be missing, and saying so matters: recorded as an ordinary project it made sync warn on every run that there was no git to read, and doctor list it for ever among the projects waiting to be synced - the record nagging about a project working exactly as intended. Now sync does not ask git about it, and doctor does not count it as unsynced.

Everything else works on it as usual: events, questions, wishes, digest, find and the context packet.

  • init - the database project writes to.
  • doctor - how many projects are recorded.
  • calendar - where a tier and its rhythm are read.
  • retro - what a service project is made for, and what it keeps of a retired one.
  • gate - running the command project set --gate records.