@hraness/dawg 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/CHANGELOG.md +201 -0
  2. package/DAWG.md +762 -11
  3. package/README.md +79 -30
  4. package/core/chords.ts +1724 -0
  5. package/core/diff.ts +261 -0
  6. package/core/euclid.ts +670 -0
  7. package/core/fx.ts +1065 -0
  8. package/core/key.ts +43 -0
  9. package/core/kits.ts +320 -0
  10. package/core/params.ts +111 -0
  11. package/core/pitch.ts +60 -0
  12. package/core/rhythm.ts +287 -0
  13. package/core/score.ts +1054 -14
  14. package/core/sdk/eval-child.ts +125 -0
  15. package/core/sdk/eval.ts +260 -0
  16. package/core/sdk/print.ts +675 -0
  17. package/core/sdk/sync-chords.ts +54 -0
  18. package/core/sdk/v1.ts +4159 -0
  19. package/core/slug.ts +19 -0
  20. package/core/synth.ts +1001 -0
  21. package/package.json +8 -5
  22. package/src/agent/agent.ts +317 -16
  23. package/src/agent/brief.ts +50 -5
  24. package/src/agent/chord-tools.ts +357 -0
  25. package/src/agent/drum-tools.ts +135 -0
  26. package/src/agent/gateway.ts +215 -41
  27. package/src/agent/models.ts +633 -0
  28. package/src/agent/ops.ts +3 -18
  29. package/src/agent/pack-tools.ts +369 -0
  30. package/src/agent/planner.ts +55 -2
  31. package/src/agent/preview-tool.ts +270 -0
  32. package/src/agent/provider.ts +234 -106
  33. package/src/agent/rhythm-tools.ts +145 -0
  34. package/src/agent/sse.ts +31 -7
  35. package/src/agent/tools.ts +705 -14
  36. package/src/agent/usage.ts +296 -0
  37. package/src/agent/workspace.ts +683 -0
  38. package/src/agent/xcb-agent.ts +35 -14
  39. package/src/agent/xcb.ts +233 -21
  40. package/src/audio/audition.ts +93 -0
  41. package/src/audio/cache.ts +160 -0
  42. package/src/audio/click.ts +125 -0
  43. package/src/audio/effects/bus.ts +147 -0
  44. package/src/audio/effects/chain.ts +99 -0
  45. package/src/audio/effects/common.ts +251 -0
  46. package/src/audio/effects/convolution.ts +301 -0
  47. package/src/audio/effects/drive.ts +142 -0
  48. package/src/audio/effects/duck.ts +122 -0
  49. package/src/audio/effects/dynamics.ts +121 -0
  50. package/src/audio/effects/filter.ts +319 -0
  51. package/src/audio/effects/modulation.ts +174 -0
  52. package/src/audio/effects/space.ts +337 -0
  53. package/src/audio/engine.ts +430 -33
  54. package/src/audio/kits.ts +200 -0
  55. package/src/audio/live.ts +152 -0
  56. package/src/audio/packs.ts +1787 -0
  57. package/src/audio/player.ts +19 -4
  58. package/src/audio/preview.ts +470 -0
  59. package/src/audio/random.ts +15 -0
  60. package/src/audio/render-worker.ts +68 -0
  61. package/src/audio/renderer.ts +174 -0
  62. package/src/audio/sampler.ts +420 -0
  63. package/src/audio/samples.ts +1025 -0
  64. package/src/audio/synth/oscillators.ts +268 -0
  65. package/src/audio/synth/voice.ts +555 -0
  66. package/src/audio/synth/zzfx.ts +137 -0
  67. package/src/audio/wav.ts +550 -334
  68. package/src/audio/wavetable-maker.ts +717 -0
  69. package/src/audio/wavetable.ts +624 -0
  70. package/src/auth/cli.ts +146 -27
  71. package/src/auth/credentials.ts +167 -41
  72. package/src/auth/discover.ts +481 -0
  73. package/src/auth/login.ts +885 -128
  74. package/src/auth/openrouter.ts +206 -0
  75. package/src/auth/picker.ts +282 -0
  76. package/src/auth/runner.ts +25 -2
  77. package/src/auth/tui.ts +60 -43
  78. package/src/commands/drums.ts +299 -0
  79. package/src/commands/edit.ts +192 -0
  80. package/src/commands/fx.ts +360 -0
  81. package/src/commands/help.ts +535 -0
  82. package/src/commands/history.ts +32 -19
  83. package/src/commands/music.ts +34 -15
  84. package/src/commands/pack.ts +423 -0
  85. package/src/commands/rhythm.ts +230 -0
  86. package/src/commands/sample.ts +462 -0
  87. package/src/commands/synth.ts +229 -0
  88. package/src/commands/wavetable.ts +370 -0
  89. package/src/main.ts +2136 -170
  90. package/src/media/analyze.ts +364 -0
  91. package/src/media/backend.ts +253 -0
  92. package/src/media/cli.ts +186 -0
  93. package/src/media/download.ts +281 -0
  94. package/src/media/dsp.ts +281 -0
  95. package/src/media/import.ts +130 -0
  96. package/src/media/lyrics.ts +201 -0
  97. package/src/media/notes.ts +363 -0
  98. package/src/media/paths.ts +168 -0
  99. package/src/media/process.ts +226 -0
  100. package/src/media/registry.ts +9 -0
  101. package/src/media/sidecar.ts +72 -0
  102. package/src/media/stemdeck.ts +254 -0
  103. package/src/media/stems.ts +173 -0
  104. package/src/media/tools.ts +397 -0
  105. package/src/media/types.ts +92 -0
  106. package/src/media/vendor/basic-pitch.ts +261 -0
  107. package/src/media/vendor/drums.ts +817 -0
  108. package/src/media/vendor/grid.ts +203 -0
  109. package/src/media/vendor/util.ts +139 -0
  110. package/src/media/vendor/wav.ts +233 -0
  111. package/src/media/wavetable.ts +202 -0
  112. package/src/project/check.ts +80 -0
  113. package/src/project/init.ts +253 -0
  114. package/src/project/sync.ts +432 -0
  115. package/src/project/typecheck.ts +149 -0
  116. package/src/render.ts +49 -6
  117. package/src/session/attach.ts +3 -4
  118. package/src/session/daemon.ts +25 -8
  119. package/src/session/delta.ts +249 -0
  120. package/src/session/naming.ts +6 -38
  121. package/src/session/port.ts +26 -6
  122. package/src/session/rebase.ts +38 -8
  123. package/src/session/store.ts +116 -21
  124. package/src/tui/audition.ts +501 -0
  125. package/src/tui/euclid.ts +472 -0
  126. package/src/tui/menu.ts +2125 -0
  127. package/src/tui/play-chords.ts +538 -0
  128. package/src/tui/play-mode.ts +442 -0
  129. package/src/tui/play-session.ts +984 -0
  130. package/src/tui/sketch.ts +108 -0
  131. package/src/web/fetch.ts +340 -0
  132. package/src/web/http.ts +137 -0
  133. package/src/web/search.ts +684 -0
  134. package/tui/activity.ts +42 -3
  135. package/tui/app.ts +398 -33
  136. package/tui/drums.ts +44 -0
  137. package/tui/grammar.ts +281 -0
  138. package/tui/highway.ts +24 -2
  139. package/tui/layers.ts +14 -2
  140. package/tui/play-strip.ts +188 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,207 @@
