Skip to content

feat(knowledge): a run can record what it learned - #85

Merged
EdmondDantes merged 1 commit into
mainfrom
feat/kb-record-action
Jul 24, 2026
Merged

feat(knowledge): a run can record what it learned#85
EdmondDantes merged 1 commit into
mainfrom
feat/kb-record-action

Conversation

@EdmondDantes

Copy link
Copy Markdown
Contributor

What was missing

A run could search and read the knowledge base but had no way to WRITE to it. Nothing taught recording — the tool's description was read-only, no prompt said "record decisions here", and zero notes exist in any project base (only the scaffolded README). The learning a run produced died with the run.

The fix (the action's existence is the teaching)

  • KnowledgeWriterInterface — the write half, its OWN interface, exactly as KnowledgeBaseInterface already promised ("Writing lives on its own interface and is obtained separately, so a palette that must not write cannot be handed a thing that writes"). One method: record(kind, title, body, tags).
  • KnowledgeBase implements it — files a markdown note into the kind's folder (decisiondecisions/, postmortempostmortems/, designdesign/), with frontmatter tags and an H1 title. The kind→folder map lives here because "where things live" is this class's sole policy. The note is readable immediately; searchable from the next indexing pass (the same read-beats-search lag read() already documents).
  • KnowledgeTool gains record — but ONLY when constructed with a writer: the action is absent from the schema, the description, and the risk level (Safe without a writer, Mutating with) when there is none. A read-only palette is not told writing exists, rather than told not to. IssueRunner passes the base as both reader and writer, so a run both consults and records.

Correctness details (a clean-context review pass caught these; fixed and tested here):

  • A colliding title files a NEW note beside the old (slug-2.md), never over it — by the base's own conventions a decision that replaces an earlier one is a new note. The claim uses an exclusive create (fopen(..., 'x')), not check-then-write, so it holds under the concurrent runs of one project the base is explicitly designed for.
  • The title is prepended only when the body has no # H1 of its own — a body opening with ## Context still gets its title, instead of the parser falling back to the filename slug (which rides into every embedded chunk).
  • Tags are stripped of the ,[]/newline characters that delimit the frontmatter list, so a stray one cannot mis-file the note.
  • The generated handle admits only [a-z0-9-], so ../../outside files as design/outside.md — traversal is not expressible.

@EdmondDantes
EdmondDantes merged commit 68bcdb8 into main Jul 24, 2026
2 checks passed
@EdmondDantes
EdmondDantes deleted the feat/kb-record-action branch July 24, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant