research-kit

Skill

The flow

Work is records: one Markdown file each, front matter plus a prose body, stitched together by transitions that consume and produce records. The records hold data only; rules live in the project’s instructions, the skills and the hooks the project runs. scripts/flow.py beside this file is the CLI, the validator, the index generator and the selftest; flow … below is that script run by its path from the project root (python3 ${CLAUDE_PLUGIN_ROOT}/skills/flow/scripts/flow.py … under Claude Code), never a flow found on PATH, which may be another version. flow.toml at the project root binds the paths and the vocabulary.

Ideas and tasks

Kind What it is States
idea a raw signal worth attention: one sentence and a source; most die open, consumed, abandoned
task a unit of work one owner can finish within its size: a design round, a prose sweep, upkeep, a community item, an owner decision ready, active, done, abandoned

Distinguishing tests: can one owner finish it within its size? then it is a task, not an idea. Is it a thing you want to know rather than a thing to do? then it is a question, the kind below. A closed task moves to the archive at its closing transition, so the record directories show the live front of work.

Transitions

Transition Consumes and produces Command
capture external → idea flow capture "…" --source S; --tag T, --body FILE
task external → task flow task "…" --kind upkeep; --question Q for a task under a question, --size, --dod, --source, --tag, --body FILE
draw ready task → active, under the owner’s hand limit flow draw task-0001 --owner agent
return active task → ready flow return task-0001 --note "…"
make active task → done and archived; follow-up tasks and ideas flow make task-0001 --resolution FILE --task "…" --idea "…"; --question SUMMARY KILL mints a question
abort active task → abandoned and archived flow abort task-0001 --reason "…"; --resolution FILE
kill idea, ready task, or open or decomposed question → abandoned with a dated reason; an active task is aborted instead flow kill idea-0001 --reason "…"
rank the ranked next list: one record’s rank, the whole order at once, or a rank cleared flow rank task-0001 1 --why "…" --first-move "…"; --direction D; flow rank --set ID…; flow rank task-0001 --clear
set one hand-editable field: summary, size, dod, rider on or off flow set task-0001 size small

Views: flow find --type task --state ready (also --kind, --status, --tag, --owner, --question Q, --paper P, --requires ID, --depends-on ID, --parked, --ranked, --grep WORD), flow show ID (the record, its links and its back-references), flow graph --from ID (--dot for Graphviz), flow state (the cold-start bundle; --from N continues it, --budget N bounds it), flow directions (the directions file), flow index (--print to stdout, --check for drift), flow check. flow --help lists every command, flow <command> --help its flags, and neither needs a bindings file. The global flags are --json (any command emits one JSON object), --root DIR (the project, found upward from the working directory otherwise) and --today DATE; flow pages prints the page manifest the dashboard skill renders. A --body FILE or --resolution FILE takes a file, never inline text, so a long body is drafted first and checked by the project’s text gates — its own checks on prose, such as a linter or a line rule. Make and abort append the resolution to the task’s body under its date, as refine appends its --body, so the archived task keeps what was asked and its notes. A ready or active task’s rider field marks it as riding the next piece of work handed to another owner; the index lists such tasks under “Rider for the next hand-over”.

A design round is a task of the design kind: drawn before the round, closed by make or abort with the round record as its resolution and its discarded options one line each inside that record. Make and abort are where follow-up work is minted: a residue sharp enough to name becomes a task or a question of its own rather than prose in the resolution or a line appended to a question’s body.

Invariants the validator enforces

  • Every id is unique and matches its filename prefix; every referenced id exists and has the type the field demands; no cycles in derived_from.
  • State, kind, size and owner are legal values from flow.toml.
  • Active tasks per owner stay within the hand limit; a closed task lives in the archive and an open one does not; an abandoned record carries a dated reason.
  • Ranks are unique and contiguous, never on a closed record or on owner-only work, and a ranked record says why now and what the first move is (“none yet” is allowed).
  • Every body is one sentence per line; the committed index equals a fresh render.
  • Every library key a record cites is a card the library holds, where a library is bound.

flow check prints a coverage line saying which resolvers were configured, so a green says what it did not look at. flow.py --selftest plants one defect per code the check reports, fails when one is planted nowhere, and must stay green.

Reading discipline

Start with flow state: the inbox slot of the directions file, the ranked next list and the log’s top entry, every line carrying its file and line. The log is dated entries, newest first, each a level-2 heading ## YYYY-MM-DD — headline opening with a **State.** paragraph; flow state prints the whole top entry, and its State paragraph is the one a cold session trusts. Then the generated index, which lists the ranked list, each owner’s hand, ready work and owner-only items. Locate records with flow find or flow show ID; open record files only by ID. Never glob the record directories, and never read a record directory whole. A cold session processes the inbox slot first, then reads the next list and the log’s top State paragraph, and continues without asking, unless the project’s instructions say the owner is asked before work is drawn.

Writing discipline

