Context
PR #78 landed the live session watcher (#77). It tails Claude Code JSONLs in real time and feeds the activity store for the live node graph. But the watcher is ephemeral — events flow through for the 8-second pulse lifetime and are then lost.
The learning model (repetition + emotion signals) needs to compute stats across sessions: "this file has been read 14 times across the last 10 sessions", "this folder is consistently missed by routing", "Claude hit max_turns here three times this week". None of that is possible without persistent history.
Scope
Add an append-only observation log stored under `.klonode/observations.jsonl` per project. Every tool_use event the server watcher extracts gets a line in this file.
Schema
```json
{
"at": "2026-04-15T21:11:34.455Z",
"sessionId": "120e914c-6c31-49a5-99a7-0ec67b527a13",
"cwd": "C:\Users\smorc\Desktop\KlonodeV2",
"tool": "Read",
"kind": "read",
"path": "packages/core/src/analyzer/scanner.ts",
"isSidechain": false,
"uuid": "2ecbe75a-...",
"toolUseId": "toolu_01Jp..."
}
```
Paths normalized to forward slashes and relative to the session's cwd (same normalization the activity store does, so downstream learning can join directly against graph node paths).
Server
- New module `packages/ui/src/lib/server/observation-log.ts` — append, read by range/session/path, tail for new-only reads.
- The session watcher writes each emitted event through this log before (or alongside) pushing it over SSE.
- Dedup by `uuid + toolUseId` so restarts and reconnects don't double-record.
- Bounded — rotate at say 50 MB per project, gzip older chunks.
CLI
- `klonode observations status` — counts per tool, per session, per path prefix.
- `klonode observations purge` — drop everything, start fresh.
Out of scope
- Doing anything with the data yet. That's the next issues (learning model repetition + emotion).
- Machine-wide observation log. This one is per-project so users can check in the graph but leave observations out (or vice versa).
Dependencies
Depends on nothing — builds directly on the server session watcher from #78.
Part of the #77 pivot roadmap.
Context
PR #78 landed the live session watcher (#77). It tails Claude Code JSONLs in real time and feeds the activity store for the live node graph. But the watcher is ephemeral — events flow through for the 8-second pulse lifetime and are then lost.
The learning model (repetition + emotion signals) needs to compute stats across sessions: "this file has been read 14 times across the last 10 sessions", "this folder is consistently missed by routing", "Claude hit max_turns here three times this week". None of that is possible without persistent history.
Scope
Add an append-only observation log stored under `.klonode/observations.jsonl` per project. Every tool_use event the server watcher extracts gets a line in this file.
Schema
```json
{
"at": "2026-04-15T21:11:34.455Z",
"sessionId": "120e914c-6c31-49a5-99a7-0ec67b527a13",
"cwd": "C:\Users\smorc\Desktop\KlonodeV2",
"tool": "Read",
"kind": "read",
"path": "packages/core/src/analyzer/scanner.ts",
"isSidechain": false,
"uuid": "2ecbe75a-...",
"toolUseId": "toolu_01Jp..."
}
```
Paths normalized to forward slashes and relative to the session's cwd (same normalization the activity store does, so downstream learning can join directly against graph node paths).
Server
CLI
Out of scope
Dependencies
Depends on nothing — builds directly on the server session watcher from #78.
Part of the #77 pivot roadmap.