Spring til indhold

Tidligere version (v3) (2026-06-10, "Calque-pass + serie-konsistens")

Dette er en arkiveret tidligere udgave af denne post. Den aktuelle version kan være ændret. Læs den aktuelle version →

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.

← Alle indlæg
v3

Fra ændrede filer til commit messages

Pks brain commit-plan kører grafens reverse query: tag staged filer, find de prompts der drev hver ændring, returnér grupperet plan. Det 4. og sidste indlæg i serien viser hvordan det blev til en /commit-message-skill — og hvorfor den var ubrugelig før vi flyttede planneren fra rå-JSONL-scanner til firehose-direct-read.

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:

human prompt
1 lines
we had a session a few days ago about writing something for pks brain to be able to query which sessions had touched a file, can you find it

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:

human prompt
1 lines
based on the work in it, can we do a skill that /commit-message that will query based on staged files and generate a good commit message following best practice that will generatre a nice release overview when the release pipelien runs later?

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:

  1. git diff --cached --name-only → den nuværende staged-liste
  2. pks brain commit-plan --files-from <list> --include-prompts --format json → grafens reverse query
  3. git diff --cached → den faktiske diff (hvad-er-ændret)
  4. Syntese: subject = hvad (ét konkret user-visible change), body = hvorfor (syntetiseret fra de prompts der drev ændringerne)
  5. Output i Conventional Commits-format, så semantic-release og 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:

DAG-diagram med fire nodes forbundet med tre edges — den samme DAG som i indlæg 3, brugt her som reference for reverse-queryen

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:

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:

human prompt
1 lines
the pks brain call was slow, was this because it had to scan all files. Can we try build the brain graph and see if the query for the same files then are close to instant?

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:

ImplementeringTid
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:

commitbb8755epks-cli

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å:

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:

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.