---
kind: none
lifecycle: open
public: true
tags: [music, active-project]
---
# midi-harness

## AC (2026-06-09)

Jake, sync session (verbatim): **"a blog post + video about lessons from making a
harness."** When the post goes out, this node moves to archive. Declared under the
20-node-cap rework — this is the node's exit condition.

**Active-project briefing node** for the MIDI harness — one of Jake's two active
projects. The code lives in a **separate repo: `~/Documents/midi-harness`** (own
`.claude/`, own CLAUDE.md — none of it is streetlight's). This node is the vault's
single pointer + briefing; the repo is the source of truth.

## North star (Jake, 2026-06-09, verbatim)

> "The MIDI harness is an example of what I want it to be: a really simple system
> prompt and a hook that captures MIDI events from a JSON-L and then an HTML, so
> that we're basically just trying to give Claude the power to let me play a couple
> chords and then have an interesting discussion about music."

## The loop

```
MIDI keyboard ──> Go listener ──> events.jsonl ──> UserPromptSubmit hook
(Williams         (forever-        (append-only)    (cluster -> <played>
 Legato III)       running)                          block -> DELETE file)
                                                          │
       ┌──────────────────────────────────────────────────┘
       ▼
   Claude (46-word CLAUDE.md system prompt) ──> conversation about music
       │                                              │
       └───────── play more chords, repeat ◄──────────┘
```

The one idea: **emptying the log every turn IS the "since last message" boundary.**
No offset marker, no time window, no second clock, no audio.

## Blog diagram + recipe (2026-06-10 sync)

The html surface now carries the full blog-post diagram (USER at top forking into
MIDI-hands + Wispr-voice streams; hook steps numbered ① read whole file ② delete
③ clean up in memory ④ emit `<played>`; the raw→clean ratio example: 34 JSON
lines → 3 chord lines) and a recipe card (1 MIDI keyboard · Claude Code · Wispr
Flow · 1 Go listener ~90 loc · 1 Go hook ~160 loc · 1 system prompt 46 words ·
no database/server/audio/clocks). Facts verified against the repo source this
session. Notable: the hook is Go not JS (~1ms startup — it runs synchronously
before every message); the HTML finger-diagram ability is NOT a skill or prompt
line in the harness repo — Claude writes it ad hoc.

## Listener button (2026-06-10)

The html surface has start/status/stop controls for the listener, wired through
the local-viewer's `/api/run-script` (stream mode → live ♪-note scroll on the
page). Scripts live in this node dir: `listener-start.sh` (kill-then-exec
foreground, builds first), `listener-status.sh` (JSON pill, matches by binary
path so it sees terminal/hook-started listeners too), `listener-stop.sh`
(pkill regardless of who started it).

## Current state (checked 2026-06-09)

- Repo: `~/Documents/midi-harness`, 1 commit (`28f316b`), built 2026-05-29.
- Two Go binaries: `cmd/listener/main.go` (capture) + `cmd/hook/main.go` (inject + erase). Pure stdlib, ~0ms hook startup.
- Real use: ~10 sessions logged in the repo's `session-drain.md` (2026-05-30 → 2026-06-01).
- Uncommitted drift: `CLAUDE.md` modified, `future-ideas.md` + `session-drain.md` untracked.
- `future-ideas.md` parks timing/rhythm capture — deliberately NOT yet; harmony-read loop gets solid first.

## The ONE next thing

Commit the drift (the prompt-under-test should be the one on disk), then a fresh
practice session to keep calibrating the chord-read loop. Lesson on file: you can't
tune a system prompt from inside the session it governs ([[system-prompt-self-edit]]).

## Lineage

`midi-coach` (`~/Documents/midi-coach`, git: `github.com/jakesimonds/MCP-Dash-Demo`)
was the abandoned, more ambitious predecessor (Wispr/whisper interleaving, byte-offset
hook); `midi-harness-rebuild` was the 2026-05-29 strip-back that produced the current
repo. Both vault nodes now live in `archive/`.

## Note on this node's directory

`nodes/midi-harness/` also still contains an **earlier, different experiment** with
the same name: a Rust subtractive synth (`src/`, `web/`, `presets/`, `SYNTH.md`) plus
a Python listener prototype (`midi-listener/`, `transcripts/`). That code is dormant;
this node's surfaces now brief the Go harness repo. The old naming collision flagged
in midi-harness-rebuild resolved this way: the repo owns the name.

## Cross-links

- [[system-prompt-self-edit]] — why prompt edits must be tested in a fresh session
- provenance-x-ray (archived) — token deep-dive on a midi-coach answer
- archive: midi-coach, midi-harness-rebuild

Created 2026-05-27 · rebuilt as active-project briefing 2026-06-09.
