benchbook
↑↓ navigate↵ openDocs · Wiki · Contract
GitHub
DocsIn practiceProjects

Projects

Projects

A project page tracks something you’re building. This is the page type that diverges most from the pattern this system came from, whose examples are research, reading and team knowledge — all of which are about things you’re learning.

Building is a different shape. It has state, it has a lifecycle, and its most valuable content isn’t the summary — it’s the decision record, including the options that lost.


Required sections

Every project page carries these, in order, and the lint pass checks for them:

SectionContent
## Summary2–4 sentences. What this is and why.
## RelationsTyped links to the entities and projects this one touches. Required while the project is active or planned, directly after ## Summary. See below.
## Use CasesWhat it needs to actually do, concretely.
## Hard- and SoftwareOptions considered, in a table, with pros and cons — then a “Selected” subsection. Supporting infrastructure links to entity pages.
## Plan / PhasesImplementation phases with checkboxes. Gated — see below.
## Open QuestionsUnresolved decisions blocking progress.
## LogChronological, append-only.

Deployed software projects additionally require ## Version Control, ## Backup Concept and ## Cron Jobs. Those three exist because they are precisely what you fail to write down and desperately need eighteen months later, at which point the answer is a forensic exercise.

## Relations on a project

Projects carry the same triplet table entity pages do — Subject | Predicate | Object, with predicates from the controlled vocabulary — and it answers the question you actually have when you reopen a project after two months: what does this touch?

## Relations

Full neighbourhood, including relations stored on other pages: `./scripts/relations.py <slug>`

| Subject | Predicate | Object |
|---|---|---|
| office-air-quality-sensor | evaluates | [ESPHome](../knowledge/entities/esphome.md) |

Three things about it are deliberate and easy to get wrong:

It’s required only while the project is open. Requiring it on completed and abandoned pages too would mean an error on every historical page in the wiki, and since errors block commits, that wedges the repo to document something of purely historical interest. Scope a new rule to the pages it helps.

A pointer-only section is complete. Each fact is stored exactly once, on whichever page reads naturally — so most of an established project’s relations already live on the entity pages that name it, and its own table is legitimately empty. The pointer line is the section doing its job. In the source wiki, 25 of 40 open projects have no page-local row at all.

Never invent a row to avoid an empty table. One true row beats five plausible ones. This is the rule the whole structure depends on: a sparse graph is merely incomplete, while a graph with inferred edges is wrong in a way you cannot detect later — nothing marks which rows were guesses.

Because edges are stored once, reading a project page shows you about half of what the wiki knows about it. ./scripts/relations.py <slug> reads both directions, and it’s the first thing the wiki-project-open and wiki-project-review skills run.

Which predicate? evaluates is the general project→entity one — assessing, adopting, rejecting or changing, resolved or open. Reach for uses when the project depends on the entity to run, builds when it produces it, replaces when it supersedes it. Otherwise evaluates.


The ## Hard- and Software options table is quietly the most valuable section in the whole system. It’s where “why not the obvious alternative?” gets answered, permanently, at the moment you actually know the answer.


The plan approval gate

The strongest human-in-the-loop rule in the system, and the one I’d most encourage copying:

While a project is in planned status, ## Plan / Phases contains only a high-level phase list marked “Deferred — awaiting manual plan approval.” No implementation work may begin — no code, no files, no API calls — until the human explicitly approves the plan. On approval, status moves to active and the plan is written out in full.

The problem this solves is specific to agentic tools and immediately recognisable: you describe an idea, and forty seconds later there are eleven files. They’re plausible. Some are even good. But you never made the architectural decisions — they were made for you, at speed, and now they’re load-bearing and you’re reviewing them backwards.

The gate forces the plan to be a separate, reviewable artifact from the execution. It costs one round trip and it is worth it every single time.


Status lifecycle

planned → active → deployed / completed
   ↓         ↓
on-hold   abandoned
StatusMeaning
plannedSpecified, plan not yet approved. Nothing built.
activeApproved, in progress.
on-holdDeliberately paused. Reason recorded.
deployedRunning in production. Requires the three extra sections.
completedDone, not a running service.
abandonedStopped for good. Reason recorded.

Status changes move the file: completed and deployed to a completed/ folder, abandoned to abandoned/, with inbound links updated.

on-hold and abandoned require a recorded reason, and that’s the point of having them. Git shows no commits since July; it cannot tell you whether that means finished, blocked, abandoned, or waiting on a decision — and those demand entirely different responses when you return. One line — “paused 2026-07-13, the concept needs a refactor, specifics TBD” — saves an hour of archaeology and possibly a rebuild of something you deliberately stopped.

Nothing is deleted. An abandoned project keeps its full plan, including phases never built. Projects get revived; this document exists because one was.


The completion fork

When a project produces something that runs, its final phase is: create or confirm an operational entity page for the deployed state.

Then the record forks:

Both questions are legitimate; they’re just asked at different times by different needs. “How was this built and why?” is archaeology. “What’s running right now?” is operations. A single page that tries to be both answers neither quickly, and the operational half decays because it’s buried under build history.

Before creating a new entity page, the rule is to check for existing coverage — a roster page or an adjacent entity may already document the deployed state, and a duplicate is worse than a pointer.


Cross-domain updates

When work in another domain touches a project — an ingested article that affects a build decision, say — the agent appends a one-line entry to that project’s ## Log.

This is how a project page stays current without anyone deliberately maintaining it. The information arrives through a side door and gets filed anyway.


Next: 10 — Skills.