Beans and todos

On this page
  1. Two things that share a word
  2. The agent bean lifecycle
  3. A bean is never deleted
  4. Engine operations are not CLI calls
  5. Human todos — not built yet
  6. What the work plan holds right now

This page is generated from docs/source/guides-beans-and-todos/ — each section below links to its own source.

✎ Edit

Beans are for agents. Todos are for humans. They share a word in ordinary speech and nothing else, and conflating them is how a work plan comes to hold two kinds of thing that need different handling.

A bean is process state an agent keeps while doing work: claimed before starting so a sibling session avoids it, kept current as the work proceeds, and closed with a record of what changed. The store is beans/, committed, so it survives a reclaimed container and is visible to every other session.

A todo is a person’s own reminder — what they mean to look at next. It is theirs to create, reorder and discard on no schedule but their own, and nothing about an agent’s process should be deciding when it is done.

This page describes the first in full. The second is not built yet and says so.

Two things that share a word

✎ Edit

The distinction is not terminology. The two have different owners, different lifecycles and different failure modes.

BeanTodo
OwnerAn agent sessionA person
PurposeProcess state for work in flightA reminder of intent
Storebeans/, committed and sharedNot yet defined
Created byAn agent, after an exact-title checkThe person, whenever they like
Closed byThe agent that did the work, with a summaryThe person, on their own judgement
Visible toEvery sibling sessionThe person, primarily
Failure modeDuplicated, or closed by the wrong sessionForgotten

The failure modes are what make the split worth keeping. A duplicated bean starves the work plan of signal — in one folio an unguarded re-run produced 14,688 duplicates, 92 % of every open bean in the repository. A forgotten todo inconveniences one person. Machinery sized for the first is ceremony on the second, and machinery sized for the second is nowhere near enough for the first.

The agent bean lifecycle

✎ Edit

BPMN swimlane diagram with two lanes. In the agent's lane: durable work is identified, the agent runs an exact-title search before creating anything, then a gateway asks whether the bean already exists. If not, it creates one; if it does, a second gateway asks whose it is. A bean owned by someone else routes to the lower lane — sibling session or human — where the only action is to leave it alone and coordinate, ending there. The agent's own or an unclaimed bean is claimed as in-progress, worked on with the body kept current, and then reaches an outcome gateway with three branches: done goes to complete, not wanted goes to scrap with reasons and never delete, and blocked goes to recording the blocker and handing it back. All three converge on a single end event, state recorded.

Open the BPMN source

The diagram above is the whole cycle, and three of its edges are the ones worth reading twice.

The first step is a search, not a creation. beans create is not idempotent: it mints a fresh identifier on every call and de-duplicates on nothing, so re-entering a step duplicates the plan rather than doing nothing. The exact-title check is what stands between a repeated workflow step and a corpus of near-identical beans.

Ownership is a gateway, not a courtesy. A bean another session claimed is not yours to resolve, scrap or delete. Claiming is how two sessions avoid picking up the same item; closing someone else’s is how one of them loses work it had not finished reporting.

“Blocked” is not “not wanted”. A blocked bean returns to todo with its blocker recorded and something said about what would clear it. Leaving it in-progress is worse than either: an item nobody is progressing reads, to every other session, as active work.

A bean is never deleted

✎ Edit

beans delete exists in the CLI. Do not use it.

Work that turns out not to be wanted is scrapped — status: scrapped, with a section saying why. That is what “disable” means here; the CLI has no disabled state, and its vocabulary is draft, todo, in-progress, completed, scrapped.

The reason is not tidiness. A scrapped bean records that something was considered and rejected, and on what grounds — which is worth as much to the next agent as the record of work that was done, because it is what stops the same dead end being re-entered. A deleted bean leaves a sibling session unable to tell abandonment from accident, and leaves the next agent free to start over on the thing you already ruled out.

The prohibition is written here, and in the diagram’s own documentation, precisely because the tool offers the operation. A rule that depends on nobody noticing a command is not a rule.

Engine operations are not CLI calls

✎ Edit

Two different things can change a bean, and a step that confuses them will announce an effect it does not have.

The workflow engine performs claim, note and resolve on a process instance’s own bean when a step marked <cat-harness.processes:bean op="…"/> completes. claim sets in-progress and is idempotent; note appends; resolve completes the bean only once the instance itself has completed, because whether work is done is a judgement and a bean is not closed on someone else’s say-so.

The agent does everything else with the beans CLI: creating, scrapping, retitling, setting a blocker. The engine has no operation for any of these.

This is not a hypothetical distinction. An activity in the CRDM diagram carried <cat-harness.processes:bean action="create"/> — action, where the engine reads op — so it parsed as no operation at all. The step advertised that sign-off produced beans, performed nothing, and did so silently until somebody read the parser.

When you add a bean-marked step, use one of the three operations the engine implements, and say in the step’s documentation which parts are the agent’s own CLI calls. bun run cat check:workflow-refs will catch a skill reference that does not resolve; it cannot catch a plausible attribute the engine never reads.

Human todos — not built yet

✎ Edit

Not built yet, and stated here rather than left as an absence somebody has to notice.

