Skip to content

ADR-0058: WavAmpster is a first-party program; its bin and capability id are knamp

this ADR extends), ADR-0015 (CIPHER owns the OLED, so WavAmpster does not draw there), ADR-0017 (the deck’s audio chain), knamp-stations.md (the station package format), 2026-06-24-knamp-design.md (deleted 2026-07-29; recover from git history) (the approved brief)


WavAmpster is the deck’s music player: a build-time tool packages a folder of MP3s or WAVs into a station (rendered PCM plus a station.knst manifest), and on the deck the operator browses stations, tunes one, and it keeps playing in the background while they use the rest of the machine. It shipped across four PRs in June 2026 (GWP-599, GWP-678, GWP-679) and has been running in the emulator since.

ADR-0042 closed the first-party program roster at thirteen and set the rule that adding a program takes a successor ADR: “Stub programs are acceptable at launch; unchartered programs are not.” WavAmpster has been a routable program in screen_router.c with no ADR behind it. The brief that approved the build predicted this gap and listed a charter as the follow-on. This ADR closes it.

The naming also needed a decision. The program was renamed to knAmp in June to fit the deck’s kn-prefixed family, and the implementation branches (cut before that rename, merged after it) put the old name back everywhere. Two names have been live in the tree since.


WavAmpster joins the ADR-0042 roster as the fourteenth first-party program, under the same rules as the other thirteen. Its operator-facing name is WavAmpster; every identifier is knamp.

  1. WavAmpster is program #14 on the ADR-0042 roster. It is a first-party program: it ships in the system image, is always present regardless of what cart is in the slot, has no Capability Registry presence, no cartridge_history entry, and is never superseded by a cart. A cart may ship stations; it never gates access to the player.

  2. The name splits by audience. “WavAmpster” is what the operator sees: the headline, the status-bar title, prose in docs. knamp is what anything typed or referenced uses: the packaging binary, the Rust crate, the launch-app program id, the screen-router entry, the Lisp namespace (knamp/…, knamp-mode), runtime/programs/knamp/, and the doc filenames.

  3. The player engine stays in C; the screen stays in Lisp. station.c owns discovery, transport, and the PCM mix because the Fe tick fires only for the active screen and background audio has to outlive the mode. runtime/programs/knamp/knamp.lsp is a control and view surface over the station-* FFI. This split is the reason background playback works, and it is the only part of the program that is not Lisp.

  4. All decode happens at build time. The knamp tool decodes MP3 and WAV on a workstation and emits S16LE / 44.1 kHz / mono PCM. The deck has no decoder and streams the rendered PCM only.

  5. Stations install into the /opt/nosh contract at /opt/nosh/share/assets/stations, which the host probes first. Operator music gets there with the stations Ansible role (converge/stations.yml), which packages on the control node and pushes the PCM.

  6. The scope stays where the brief locked it. Real PCM only: no chiptune conversion, no MIDI to PSG, no generative audio. No OLED now-playing readout, because ADR-0015 gives the auxiliary display to CIPHER.


Option A: Charter it as roster program #14, split the name by audience. (ACCEPTED)

Section titled “Option A: Charter it as roster program #14, split the name by audience. (ACCEPTED)”

Keeps ADR-0042’s rule intact by doing what the rule asks, and settles the naming with one line an author can apply without thinking: display name WavAmpster, identifier knamp.

Rejected because ADR-0042 makes unchartered programs a defect, and the roster is the router’s authoritative list. An unlisted routable program is exactly the drift the roster exists to prevent.

Option C: Rename it wholesale to knAmp, retiring “WavAmpster”.

Section titled “Option C: Rename it wholesale to knAmp, retiring “WavAmpster”.”

Rejected because the Napster-homage register is the point of the operator-facing name, and the brevity argument only ever applied to what gets typed. Splitting by audience keeps both.


  • The router’s program set matches the chartered roster again.
  • One naming rule covers every future reference, so the June rename cannot silently revert twice.
  • Stations resolve through the /opt/nosh contract instead of the build-time source checkout.
  • Two names for one thing, which needs the rule in this ADR to stay coherent.
  • The audio engine is C, so the player is the least Lisp-authored of the first-party programs.
  • Operator music is not in version control, so a deck reflash needs stations.yml re-run.
  • The screen predates the ASCII design system and hand-draws its progress bar. Recomposing it on ui/pattern.lsp slots (meter, list, kv) is a separate story.

  • docs/adr/README.md: index entry for this ADR
  • docs/software/cartridges/authoring/knamp-stations.md: renamed from wavampster-stations.md
  • docs/software/cartridges/authoring/README.md: updated link
  • runtime/src/screen_router.c: knamp program id + lib path
  • runtime/programs/knamp/knamp.lsp: renamed, namespace knamp/
  • sdk/knamp/: crate, binary, and lib renamed from wavampster
  • runtime/src/cli.{h,c} + hosts/emulator/src/main.c: --stations and the contract probe
  • hosts/device/tools/sd-provision/converge/: the stations role + stations.yml

WavAmpster is the deck’s music player, and it has worked for a month without ever being written down. That was fine while it lived only in the emulator, and it stopped being fine once the roster of first-party programs became the router’s authoritative list: a program the router can reach but no decision describes is drift waiting to happen. This ADR writes it down, and it settles a name that had been reverting on its own. The program the operator sees is WavAmpster, loud and a little ridiculous, which is the point. Everything an author types is knamp. The one piece of the design future readers should hold onto is why the audio engine is C while the screen is Lisp: the Lisp tick only fires for the screen you are looking at, and music that stops when you look away is not background music.