Transitions go through flow. Never edit id, type, state, derived_from, consumed_by, owner, drawn, rank, abandoned, origin or created by hand. The one record written by hand is one imported from before the flow: its whole file, with origin: legacy, which exempts it from the kill-criteria rule until its first round; no transition writes that value. Edit a body freely, and a summary, size, dod or rider with flow set, which refuses a field the record’s type does not carry and a value the field does not take; a body is one sentence per line, and a write that adds a markdownlint violation is reverted where markdownlint is on PATH (with the project’s configuration where flow.toml binds one or the root keeps one, else a built-in one under which a record’s summary: is its title). The front matter is the subset of YAML the script writes: plain scalars, single-quoted strings (a quote doubled inside), double-quoted strings with escapes, null, true/false, integers, block lists (- item) and one-level maps; a hand edit stays inside that subset, and flow check reads every record back. A record points at where its subject is STATED and never restates it, because the statement moves and a copy does not. Run flow check before committing; the project’s hook runs it as well.

The next list

The ranked records are the schedule of the WORK, and the only one; the registry below orders the deliverables, not the work. A session works from the top. The list is filled or refreshed when the owner asks or when it is empty, on no cadence, with no per-landing re-triage; references/next-list.md is the refresh procedure. Nothing is ranked down or left off for lacking a route: a record with no known route is ranked with a first move of “none yet”, and finding the route is its first round’s job. The one gate is owner-only work — a task of a decision kind, or held by a decision owner — which is never ranked, since it holds what only the owner can do or should decide; a decision gates a landing, never a start. A done item clears its own rank through its transition, and the ranks below it close up, so the list stays 1..n without a hand on it.

Questions and findings

The two kinds above hold the work; these two hold what is KNOWN and what is WANTED.

The two kinds

Kind What it is States
question a precisely stated question or conjecture, with kill criteria; what we want to know open, decomposed, answered, abandoned
finding a CHECKABLE claim: its evidence is a declaration in a manifest, a document’s numbered statement or table row, or a self-asserting probe none; it accumulates

Distinguishing tests: can you say what would count as an answer? then it is a question, not an idea. Can its evidence be resolved by a machine? then it is a finding; otherwise it is a claim inside a task’s resolution until it earns evidence. Every task done and nobody can state the answer? then the question goes back to refine. A conjecture is a question of kind conjecture (flow frame … --kind conjecture), never a finding; a dead end is an abandoned task’s resolution, never a finding. There is no artifact record: the documents and the machine-checked library ARE the artifacts, and findings point at them directly.

A question asks one thing, and its kill criteria say what answers it. An open end a round finds beyond those criteria is framed as a question of its own, from the finding that exposed it (flow frame finding-0001 …) or from an idea captured first, and is never appended to the first question’s body as what stays open: a question that gathers its residues has no answer anyone can reach, and the next list can no longer rank it by how near it is to done. A question whose parts each carry weight alone is split: at framing, into one question per part; at answering, the part answered closes the question, and each part still open is framed on its own with a pointer to where it is stated.

Evidence and status

An evidence item is one of four forms, each resolved by the validator and by make:

Form Example Resolved against
declaration Lib/Foo.lean#lemma_L, or a whole module Lib/Foo.lean (the extension is the project’s: .v, .thy, whatever its manifest names) the declaration manifest the project binds ([evidence] manifest, a text file of Module.Path name lines, a prover library’s declaration list being the instance), the file looked up under manifest_roots; the extension is manifest_extension, required beside a manifest, and any extension but md and py passes as a declaration where none is bound
row papers/alpha.md#FV-1 a table row of that document whose first cell is the id — two or three capitals, a hyphen, then letters and digits — written | FV-1 |
statement papers/alpha.md#Theorem 2.1 a numbered statement of that document — Theorem, Proposition, Lemma, Corollary, Definition, Remark, Fact, Conjecture or Example, then N or N.M… — found at a line start, after ** or in a heading
probe probes/p.py a self-asserting script, named with its directory, listed in the probes register the project binds: a Markdown table whose first column holds the file’s name in backticks

A finding’s status is one of four roles the project names in [finding] (the defaults are verified, stated, empirical, refuted; a prover project may call them lean-verified, proven, empirical, refuted): verified needs a declaration among its evidence; stated is document-level, a statement or row and no declaration; empirical needs a probe and no declaration; refuted needs a guard declaration or a probe as the counterexample. The status follows the evidence and is never set by hand: a finding is verified only because its declaration resolves in the manifest the project’s build regenerates. Where no manifest or register is bound, such evidence is reported unchecked, and the coverage line of flow check says so. Findings shard by the document that registers them (--paper, read off a row or statement item when not given) under the shards flow.toml lists.

Their transitions

