52 staged filer. 200 sekunder. Tre minutter på at vente på en commit message — det er længe nok til at jeg åbner en anden fane og glemmer hvad jeg var i gang med. Da pks brain commit-plan begyndte at læse grafen direkte i stedet for at re-parse rå JSONL hver gang, faldt de 200 sekunder til 1,3. Speedup på ~165×. Det forvandlede /commit-message-skillet fra "for langsom til at bruge" til "kør den hver gang".
Det her er det 4. og sidste indlæg i serien om pks brain (efter hvorfor AI-hjernen eksisterer, hvad den producerer og hvordan grafen er bygget op). Det handler om at lukke loopen: tage grafen fra indlæg 3, køre dens reverse query mod staged filer, og bruge resultatet til at skrive en commit message der ved hvorfor — ikke kun hvad.
Sessionen startede med at jeg ledte efter en gammel samtale jeg havde glemt indholdet af:
Found it.
Session: 18377515-f8c8-4f45-a0d5-efb302e4c222.jsonl — May 24, ~20:13 UTC.
What it was about: A graph-based design for pks brain that tracks which Claude Code sessions edited which files, so you can group uncommitted files into smart commits. Four-node graph: sessions (jsonl) → prompts → tool calls → files. Captured live via a Stop hook into .pks/brain/ (SQLite/JSONL), exposed as something like pks brain commit-plan to answer "which sessions touched these dirty files" and generate commit messages from session context. You also asked to review the product-cli graphs framework before dismissing it.
Starting quote from you: "my problem is more the other way around — I end up with a lot of uncommitted files and would like a smart way to find out how to group them based on AI sessions and generate good commit messages."
Want me to open the transcript or extract the design notes into a memory entry?
AI-hjernen fandt den. Tre dage gammel session, fuld af notater om hvordan man linker filer til de sessioner og prompts der havde rørt dem. Spørgsmålet kom umiddelbart:
Hvad skillen gør
/commit-message er en Claude Code-skill der kører hver gang man har staged filer og vil skrive en ordentlig commit-message. Flowet er:
git diff --cached --name-only→ den nuværende staged-listepks brain commit-plan --files-from <list> --include-prompts --format json→ grafens reverse querygit diff --cached→ den faktiske diff (hvad-er-ændret)- Syntese: subject = hvad (ét konkret user-visible change), body = hvorfor (syntetiseret fra de prompts der drev ændringerne)
- Output i Conventional Commits-format, så
semantic-releaseog lignende kan rulle dem sammen til release notes senere
Pointen er at AI-hjernen kender konteksten bag hver fil-ændring — ikke kun selve ændringen. Når man skriver feat(blog): publish coolify-destinations-pr post er det fordi grafen kunne pege på de prompts der oprindeligt diskuterede coolify-destinations-PR'en — ikke fordi modellen gættede et subject ud fra filnavnene.
Grafens reverse query
Det 3. indlæg etablerede at grafen er en DAG med fire nodes: Session → Prompt → ToolCall → File. Forward er trivielt. Reverse er det interessante:

