<!--
Lab Notes Practice Playbook

Part of the free Claude Code template library from BILT AI — https://biltai.io/claude-templates

These are the actual playbooks used to build and ship production SaaS apps with
Claude Code. They're written to be handed to an agent as-is: point Claude at one
and it has the full pattern, the schema, the gotchas, and the "don't do this"
list. Paths, project refs, and org names have been replaced with placeholders
(<your-app>, <supabase-project-ref>, <your-github-org>) — search for "<" and
fill in your own before running.

Free to use, modify, and ship. No attribution required.
-->

# Lab Notes Practice Playbook

**Portable discipline for maintaining a per-repo `CLAUDE.md` so future agents (and future-you) don't re-derive the same broken solutions.**

Built from the BKE / Kompozy workflow. Reference file: `CLAUDE.md` (25+ active lab notes).

---

## 0. What this is

The `CLAUDE.md` file at the root of each app repo is the **canonical agent-instructions doc**. It accumulates four kinds of knowledge that the agent must read before doing anything:

1. **Tooling decisions** — locked-in choices (bundler, port, persistence layer)
2. **Known issues + workarounds** — bugs in the stack that have proven workarounds
3. **Patterns to preserve** — hard-won architectural lessons
4. **Lab notes** — a running log of failed approaches with the date, the symptom, why it failed, and what to do instead

This playbook is meta: it tells you how to run the doc, not what to put in it for any specific app.

---

## 1. Why it matters

Without a persistent lab-notes log, every new agent session starts from zero and re-derives the same broken solutions. The 25+ lab notes in BKE's `CLAUDE.md` have saved hundreds of hours — across sessions, across agents, across human collaborators.

The single highest-leverage habit when working with Claude Code on a long-running codebase is **persisting failure modes to `CLAUDE.md` the moment you discover them**.

---

## 2. Lab notes format (strict)

One bullet per failed approach. Date prefix for chronology. Three-clause structure makes it scannable in 5 seconds.

```
- YYYY-MM-DD — <what was tried> → <why it failed> → <what to do instead>.
```

**Example (real, from BKE):**

```
- 2026-04-23 — Bulk-replace sync (DELETE non-matching + UPSERT) → wiped creator_profiles, user had to restore from backups → sync is upsert-only; deletes only from explicit user actions.
```

**Anatomy:**
- **Date** — when the failure happened (lets you correlate with git log + memory entries)
- **What was tried** — terse, concrete; reference file paths when applicable
- **Why it failed** — the load-bearing clause. Without this, future-you doesn't learn.
- **What to do instead** — the actionable lesson; the thing the next agent will follow

---

## 3. When to append a lab note

Append a new line to the Lab Notes section any of these moments:

- Any time a fix fails (the fix attempt itself failed, OR the fix worked but exposed a new bug)
- Any time you spent >30 minutes debugging something with a non-obvious answer
- Any time you reverted a commit
- Any time you found yourself thinking "don't try this approach again"
- Any time a third-party API/library behaved differently than its docs claimed

If in doubt, write the note. They're cheap. Skipping one and re-discovering the same problem next month is expensive.

---

## 4. CLAUDE.md section structure (mirror BKE's)

Every repo's `CLAUDE.md` should have these sections in this order. Reference: `BKE CLAUDE.md`.

1. **User preferences** — terse mode, no preamble, etc. (inherited from global)
2. **Session-scoped commits** — mandatory hard rules: stage by exact path, never `git add -A`, surface unrelated changes
3. **No assumptions** — verify, don't guess; read the file before citing it
4. **Known Issues & Decisions (locked-in)** — Next.js version, bundler (webpack not Turbopack), dev port, Tailwind setup, persistence layer, deployment target. These are **resolved** and should NOT be re-litigated by future sessions.
5. **Research already done — don't re-investigate** — pointer list of docs that should be read FIRST rather than re-web-searched (e.g. "GHL publish API quirks: see lab note 2026-04-12 + ghl-api-notes.md")
6. **Patterns to preserve** — generalized lessons (commit to IndexedDB before flipping UI state; persist synchronously inside the setState updater on success; arm watchdogs only after every async source has reported in)
7. **Lab notes** — the running failed-approaches log (this is the heart of the doc)
8. **Commands** — npm scripts cheat sheet (`npm run dev:webpack`, `npm run build`, etc.)
9. **Stack note** — one-liner reminder of versions (Next 16.x, React 19.x, Supabase JS 2.x, Trigger.dev 3.x)
10. **Architecture pointer** — link to the source-of-truth spec doc (e.g. `KONTENT_ENGINE_SPEC.md`)

---

## 5. Hygiene rules

- **NEVER delete old lab notes.** They're history. Old notes that are no longer load-bearing get archived (move to bottom under `## Lab notes (archive)` or split to `LAB-NOTES-ARCHIVE.md`) but never deleted.
- **Cross-reference lab notes to code with line numbers.** Format: `src/app/foo.ts:42`. Lets future-you jump straight to the offending line.
- **When fixing something that has a related lab note, UPDATE the note with the fix date + path.** Don't delete the failure record — append a `→ FIXED YYYY-MM-DD at src/path.ts:NN` tail. The failure history is the lesson; the fix is just the resolution timestamp.
- **One concern per bullet.** Atomic notes are searchable; multi-concern notes are not.
- **Date format is `YYYY-MM-DD`.** Sortable, unambiguous, ISO-friendly.

