Research notes
Use Case 2.3 from the design overview (§2.3). A team’s accumulated research notes — competitive analysis, technical experiments, market observations — captured one row per note, with light structure that AI agents can extend.
The shipped sheet is
examples/research-notes/.
The shape
contract.yaml columns: id string PK title string human-editable body string human-editable category string human-editable ("competitive" / "technical" / "market" / "internal") tags array human-editable word_count integer derived (python — counts words in body)Why a sheet (and not a wiki)?
Notes in a wiki are unstructured text. Notes in a sheet have:
- A typed
categoryfield that drives sorting and filtering. - A
tagsarray for free-form labels. - A derived
word_countfor “long” vs “short” sorting. - A clean upgrade path: an
aiderivation that fillstags/summary/categoryfrombodyonce you setANTHROPIC_API_KEY.
The cost of structure: the contract has to be designed up front. The benefit: every reader and writer (human or agent) sees the same shape.
Walking through the sheet
folio validate examples/research-notesfolio materialize examples/research-notes --actor agent:demo
folio query examples/research-notes \ "SELECT category, COUNT(*) AS n, SUM(CAST(word_count AS INTEGER)) AS total_words FROM records GROUP BY category ORDER BY n DESC"[{"category":"technical","n":2,"total_words":46}, {"category":"competitive","n":1,"total_words":29}, ...]Open the Viewer:
folio serve examples/research-notes --port 3000 --actor agent:humanThe Records tab lets a human edit title / body / category / tags
inline. The word_count column has a python dot;
clicking it surfaces the history (when was the body last edited, what
was the count then).
A typical lifecycle
- A team member writes a note. Inline-editable in the Viewer, or via
folio upsertfrom a script. - Materialize. The
pythonderivation fillsword_count. - An AI agent extends. (opt-in extension) An
aiderivation readsbodyand fillssummary,category(if blank), andtags(if empty). SetANTHROPIC_API_KEYand re-materialize. - Periodic reviews. A weekly
folio querysurfaces the longest notes, or notes lacking tags, for cleanup.
Extending with AI
A starting ai derivation:
targets: [tags]inputs: [body]kind: aimodel: claude-sonnet-4-6prompt: | Read this note body and return JSON: {"tags": ["..."]}. Choose 1-4 tags from this controlled vocabulary: ["mcp", "duckdb", "frontend", "feedback", "deprecation", "performance", "interviews", "competitor", "tanstack"].
Body: {{ body }}output: jsonoutput_schema: tags: arraySet ANTHROPIC_API_KEY and run:
folio materialize examples/research-notes --actor agent:auto-tagThe cache invalidates on edits to body or to auto_tags.yaml. Existing
human-edited tags stay (default respect_human_override).
See also
- examples/research-notes/README.md
aiderivation — the path to add the AI extension.pythonderivation — the kind that handlesword_count.