pks brain commit-plan kører præcis den reverse query: for hver staged fil finder den ToolCalls i files.jsonl der har skrevet til den filsti; for hver matched ToolCall finder den den seneste brugerprompt i prompts.jsonl med samme sessionId og timestampUtc ≤ tool-call.ts; til sidst grupperer den efter primary-session og returnerer.
Resultatet er en JSON med:
groups[]— filer der hænger sammen (samme primary session)groups[i].prompts[]— de brugerprompts der drev edits til de filer (verbatim tekst, timestamp)groups[i].contributing_sessions[]— andre sessioner der også rørte filerne
Skillet bruger det output til at vælge en type (feat/fix/chore/docs), et scope (det mest specifikke område), og et subject der reflekterer det mest user-visible change — så syntetiserer body'en fra prompt-teksterne uden at citere dem ordret.
Hvad gjorde den ubrugelig først
Da skillet blev skrevet, var pks brain commit-plan implementeret oven på en per-fil scanner der re-parsede rå ~/.claude/projects/**/*.jsonl fra bunden af hver gang. For 52 staged filer tog det ~200 sekunder. Tre minutter. Det er ubrugeligt for et "tryk-her-så-commit"-flow.
Jeg stoppede op og skrev:
Den observation delte arbejdet op i to features (præcis som indlæg 3 beskriver): ingest-laget — som allerede producerede en graf i form af firehoses — og graf-laget, der bare skulle læse den eksisterende graf i stedet for at re-parse rå-data.
Fixet var en ~80-linjers omskrivning af BrainCommitPlanner i pks-cli: én streaming-pass over files.jsonl filtreret til input-filerne, en binary-search-join mod prompts.jsonl for prompts før hver edit-timestamp, scanneren beholdt som fallback når firehose'en mangler, og en auto-ingest før query så grafen er frisk.
Resultatet på det samme 52-filers staged-set:
| Implementering | Tid |
|---|---|
| Firehose grep (rå lookup over indekseret firehose) | ~10 ms |
pks brain commit-plan (ny — auto-ingest + firehose-read) | ~1,3 s |
pks brain commit-plan (gammel — per-fil scanner) | ~200 s |
Speedup: ~165×. Det forvandlede skillet fra "for langsom til at bruge" til "kør den hver gang".
Dogfood-momentet
Den her serie er skrevet i den session hvor skiftet skete. Den her commit blev skrevet af /commit-message selv — skillet brugte den nye firehose-implementering til at finde de prompts der drev sin egen rewrite, gennem en JSON-output på 1,3 sekunder, og syntetiserede:
feat(brain): wire commit-planner to firehose graph
The graph itself already existed — pks brain ingest materialises
files.jsonl as the File↔Session edge table — but BrainCommitPlanner
ignored it and re-parsed every raw ~/.claude/projects/**/*.jsonl per
input file, taking ~3 minutes for a 52-file plan. The planner now reads
the firehose directly with a binary-search join on prompts.jsonl and
keeps the scanner as fallback when the firehose is absent.
Hele kæden — ingest, firehose, graf-query, skill, conventional commit — lukkede loopen på sig selv. Se artifact-siden for /commit-message hvis du vil læse selve skillen.
Hvad jeg konkret får ud af det
Tre ting jeg kan mærke forskel på:
- Bedre commit-messages. Subject = ét user-visible change. Body = hvorfor, ikke hvad. Hvad → diff. Hvorfor → kun synlig hvis nogen har et signal fra prompts der drev edits. Det signal fandtes ikke før grafen.
- Bedre release notes. En release-pipeline (semantic-release / conventional-changelog) tager subject-listen og bygger "## Features" / "## Bug Fixes" automatisk. Body'erne overlever som expandable detail. Pludselig er release notes ikke et review-step men en bivirkning.
- Sporbarhed. Hvert commit kan slås tilbage til præcis de prompts der diskuterede det. Det er ikke et "AI wrote this" disclaimer — det er at kunne læse hvad der blev sagt før koden blev til.
Slut på serien
Det her var det 4. og sidste indlæg i serien om pks brain. Genopfrisk de tre andre hvis du sprang ind midtvejs:
- Hjernen bag — hvorfor AI-hjernen overhovedet eksisterer
- En wiki skrevet af vores AI-hjerne — hvad den producerer
- Grafen var der hele tiden — hvordan den er bygget op
Måske kommer der et 5. indlæg en dag med en interaktiv visualisering af grafen. Måske ikke. Serien lukker her: fire indlæg, ét repo, ~7.000 prompts kondenseret til en DAG der ved hvorfor mine filer eksisterer.
Denne post er blevet revideret 4 gange — se hele historikken
Førstegangs ai-draft. Havde to pseudo-terminaler der ikke var rigtige shell-sessioner (benchmark-tabel og commit-hash + body) som tvang horisontal scroll på mobile. Manglede en artifact-side for /commit-message-skillet. Pks writing score 52.
Erstattet benchmark-pseudo-terminalen med en markdown-tabel (alignment-decoration, ikke real terminal-output). Indført ny `<CommitBlock>`-komponent som rendrer commit-hash + body som ét semantisk kort i stedet for to separate kodeblokke. Tilføjet artifact-side for /commit-message-skillet med fil-tree + inline SKILL.md.
Erstattet meta-narrativet ('Jeg startede session med at lede efter en gammel samtale…') med en number-first lede: '52 stagede filer. 200 sekunder. […] faldt til 1,3.' Samme greb der løftede post 1 fra Hook 2 til 4. Humanprompt-blokke bevaret verbatim, blot demoteret til kontekst efter punchline.
Opus-review (score 60, Terminology 2/5): 'stagede filer' → 'staged filer', 'skanner' → 'scanner', 'Strøm én pass' → 'én streaming-pass', 'Du skar ind' → 'Jeg stoppede op og skrev', genusfejl ('det output', 'det samme staged-set'). 'Fire knuder' → 'fire nodes' så terminologien matcher indlæg 3. Cliffhanger-slutningen kortet ned til seriens punchline.
To sessionstory-blokke fra session c848c842: (1) 'we had a session a few days ago' med grep-jagten og 'Found it'-svaret; (2) 'commit this with /commit-message' med selektiv staging, 1,3s-planen, commit-bekræftelsen og bb8755e — verbatim.