Transition Consumes and produces Command
frame ideas → question (ideas consumed), or one finding → question flow frame idea-0001 --summary "…" --kill "…"; --kind conjecture, --parent Q for a sub-question, --size, --direction D, --tag, --source, --body FILE
refine open or decomposed question → tasks, sub-questions, ideas; the question is decomposed (a parked one is unparked first) flow refine question-0001 --task "…" work --subq "…" "…" --idea "…"; --kind, --size, --dod and --requires ID for the tasks minted, --body FILE
make, abort an active task’s closing transition may mint findings and questions flow make task-0001 --finding "…" verified Lib/Foo.lean#decl --resolution FILE; --paper P names the shard, --depends-on F a finding’s dependence
answer question with a finding → answered; refused while it has open tasks; a question whose kill names work rather than a result is answered by the done tasks drawn under it flow answer question-0001 --by finding-0001; flow answer question-0002 --by task-0003; --by repeats where several findings or tasks answer it together
kill an open or decomposed question → abandoned with a dated reason flow kill question-0001 --reason "…"
park, unpark an open question gains or loses a parking block: the date, the reason, and revival triggers where known (--revival is optional) flow park question-0001 --reason "…" --revival "…"; flow unpark question-0001
checked refresh a question’s last-checked date flow checked question-0001 …
set kill (the criteria), depends_on on a finding (a cycle is refused) flow set question-0001 kill "…"

flow task "…" --kind work --question Q mints a task under a question outside a refine; without --question only a question-optional kind stands alone. A question tagged do-not-reopen (--tag at frame, or a hand edit of tags) is listed by the index under “Settled, do not re-open” whatever its state, so a settled matter is seen before it is asked again. Refine is the commitment point: anything ready may be drawn without further approval, so refine with that weight. The last cheap “no” is at refine; most ideas should die, and a kill keeps its reason. The kill criteria a question carries are fixed when it is framed; the probes and criteria a round fixes bind that round alone, and the method skill’s honest-change invariants say how a target may change.

Directions

A direction is a hint about what interests the owner, not a boundary or a gate: items toward one rank first on the list and may be opened with no known route; a direction changes nothing else. Directions are bullets of the directions file’s ## Directions section, written by the owner, each in the form - **Name** (date) — the words; a question’s direction carries the bold name and must match one (the validator’s V22), and sessions propose directions in the log and mint none.

Invariants the validator adds

  • A task has one question unless its kind is one the project lists as question-optional; an open task’s question is open or decomposed.
  • Every finding has evidence, each item resolves by its kind, and the status is consistent with the kinds present.
  • Every open question has a last-checked date; a current question has kill criteria, and a question imported from before the flow gains them at its first round; a parked question is open with a date and a reason and is never ranked.
  • A decomposed question has a task; one whose tasks are all closed is flagged as needing refine or answer.
  • A question’s direction names a bullet of the directions file.
  • No cycles in depends_on.

Reading and writing them

Everything above holds; in addition: never edit question, answered_by, parked or abandoned by hand, and change the kill criteria through flow set … kill; a question’s body points at where the question is STATED (a document’s section, a module) and never restates it. No question is parked, ranked down or excluded for lacking a route; parking carries a dated reason, and revival triggers where they are known, and a stalled item is parked rather than left ranked. A result is registered in a document as a specific numbered statement with its rows and boundary, never as a thesis rewrite, and the finding that records it is written from the landed artifact, never from the design record that commissioned it.

What else a project keeps

  • A LOG of dated entries, newest first, one per landing or decision, each ## YYYY-MM-DD — headline opening with a **State.** paragraph, the top one the paragraph a cold session trusts; the commit message carries its headline and a pointer, never the entry; old entries are archived by period, verbatim.
  • A directions file the owner writes: an inbox slot the next session processes before anything else — each item turned into a record or acted on, named in that session’s log entry, and removed, the slot never serving as a log — and the owner’s dated statements of interest.
  • A REGISTRY of the deliverables — what the project produces (documents, a library, releases) and in what order they are read or shipped — the one place that order is stated; the ranked list orders the work, the registry the products.
  • Optionally a reference library of the works it refers to, the library skill’s, bound to the flow by one command.

What the project binds

flow init in an empty project writes flow.toml with the bindings filled in and the optional ones commented, the record directories under records/ (--records DIR for another), the directions file, the log where --log FILE names one, and the index, and prints the paragraph the project’s instructions should carry; --force overwrites a bindings file that exists. It writes two owners unless --owner names others: agent, the working session, with a hand limit of two active tasks, and owner, the person, with no limit (a limit of 0 is unlimited), who is the decision owner — a task of a decision kind is minted under that owner’s hand and is never ranked. flow.toml names the record directory, the index, the archive, the directions file, the log, the id prefixes and width, the owners and their hand limits, the task kinds, the default kind, the question-optional kinds, the decision kinds and owners (owners listed under [hand], or none), the sizes, the finding statuses, the shards, the evidence resolvers, the reference library’s command, the reflow module and the markdownlint config, and the library’s command, which may stay unset: with a library.toml at the root the flow asks the library skill installed beside this one, else library on PATH, and flow check’s coverage line says which. The project’s instructions name the log, the registry, the gates that cover the records and the archive rule. The project’s instructions also name where results are registered and what gates cover them.