A person’s todos need a cycle of their own, and none of it exists:

  • When a todo is shown. Surfacing every open item on every turn is noise; surfacing none is a list nobody reads. Whatever the rule is, it is not the same as the work-plan priming an agent gets at session start.
  • When a person may create one, and through what — chat, a command, the session-start surface.
  • How one is retired. A person abandoning a reminder is ordinary and needs no “reasons for scrapping” section; the bean rules do not transfer.

Until that is designed, do not repurpose beans for it. A store whose entries are claimed by sessions, closed with change summaries and never deleted is the wrong shape for a reminder somebody wants to drop without ceremony — and mixing the two would put items in the agent work plan that no agent should be acting on.

What the work plan holds right now

✎ Edit

The rest of this page says what a bean is. This section says what the store currently holds — read live from /assets/beans/index.json, the projection gen-docs-pages.ts writes from beans/defs/ on every build, beside the todo index it has published for longer.

Until 2026-09-20 there was nothing to put here. todos/ had a reader, a published index and a board over it; beans/ had none of the three, though it is the larger store by two orders of magnitude. A work plan nobody can look at is one nobody checks.

What the dashboard shows, and why each panel is the shape it is. The counts are a headline, so they are numbers rather than a chart of four bars saying the same thing. The work plan itself is a tree, goal → epic → feature → story, because the question a reader brings is “where does this sit”, and a bar per epic answered “how many” and listed one level. The type filter and the search prune that tree to what matches and open it down to them. The store’s task type is shown as story, since a Task here is a BPMN task. The findings are three or four rows, so they are a list — with an icon and a label on every row, because a status colour never carries meaning alone.

The findings are computed from committed data only, and one of them is missing on purpose. A stale in-progress detector would have to read the clock, and the projection is gated on exact content — anything computed against the clock changes the file on every build and the staleness gate then fires forever. So the projection publishes each bean’s updated_at as a fact and the page computes age when you open it. Age therefore moves without the file moving, which is the right way round.

There is a fuller view, and it is browsable. Every declared state graph gets its own visualiser at the path this instance already uses for that graph — /beans/, /todos/, and one for each of the others. The route is not this page’s invention: bean o7eq carries the owner’s ruling that a rendered asset is addressed by its instance’s name with the declared graph as a path segment, and that this instance elides its own name because its docs/ is what the site serves, and the harness-requirements skill names that exact URL as the obligation — “a requirement of them is to provide visualisers accessible at <base-url>/beans“. There is no index above them, because / is the documentation site’s, so each page lists its siblings.

A graph with no projection says so. qa, health, issue-marks and uploads are declared state graphs that nothing publishes a projection for yet. Their dashboards say exactly that and name bean 2krx, rather than rendering zeros for a store nobody read — a dashboard that opens at zero is indistinguishable from a store with nothing in it, and those are opposite facts.

Every identifier on those pages is a link. A bean id resolves to the bean’s file, an issue or pull-request number to the forge, and each finding carries a pencil to where writing actually happens. A reference that cannot be resolved stays as plain text, which is the visible difference between “follow this” and “this points somewhere I could not reach”.

What is not here. Where a bean sits in a BPMN process, which is the other half of bean v49e. That join needs beans/workflows/, the declared workflow-state graph, and it is empty — so a position view would report “nowhere” for every bean in the store. It waits for instance state to exist.

The live work-plan dashboard needs JavaScript. The projection it reads is a plain JSON file and can be read directly.


Notes on this page (1)

The notes attached to this page, in document order. Every note in this folio is on the todos board.

  1. The human-todos page still says 'Not built yet' — the store now exists

    Status
    open
    Priority
    high
    Raised by
    agent
    Created
    2026-09-19
    About
    guides/beans-and-todos › human-todos

    content/docs/guides-beans-and-todos/human-todos.md opens **"Not built yet"**, and that is no longer true. todos/ is a declared graph with items on disk, a reader, a published JSON index and a board on the site.

    This todo is attached to that block, so it renders beside the sentence it contradicts. That is the per-page assignment working on a real case rather than a demonstration — the page is genuinely stale and somebody has to decide what it should say now.

    ## What the page still gets RIGHT, and must not lose

    Three of its four claims survive, and they are the valuable part:

    - **"Do not repurpose beans for it."** Still correct, and now structural: beans/ and todos/ are separate declared graphs. - **When a todo is shown.** Still undecided. This PR answers it for the navbar and the board; it does not answer whether an open item should surface unasked, and the page's objection stands — surfacing every item on every turn is noise, surfacing none is a list nobody reads. - **How one is retired.** Still undecided. TodoStatus carries resolved and wontfix, but nothing retires one, and the page's point holds: a person abandoning a reminder is ordinary and needs no ceremony, so the bean rules do not transfer.

    ## What has changed and needs writing down

    - **How a person creates one** is answered in the worst way: by an agent writing a file. There is no human path at all yet. - The 2×2 the page is missing — memory against workflow management, human against agent — with the empty quadrant named.

    ## Done when

    The page says what is true. Cheapest correct move is an edit to that block, not a rewrite: strike "Not built yet", keep the three open questions, add what now exists and who created it.

    Every todo carries a pencil to exactly this file, so the edit is one click from where the stale sentence renders.

folio-assistant — code under the Apache License 2.0, documentation under CC BY 3.0. Generated schema and API references are rebuilt from source on every push to main.

deployed b08c961 · 2026-10-23T23:11:09Z