2
2
 
3
3
  All notable changes to dawg are recorded here. Versions follow [semantic versioning](https://semver.org); releases are published as immutable GitHub Releases with a tarball, `SHA256SUMS` and a build provenance attestation.
4
4
 
5
+ ## Unreleased
6
+
7
+ ## 0.4.0
8
+
9
+ dawg now has a full sound engine with Strudel's synth, effect and sample parameters, Strudel sample packs, wavetables (including ones made from your own audio), Euclidean drum rows and a pattern library, Orchid-style chords, sound previews with A/B, and one consistent set of keys across every screen. Projects from 0.3.0 open and sound the same, and the `dawg` SDK is 1.13.0 (every step additive within v1).
10
+
11
+ ### Previewing changes
12
+
13
+ - **Audition loop in the edit menu.** `Space` loops the focused track (solo, or the whole mix with `c`), using its own notes over a region of at most four bars, or a short phrase by role when it has none (chord, riff, groove, or one held wavetable note).
14
+ - **Staged edits with A/B.** While the loop plays, menu changes are staged and heard within about 100 ms (only the changed track re-renders, off-thread). `a` flips between the committed and the staged sound, `Enter` keeps all staged changes as one revision and one undo step, `Esc` reverts. Changed rows show `staged ← committed`. Edits from another window are re-applied under the staged ones.
15
+ - The audition controller (`src/tui/audition.ts`) and the preview score builder (`src/audio/preview.ts`) are reusable by any screen; a preview renders byte-identical to the same bars of a full render.
16
+ - **Hover to hear lists.** With the loop on, moving through a list (wavetables, instruments, drum kits, patterns, choice lists in `/menu`, and the `/kit` and `/pattern` pickers) plays the highlighted item on the loop. Hovers replace each other, fast moves skip straight to the latest item, and a pack sound that needs fetching shows `fetching…` without blocking the cursor. Enter chooses, Esc leaves with nothing changed.
17
+ - **The agent can hear before it commits.** `preview_sound` renders a track, or candidate `set_fx`/`set_synth`/`set_wavetable`/… calls applied to a copy, over the audition loop's bars, and returns RMS/peak dBFS, spectral centroid, a description and a comparison with the current sound. It plays once in a quiet window; `/try agent off` keeps it silent.
18
+ - **Audition visuals.** The menu title shows a level meter with a clip mark while the loop plays, and the focused cutoff, envelope or wavetable position row draws a one-line sketch of its response.
19
+ - **`/try <sound command>`** hears a prompt command on the loop first: `/try fx reverb mix 0.6`, then `a` for A/B, Enter to keep (one undo step) or Esc to drop it.
20
+
21
+ ### Effects
22
+
23
+ - **A full effects chain on every track**, in a fixed order: filter → dj filter → auto filter → vowel → bitcrush → distortion → tremolo → compressor → pan → phaser → chorus → leslie → post gain → delay → reverb. Each effect turns on with a good default and has a few simple parameters, with the rest under **advanced**.
24
+ - **Filter** gains `type` lpf/hpf/bpf and a 12 dB, 24 dB or ladder slope. **Auto filter** sweeps the cutoff with a tempo-synced or free LFO (sine, triangle, square, saw, ramp, sample-and-hold) and can follow the input's envelope.
25
+ - **Delay** turns on as a dotted-eighth stereo ping-pong with gentle feedback and a high-cut on the repeats. **Reverb** adds decay time, damping and pre-delay.
26
+ - **Distortion** (ten curves, tone, mix, automatic gain compensation), **compressor** (threshold, ratio, knee, attack, release, make-up), **chorus**, **tremolo**, plus Strudel's dj filter, vowel, bitcrush/coarse, phaser, leslie and post gain.
27
+ - Parameter names follow Strudel's (`lpq`, `delayfeedback`, `room`, `tremolodepth`…), and every numeric parameter can be automated (`automate distort-drive points 0:1 8:6`).
28
+ - **`fx` prompt command**: `fx delay mix 0.3`, `fx filter type hpf cutoff 300`, `fx chorus preset wide`, `fx tremolo off`. The Effects menu lists the core effects first, with presets. The agent's new `set_fx` tool sets the same parameters.
29
+ - **ZzFX sounds**: `instrument z_square` (and `z_sine`, `z_triangle`, `z_sawtooth`, `z_tan`, `z_noise`) with Strudel's ZzFX controls as synth parameters: `synth slide -4 pitchJump 300 pitchJumpTime 0.1 lfo 0.25 zcrush 0.3`, plus `zrand`, `curve`, `deltaSlide`, `zmod`, `zdelay`, `tremolo` and the `zap` preset. Clean-room, deterministic. SDK 1.10.0 (additive).
30
+ - **Orbits and sidechain ducking**: `fx orbit 2` puts a track on orbit 2; `fx duck preset pump` on a kick dips every track on that orbit at each hit and lets it swell back (Strudel's `orbit`, `duckorbit`, `duckdepth`, `duckattack`, `duckonset`). SDK 1.9.0 (additive).
31
+ - **Convolution reverb** (Strudel `ir`/`iresponse`): `fx reverb ir hall` (also `room`, `plate`, a pack sound or a project WAV), with FFT convolution; `fx ir off` returns to the algorithmic tail. SDK 1.12.0 (additive).
32
+ - **Shared orbit buses**: `fx orbit shared on` sends a track to one delay and one reverb shared by its orbit, as Strudel orbits do.
33
+ - **Raw ZzFX arrays**: `synth zzfx ,,129,.01,,.15,2`, SDK `zzfx([...])` and `set_synth { zzfx }` map ZzFX's positional array to the named controls.
34
+ - **Strudel sample controls** on sampler voices: `loopBegin`/`loopEnd`, `clip` (`legato`), `fit`, `unit` "c"/"s", `loopAt`, `accelerate` and `squiz`, beside `begin`/`end`/`speed`/`loop`/`cut`. `/sample set brk fit on clip 1`, the per-voice menu and the agent's `set_sample` tool edit them. SDK 1.13.0 (additive).
35
+ - Older projects and sessions load and sound exactly as before. The `dawg` SDK is 1.5.0 (additive).
36
+
37
+ ### Synth
38
+
39
+ - **A full synth voice with Strudel's parameters.** `synth` on a track takes Strudel's names and aliases: sine, sawtooth, square, triangle, supersaw, pulse, additive `user` and white/pink/brown/crackle noise; `noise`/`density`; `unison`/`detune`/`spread`; pulse width with `pwrate`/`pwsweep`; eight FM operators (`fm`, `fmh`, an ADSR, `fmenv`, `fmwave`); ADSR; a pitch envelope (`penv`…); vibrato; and low-, high- and band-pass filters with envelopes and `ftype`.
40
+ - **Presets**: pad, lead, pluck, bass, sub, acid, keys, bell, organ, strings, brass, wind, chip.
41
+ - **`synth` prompt command**: `synth preset pad`, `synth lpf 800 lpenv 3`, `synth fm 4 fmh 1.5`, `synth reset`. The menu's Parameters section shows the preset and simple parameters, with every parameter under **advanced**. The agent's new `set_synth` tool sets the same parameters. Every numeric parameter has a `synth-<param>` automation lane.
42
+ - Older projects and sessions load and sound exactly as before. The `dawg` SDK is 1.6.0 (additive).
43
+
44
+ ### Rhythm (Euclidean rows)
45
+
46
+ - **Drum parts as generators.** A kit or oneshot sampler track can carry `rhythm` rows: `euclid("kick", 4, 16)`, `euclid("hat", 7, 16, 2, { swing: 0.15 })`, `grid("snare", "....X.......x...")`. dawg expands them into ordinary notes, so you and the agent edit four numbers instead of sixteen hits, and rendering, sync and diffs are unchanged. Patterns and rotation match Strudel's `euclid`/`euclidRot`.
47
+ - **Torso T-1 parameters**: steps, pulses, rotate, division, repeats with time/pace/ramp (rolls that speed up, slow down, build or fade), velocity, accent, gate/legato, seeded probability, swing, nudge and per-pass cycles. The same seed always gives the same hits.
48
+ - **`/euclid` editor** (also Rhythm in `/menu`): one row per voice with its step grid. Arrows nudge the selected parameter, Tab moves between parameters, digits type a value, Space auditions. Every change is one undo step.
49
+ - **Prompt grammar**: `euclid kick 4 16`, `euclid hat 7 16 rotate 2`, `euclid hat swing 0.2`, `euclid snare off|freeze`, `grid snare ....X.......x...`.
50
+ - The agent's new `set_rhythm` tool takes the same rows, and the agent prefers it to hand-placed drum hits.
51
+ - Editing a generated lane by hand freezes that row into plain notes. Changing the loop length regenerates rows.
52
+
53
+ ### Chords
54
+
55
+ - **Chord engine (`core/chords.ts`)** modelled on the Telepathic Instruments Orchid: four chord types (dim, min, maj, sus) with combinable 6, m7, M7 and 9 extensions, Key-mode diatonic chords for major, minor and the church modes, a voicing dial, voice leading to the nearest inversion, bass, and block, strum, arpeggio and harp performance.
56
+ - **Progressions.** Eleven presets (I–V–vi–IV, ii–V–I, i–VI–III–VII, the Andalusian cadence, …) and pop, jazz, modal and classical styles that walk a weighted functional-harmony graph with a seed, so the same request always gives the same chords.
57
+ - **Secret chords from the Orchid manual.** Two latched chord types now play the official table: dim+sus C5, maj+sus C+, min+sus Cm(add4), min+dim Cm(b6), maj+dim C(b6), maj+min C7♯9 (they replace dawg's earlier guesses).
58
+ - **Slop perform mode**, Orchid's humanised timing: a block chord whose voices land a seeded fraction of up to 1/16 beat late (SDK 1.5.0, `perform: "slop"`).
59
+ - **Pattern perform mode** with thirteen chord rhythms (eighths, offbeat, pop, charleston, bossa, skank, tresillo, oom-pah, …) by name or number: `/chords pattern 3`, `9` in play mode, the menu, `write_chords {perform: "pattern", pattern}` and SDK 1.7.0 `perform: "pattern", pattern: "bossa"`.
60
+ - **Orchid bass modes.** Bass is now `off`, `chords`, `unison`, `single` or `solo`, as in the Orchid's bass menu: `B` in play mode cycles them, `/chords bass unison`, the menu, `write_chords {bassMode}` and SDK 1.7.0 `bass: "solo"`.
61
+ - **Agent tools.** `suggest_progression` returns voice-led chords with names, numerals and bass; `write_chords` writes them to a track (and its bass to another) as block chords, strums, arpeggios or harp sweeps.
62
+ - **SDK 1.3.0.** `chord("Cm7")` and `progression(["ii7", "V7", "Imaj7"], { key, perform })` expand to notes in `track.ts` files.
63
+ - **Chord mode in play mode**, on by default (`auto`) for chord-capable tracks: every note key plays the song key's diatonic chord, voice-led from the last one. `1`–`4` latch dim/min/maj/sus, `5`–`8` latch 6/m7/M7/9, `0` clears, `-`/`=` turn the voicing dial, `9` cycles the perform mode, `B` toggles bass, `N` plays the suggested next chord and `Q` switches auto ⇄ manual. The header shows the mode, key, current chord and the suggestion. Recorded chords keep their strum or arpeggio and stay one undo step per bar.
64
+ - **`/chords`** and a Chords section in `/menu` edit the same settings; **`key <tonic> <mode>`** sets the song key.
65
+
66
+ ### Wavetable synth
67
+
68
+ - **`instrument: "wavetable"`**: a band-limited wavetable oscillator (per-octave mipmaps, smooth frame interpolation) with Strudel's parameter names: position `wt`, a position envelope (`wtenv`, `wtattack`, `wtdecay`, `wtsustain`, `wtrelease`), a position LFO (`wtrate`, `wtdepth`), `warp`/`warpmode` (`asym`, `bendp`, `bendm`, `bendmp`, `sync`, `quant`) and `wtphaserand`. `wt` is automatable.
69
+ - **Tables**: four built-ins that work offline (`basic`, `pwm`, `formant`, `harmonics`) and Strudel's `wt_` sounds (`wt_digital:2`) from the new `uzu-wavetables` pack, fetched once and pinned by sha256 like any pack sound.
70
+ - **`/wt <table|0..1|list>`**, one command per parameter (`/wtenv 0.5`, `/warpmode bendp`), the table picker and parameters in the menu's Parameters section, and the agent's `set_wavetable` tool. Play mode plays wavetable tracks.
71
+ - It runs through the new synth voice, so ADSR, filter envelopes, FM, unison/detune and vibrato apply to wavetable tracks too.
72
+ - SDK 1.8.0 (additive): `wavetable("basic", { wt: 0.4 })` as a track's `instrument`, and `automation: { wt: [...] }`.
73
+
74
+ ### Wavetables from audio
75
+
76
+ - **`make_wavetable`**, a new agent media tool (`dawg media wavetable <file> <name>` from the shell): turns any audio in the project (a download, a stem, an imported sample) into a 2048-sample-frame wavetable at `tracks/<slug>/wavetables/<name>.wav`. Pitched material is sliced into single cycles at the detected pitch; vocals, pads and noise become spectral snapshots. It picks the most stable tonal region by default, phase-aligns and normalises the frames, and tells the agent how the timbre moves across the table (for example "brightens, very smooth morph") so it can choose a position or envelope. Output is deterministic.
77
+ - **Project tables play like any other table**: `/wt vox.wav`, the menu's table picker (project tables are listed first), `set_wavetable` with the path, and `wavetable("./wavetables/vox.wav")` in `track.ts`. They are pinned by sha256; a changed file plays with a warning, a missing one is reported with a fix.
78
+ - SDK 1.11.0 (additive): `wavetable()` accepts a project `.wav` path.
79
+
80
+ ### Sample packs
81
+
82
+ - **Strudel's sample ecosystem, read through its public manifest format** (clean-room, no Strudel code). Built-in catalog: tidal-drum-machines, dirt-samples, uzu-drumkit, VCSL, piano, mridangam, emu-sp12 and two General MIDI soundfonts, each with its license.
83
+ - Files download lazily on first use over HTTPS and are cached offline. A sampler voice can point at `pack:<pack>/<sound>[:<n>]`, and first use pins its sha256, URL and license. SDK 1.1.0 (additive).
84
+ - `/pack list|add|info|remove|use`, `/kit <bank>`, a sounds list in the menu, and agent tools `list_packs`, `search_sounds` and `use_sound`.
85
+ - Renders credit the packs they use, and projects using CC-BY or CC-BY-SA packs get a `CREDITS.md`.
86
+
87
+ ### Sample packs: bank nicknames and cache sizes
88
+
89
+ - **Bank nicknames.** Strudel's drum-machine nicknames (`TR909`, `tr808`, `Linn`, `DMX`, `SP12`, `MPC60`, … from its `tidal-drum-machines-alias.json`) work in `/kit`, `/pack use`, `pack:` refs in `track.ts`, the agent's `use_sound` and a new **Strudel banks** list in the menu's drum kits. dawg ships a snapshot and refreshes it with the manifest. `909`, `808`, `linn` and the other short names work as before, and pins keep the full bank name.
90
+ - **`/pack cache`** shows disk used by pack downloads and decoded audio against their caps; `/pack cache prune [size]` and `/pack cache clear` evict least recently used files and keep the open project's sounds.
91
+ - Pack downloads are now capped at 2 GiB (they were uncapped) and decoded audio at 1 GiB per project (was 512 MiB), overridable with `DAWG_PACKS_CACHE_MAX` and `DAWG_ASSETS_CACHE_MAX`. Eviction never removes a file the open project uses; an evicted pack file re-fetches by its pinned sha256.
92
+
93
+ ### Drum patterns and kits
94
+
95
+ - **Pattern library.** 31 starting grooves (house, techno, boom bap, trap, drill, dnb, reggaeton, afrobeats, bossa nova, samba, garage, jersey club, footwork, funk and more), each a set of rhythm rows you keep editing as parameters. `/pattern` opens a picker that plays one bar of the pattern under the cursor; `/pattern <name> [keep-tempo|tempo]` applies one and moves the tempo into the pattern's range when needed. Also under Sounds → Drum patterns in `/menu`, and `pattern("boom-bap")` in `track.ts`.
96
+ - **Synthesized kits.** `kit: "syn808" | "syn909" | "acoustic" | "lofi" | "electro" | "trap"` on a drum track, or `/kit <name>`, chooses an offline drum synth sound. Tracks without a kit sound exactly as before.
97
+ - **One kit picker.** A bare `/kit` now opens a picker of every kit, synth kits first and then the sample kits from packs (it used to apply the 909 sample kit directly; `/kit 909` still does). `/kit syn909` on a sampler kit turns it back into a synth kit.
98
+ - The agent's new `list_drum_patterns`, `apply_drum_pattern` and `set_drum_kit` tools, and it starts genre grooves from a pattern.
99
+ - SDK 1.4.0.
100
+
101
+ ### Menus (reorganised)
102
+
103
+ - **`/menu [section]` or Ctrl-K** opens six plain sections, most used first: **Sound**, **Effects**, **Rhythm**, **Chords**, **Mix & automation** and **Project**. The old section names (`parameters`, `sounds`, `track`, `automation`, `transport`) still open the matching place.
104
+ - Rows show a plain label and the value with its unit (s, Hz, oct, st, dB, BPM, bars); a line under the list describes the focused row and shows, dimmed, the prompt command it runs. Every change is one receipt and one undo step; `x` resets a value to its default.
105
+ - New prompt commands behind the menu: `automate <lane> points <b:v>...`, `automate <lane> remove <beat>`, `track name <text>` and `meter <n>`.
106
+
107
+ ### One key grammar
108
+
109
+ - **Every picker, menu, editor and panel uses the same keys**: `↑↓`/`j k` move, `←→`/`h l`/`- +` adjust, Enter opens or confirms, Space auditions or toggles, `/` filters, Esc goes back one level (filter or typed value first), `?` shows the keys for the current screen. Digits type a value only where one is focused.
110
+ - **A one-line key footer on every screen** that fits 80 columns; when narrower it drops the middle and keeps `esc` and `? keys`.
111
+ - **`?` panel**: the keys for the screen underneath, drawn over it; on an empty prompt it lists the prompt keys and the three ways in (type a request, Ctrl-P, Ctrl-K). In play mode it also holds velocity, grid, click, count-in and the chord settings.
112
+ - **Play mode header** keeps range, record state and the chord at a glance (`AUTO C major · Dm (ii) · next G`); chord mode adds a legend row for the number-row latches.
113
+ - The `/euclid` editor is titled **rhythm** and its rows use the shared keys; pickers report the highlighted row on every move (`pick-move`), the hook live previews (and a future audition controller) listen on.
114
+
115
+ ### Help
116
+
117
+ - **Sentences reach the agent**: a request that merely starts with a command word (`add a walking bass in A minor`, the prompt's own example, or `pan the hats left`) goes to the agent instead of answering with the command's usage. Short or numeric misuse (`pan 3`, `add H4 at 0`) still gets the usage hint locally.
118
+ - **`/help` is a short task guide** (start here, play notes, make drums, shape the sound, chords) pointing to Ctrl-K, Ctrl-P and `?`; `/help all` is the full reference and `/help music|session|window|keys` shows one group. The reference now lists `fx`, `synth`, `/pattern`, `/kit` and `/pack`.
119
+ - **Typos get the nearest command**: `/clik on` answers `unknown command /clik · did you mean /click? · /help` instead of a bare "unknown". Entering play mode says `? keys · esc leaves` instead of listing four keys.
120
+ - **Bare-word slips are caught too**: `tempoo 90` answers `did you mean tempo 90?` without a model call when the rest parses as that command's arguments; sentences still go to the agent.
121
+ - **First run names the three ways in**: an empty track reads `<track> · empty · type a request · ctrl-p play · ctrl-k menu` (narrow windows keep `add C4 at 0 to start`).
122
+ - **The play `?` panel's chord line uses the header's words** (`next G`, `(assumed)`, `voicing +1`) instead of `→`, `?` and `inv`.
123
+
124
+ ### Fixed
125
+
126
+ - Rhythm rows with options but no rotate printed as `euclid("hat", 8, 16, { … })`, which the SDK read as a rotate and rejected. The printer now writes rotate 0, and the SDK accepts options in that position.
127
+ - Gateway web searches no longer count the search fee twice in the spend line and ledger. The gateway's reported cost already includes it. A real Exa search response is now a test fixture.
128
+
129
+ ## 0.3.0
130
+
131
+ dawg projects are now plain TypeScript files that you, an agent or another window can edit, with sampler tracks, local media tools, a computer-keyboard play mode and menus for every edit by hand.
132
+
133
+ ### Play mode (computer keyboard)
134
+
135
+ - **`/play` or Ctrl-P** turns the computer keyboard into a MIDI keyboard for the focused track: `A S D F G H J K L ; '` are white keys from C, `W E T Y U O P` the black keys, `Z`/`X` move an octave, `C`/`V` change velocity, Shift sustains and Tab latches sustain. Esc leaves.
136
+ - Bass tracks start an octave lower and leads an octave higher; the header shows the range, velocity, record state, click and grid.
137
+ - **Recording.** `R` arms overdub and `Shift-R` replaces the bar; notes are quantized to `/grid` and land as ordinary score edits, so other windows, undo and `track.ts` all see them. One undo step per recorded bar.
138
+ - **Click track.** `M` or `/click on|off|<volume>` toggles a tempo-synced metronome that never reaches renders or exports; `/count-in 0|1|2` sets the count-in before recording.
139
+ - Sampler tracks play their voices from the keyboard: oneshot voices from MIDI 36, keyed samplers repitched from their root.
140
+ - Terminals send no key-up, so held notes last one grid step and extend while the key auto-repeats.
141
+
142
+ ### Menus
143
+
144
+ - **`/menu [section]` or Ctrl-K** opens Track, Parameters, Effects, Automation, Mix and Transport. Arrows or `j k` move, Enter opens or toggles, `← →` or `+ -` nudge, digits type a value, `/` filters, `x` deletes an automation point, Esc steps back.
145
+ - Each row shows its current value and the command it runs; every change is one receipt and one undo step.
146
+ - New prompt commands behind the menu: `automate <lane> points <b:v>...`, `automate <lane> remove <beat>`, `track name <text>` and `meter <n>`.
147
+
148
+ ### Performance
149
+
150
+ - Session records store reverse deltas instead of whole compositions, so a session reaches the 2000-event cap instead of failing around edit 70 (or on the first edit of a 16-bar loop).
151
+ - Audio renders run off the main thread with a per-track stem cache: a one-note edit re-renders in about 44 ms instead of blocking for 165–190 ms.
152
+ - AI Gateway and OpenRouter requests retry and time out when no response arrives; transport keys no longer wait on the daemon.
153
+
154
+ ### Sample playback
155
+
156
+ - **Sampler tracks play.** `sampler({...})` voices now render in playback, `dawg render` and exports, with Strudel's semantics: `begin`/`end` windows, `speed` (negative reverses), `loop` for the note's length, `gain`, `choke` groups (Strudel's `cut`), keyed repitching from `root`, and oneshot voices on pitch slots from 36. Starts, stops and cuts fade over a few milliseconds. Volume, pan, automation, filter, delay and reverb apply as on any track, and sampler tracks are cached stems keyed by the files' sha256.
157
+ - **Decoding.** WAV (PCM 16/24/32-bit and float32) and AIFF decode natively and resample to the engine rate; MP3, FLAC, Ogg and M4A decode through `ffmpeg` when it is on `PATH`, otherwise the voice is skipped with a diagnostic. Decoded audio is cached at `.dawg/assets/<sha256>.pcm` (512 MiB LRU). Files over 50 MiB or 10 minutes and paths that escape the project, symlinks included, are rejected; a stale `sha256` warns and still plays.
158
+ - **`/sample <path> [as <voice>]`** adds a voice to the focused track (copying the file into `tracks/<slug>/samples/` and reprinting `track.ts`); `/sample` lists voices. Oneshot samplers get one highway lane per voice, `/tracks` shows sample counts and missing files, and load problems are receipts.
159
+ - `dawg render` in a project with no `--session` renders the project files (`song.ts`).
160
+
161
+ ### Sign-in, model picker and spend
162
+
163
+ - **One sign-in picker.** `dawg login` (and the first `dawg` with no provider) finds what is already set up, in parallel within 4 s: `AI_GATEWAY_API_KEY`, `OPENROUTER_API_KEY`, stored keys, a logged-in Vercel CLI, `VERCEL_OIDC_TOKEN`, and xcb Codex and Claude accounts. It then shows one Codex-style picker (arrows, numbers, Enter), with the first detected option as the default. When one option is ready, it asks `Use <it>? [Y/n]`. Non-interactive runs pick the best detected option or exit with a hint.
164
+ - **OpenRouter** is a fourth provider. Sign-in is OpenRouter's OAuth PKCE flow (browser plus a `127.0.0.1` callback with a state check, URL printed as a fallback, 5 min timeout), or a pasted key with hidden input. Turns stream with tool calls through the same agent tools as the gateway.
165
+ - **Subscriptions** (`dawg login codex`, `dawg login claude`) go through xcb 0.20+: pick the account and model, and dawg runs `xcb setup <family>` when none is ready. An account is usable iff xcb reports `available`. Pending admission works, with a longer first call (the child timeout is `timeoutMs + 75 s`) and `busy` retried with backoff. Accounts reporting `models_unavailable` are refreshed once, and `dawg auth status` prints the xcb version with an upgrade hint below 0.20.0.
166
+ - **The choice sticks.** The provider, model and account are saved in `~/.config/dawg/config.json` (0600, atomic, no keys) and reused silently. `dawg logout [provider]`/`/logout`, `dawg login <provider>` and `/model` change it. A saved provider that stops working is reported once and reopens the picker, never swapped.
167
+ - **`/login` in the TUI** suspends the screen, runs the same flow (browser and `vercel login` included) and redraws, replacing "run dawg login in a shell".
168
+ - **Model picker.** `/model` or `dawg model` lists frontier (Opus 5.5, Fable 5.1, GPT-6.1 Sol, Gemini 3.1 Pro), fast (Sonnet 5.5, Haiku 4.5, GPT-5.4 mini, Gemini 3.8 Flash) and open-weight models (DeepSeek V4 Pro, Kimi K3, Qwen3.8 27B, GLM-5.3, Llama 4 Maverick). Only tool-calling models the provider serves are listed. Each row shows an estimated `~$0.004/prompt` from models.dev pricing (cached 24 h; OpenRouter's own prices on OpenRouter), and subscriptions list xcb's models as `included`. Type to filter; the current model is marked. `DAWG_MODEL=<unknown>` is now an error listing the choices.
169
+ - **Spend under the prompt.** `$0.12 session · $0.48 today · opus-5.5 · gateway`, from the usage each response reports (`include_usage`; the provider's cost when given). Today's total is shared across windows through `~/.config/dawg/usage.json`. Billed web searches count too. Subscriptions show `subscription`; with no provider it reads `no model · dawg login`, the placeholder teaches direct commands and the STEER pill hides. The model shows once, in the header.
170
+ - `dawg auth status` lists all four options with detected, active and validated state.
171
+
172
+ ### npm
173
+
174
+ `@hraness/dawg` is on npm: `npm i -g @hraness/dawg` or `bun add -g @hraness/dawg`, alongside the install script and the GitHub Release tarball.
175
+
176
+ ### UX review fixes
177
+
178
+ - `/track <name>` (and bare `track <name>`) focuses the track in this window, creating it when new; a track another window has open answers `<name> is open in another window`. The quickstart `track drums` → `pattern kick …` now works.
179
+ - Receipts carry their outcome structurally, so `main is not a drum track`, `no kick hits`, `score is full` and friends render as errors instead of green checks.
180
+ - An unknown `/word` is rejected locally and a known verb with bad arguments (`pan 3`, `volume 2`, `add H4 at 0`, `/export` with no file) gets usage; neither reaches the model.
181
+ - `/help` (or `?`) opens a grouped, scrollable overlay listing every command once; `/sessions` and `/tracks` open the same overlay and leave one summary card.
182
+ - `dawg --version`; unknown subcommands and options are rejected before `.dawg/` is created; the launch that creates `.dawg/` says `created .dawg/ · add it to .gitignore`; `dawg --session <typo>` is an error instead of a silent new session; `render --help` and `sessions --help`.
183
+ - `/resume <n>` accepts any list index as well as a name or id prefix.
184
+ - Errors share one shape, `<what> · <why> · <next step>` (`no such file · nope.json`).
185
+ - The `^z undo` hint rides only on receipts that changed the score, and only the first three in a session.
186
+ - An empty track shows `main · empty · add C4 at 0 to start` instead of stray lane labels.
187
+ - `/status` says `shared via dawgd` or `saved locally · no daemon`; auto-names announce as `<name> (auto-named) · rename with /rename <name>`.
188
+ - Docs: header order frozen in a test and corrected, render is stereo, the `meta` frame is listed, one environment table.
189
+
190
+ ### Agent workspace and web tools
191
+
192
+ The agent can now work with the project directory and the web. `list_files` and `read_file` cover the whole project except `.dawg/`; `write_file` and `edit_file` are limited to `song.ts` and the focused track's `tracks/<slug>/` directory, write atomically and cap sizes. `web_search` answers through the AI Gateway's server-side search tools when a gateway key is configured (`DAWG_WEB_SEARCH` picks `exa`, `perplexity`, `parallel` or `browserbase`), through OpenRouter's `web` plugin when an OpenRouter key exists, and otherwise through DuckDuckGo; `BRAVE_SEARCH_API_KEY` overrides the chain. `fetch_url` reads one public page with private-address blocking and bounded output. The composition brief includes a bounded project tree and the head of the focused track's `notes.md`. New `trackSlug()` in `core/slug.ts` and an optional `onWorkspaceWrite` host hook.
193
+
194
+ ### Project files
195
+
196
+ - `dawg init [dir]` creates a project: `dawg.json`, `tsconfig.json`, `song.ts`, `tracks/`, a vendored typed SDK in `.dawg/sdk/v1.ts` and `.gitignore` lines. It is idempotent and refreshes the SDK only for a newer 1.x.
197
+ - Every window keeps `song.ts` and `tracks/<slug>/track.ts` in two-way sync with the session: file edits apply as one `files.apply` revision (`applied from files · …`, or `files rejected · <file:line:col …>`), and score edits reprint only the files that changed.
198
+ - `dawg check` typechecks (native TypeScript 7, incremental) and evaluates the project; the header shows `types ✓` or `types ✗ N`. Agent writes to project sources report the apply outcome and type errors in the tool result.
199
+ - Score: optional `sampler` on tracks (validated, rendered silent for now) and `removeTrack`, `moveTrack`, `setKey`, `setMeter` operations. The format stays `track.loop/v1`.
200
+ - `typescript` is now a runtime dependency; the package ships `core/sdk/**`.
201
+
202
+ ### Local media tools
203
+
204
+ Six agent tools and `dawg media <verb>` turn reference audio into track material under `tracks/<slug>/downloads/`: `download_audio` (YouTube via yt-dlp or StemDeck, with a sidecar and reuse), `split_stems` (six stems via StemDeck or demucs), `analyze_audio` (tempo, key, beat grid, waveform), `transcribe_notes` (drums via a vendored classifier, pitched stems via basic-pitch, quantized to `note()`/`hit()` snippets), `import_sample` (48 kHz stereo `samples/<name>.wav` and a `sampler()` snippet) and `transcribe_lyrics` (whisper-cli). StemDeck at `DAWG_STEMDECK_URL` is preferred when it answers; dawg never installs a binary and `dawg media doctor` names the install commands. Helpers report progress on the activity card, are bounded in time and output, are stopped with SIGTERM then SIGKILL on Esc, and pause the turn deadline while they run.
205
+
5
206
  ## 0.2.0
6
207
 
7
208
  The first tagged release. Open a session in several terminals, give each window its own instrument, let an agent write parts, and every window stays on the same song.