---

## 6. The memory layer (complement, not substitute)

Two layers, different jobs:

- **Per-repo `CLAUDE.md`** — repo-specific lab notes, decisions, patterns. Lives in the repo. Versioned with the code.
- **Global memory** — `~/.claude/projects/<project>/memory/MEMORY.md` — cross-project, cross-session, high-signal pointers. Lives outside the repo.

Memory entries may **point to** `CLAUDE.md` sections for high-value items (e.g. "BKE GHL publish needs manual userId — see CLAUDE.md lab note 2026-04-12"). They are not a replacement.

When in doubt: repo-specific → `CLAUDE.md`. Anything that generalizes across multiple apps → also write a memory entry.

---

## 7. Verify before citing

The injected `claudeMd` snapshot at the top of any given agent session **can truncate**. Before claiming "the CLAUDE.md says X" or "no rule about Y exists":

- READ the current `CLAUDE.md` file with the Read tool
- Grep it for the relevant keyword
- Confirm the rule still says what you think it says

Reference memory: `feedback_claudemd_full_read.md`.

Same discipline applies to logs before iterating: read Vercel / Trigger.dev / Supabase logs FIRST, not after the third failed redeploy. Reference: `feedback_verify_before_push.md`.

---

## 8. Bootstrapping `CLAUDE.md` for a new app

When spinning up a new repo:

1. Copy `BKE's CLAUDE.md` into the new repo root.
2. **Prune BKE-specific lab notes.** Keep ones that generalize (e.g. "PostgREST integer columns reject JS floats", "Trigger.dev needs NEXT_PUBLIC_APP_URL"). Delete ones that don't apply (GHL publish quirks, Pulse template rules).
3. Update the Stack note section with the new app's versions.
4. Update the Architecture pointer to the new app's spec doc.
5. Replace the Commands section with the new repo's `package.json` scripts.
6. Empty the Lab Notes section to a single placeholder: `- (no lab notes yet — append as failures surface)`.
7. Commit it as the very first commit of the repo.

---

## 9. Agent kickoff prompt

Every agent session on the repo should start with the agent being told to read `CLAUDE.md` before any work. Do not rely on the auto-injected snapshot — it may be truncated.

> Read `CLAUDE.md` in full before starting. Pay attention to the Known Issues & Decisions, Patterns to preserve, and Lab notes sections — these are non-negotiable. After reading, summarize the 3 most relevant lab notes for the task I'm about to give you. Then wait for the task.

This kickoff has two effects: (1) forces a fresh read past the truncation risk; (2) surfaces relevant prior failures into the agent's working context before it starts coding.

---

## 10. Common pitfalls

- ❌ **Don't combine multiple unrelated decisions in one lab note.** Atomic notes are searchable; multi-concern notes get half-remembered.
- ❌ **Don't write lab notes in conversation only.** If it's not persisted to `CLAUDE.md` by the end of the session, it's lost. The session ends, the context evaporates.
- ❌ **Don't put lab notes in code comments.** Discoverability is poor. Future agents grep `CLAUDE.md`, not random `// note:` comments.
- ❌ **Don't skip the "why it failed" clause.** Without it, future-you learns nothing — you just see "we tried X, don't try X" without understanding the boundary condition.
- ❌ **Don't archive too aggressively.** Even 12-month-old notes have value when the same library bug resurfaces after an upgrade.
- ❌ **Don't bypass `CLAUDE.md` in agent kickoff prompts.** The agent must be told to read it before starting. Auto-injection alone is not sufficient.
- ❌ **Don't write lab notes during a hot debugging loop.** Fix first, then append the note before closing the session. Writing mid-loop fragments your attention.
- ❌ **Don't let `CLAUDE.md` drift uncommitted.** Commit `CLAUDE.md` updates alongside the fix that triggered them. The note and the fix should land in the same commit when possible.

---

## 11. Worked example

A real flow from BKE:

1. Agent spends 2 hours trying to publish a GHL post. Keeps getting 422s.
2. Eventually discovers `media[].type` must be a MIME string, not a category alias.
3. Fix lands at `src/lib/ghl-publish.ts:142`.
4. Before closing the session, agent appends to `CLAUDE.md`:
   ```
   - 2026-04-15 — Sent GHL media with type: 'image' (category alias) → 422 invalid media type → use MIME string like 'image/png'; see src/lib/ghl-publish.ts:142.
   ```
5. Memory entry written: `feedback_ghl_media_no_type.md` pointing back to the `CLAUDE.md` note.
6. Commit message: `fix(ghl): use MIME for media[].type + lab note`.

Three months later, a new agent session hits an adjacent issue. It greps `CLAUDE.md` for `ghl media`, sees the 2026-04-15 note, jumps straight to `src/lib/ghl-publish.ts:142`, and saves the 2 hours.

That's the whole point.

---

**Reference paths:**
- `CLAUDE.md` — exemplar repo `CLAUDE.md` with mature lab notes section
- `~/.claude/projects/<project>/memory/MEMORY.md` — cross-project memory layer
- `~/.claude/projects/<project>/memory/feedback_claudemd_full_read.md` — verify before citing
- `~/.claude/projects/<project>/memory/feedback_verify_before_push.md` — read logs before iterating
- `CLAUDE.md` — global user instructions (the parent layer)
