jevstrudel.git / README.md

jevstrudel

Strudel — the JavaScript port of TidalCycles — with two additions: an MCP bridge so Claude can play and edit code in a browser session, and the jev panel on the REPL's left, which holds everything this fork adds (the song browser, who is listening, your account, how to connect your AI, and everything the site stores, for anyone to read) so it is never mistaken for Strudel's own, and Jev at work in a pane under the editor. The songs live here too: pick one and it opens there with its spec, its code loads, and it plays from the top. The public site also hosts an MCP for everyone's own AI (/ai/, worker/README.md, The hosted MCP): signed in, a visitor connects Claude Code or Claude, which plays into their own tab's sandbox and publishes songs Jev screens.

What this repo is made of

It is a fork, kept as three layers so each can be updated on its own:

BranchWhat it is
strudel-upstreamStrudel's main, from codeberg.org/uzu/strudel (remote strudel)
strudel-llmThe MCP fork as published, calvinw/strudel-llm-mirror (remote strudel-llm)
strudel-llm-rebasedThe fork's 9 commits rebased onto strudel-upstream
jevstrudelstrudel-llm-rebased plus this project: the songs, samples, vocal tools, the flake, and the song browser

Both remotes have push disabled; this repo only ever reads from them.

Running it

buck2 run //:dev, inside the devshell (nix develop, or direnv), is the working tree with hot reload on http://localhost:4322/: edit the site, a song or a sample and the page updates. Beside it runs the jevstrudel Worker (worker/) with the Jev relay and an MCP hub: .mcp.json runs nix run .#mcp, a small stdio proxy, so Claude can play code into an open tab. Either side can restart without the other. The proxy's use_environment tool switches it to the public site's hosted MCP, signed in as you with a passkey, and back (tools/mcp/).

buck2 run //:preview is the last listen before a deploy: the deploy's own static build with the production Worker (the relay, no MCP) on http://localhost:4324/.

buck2 run //:check-songs plays every song fast in a silent headless tab on the dev server and reports what Jev did, and anything that failed. nix flake check evaluates every song in Node against a stand-in Jev.

nix build .#static is the site alone, for any static host: the REPL and song browser with the sample pack bundled, and no MCP. nix run .#deploy publishes it with the Jev relay as a public Cloudflare Worker at https://jevstrudel.deizel.workers.dev; the Cloudflare token comes from 1Password on each run.

The devshell also has speak TEXT OUT.wav and vocode IN.wav OUT.wav --chord "a2 a3 c4 e4" (a Windows speech voice, and a vocoder that makes a chord sing it), and ffmpeg for cutting vocal clips.

Audio comes out of the browser (on Windows), so nothing in WSL needs a sound server.

Layout

Everything upstream (packages/, website/, …) is Strudel's, with the MCP fork's changes on top. This project adds:

  • songs/<theme>/<song>/ — one folder per song: SPEC.md and song.js.
  • samples/<sound>/ — the sample pack: every folder is a sound (samples/jeff/jeff.mp3 plays as s("jeff")). Songs load it with samples('jev-samples/strudel.json'), which the site builds.
  • tools/vocals/ — the vocal tools' sources; tools/mcp/ — the MCP proxy; tools/measure/ — each song's mix, measured; tools/events/ — the Worker's telemetry, read back; tools/jev-history/ — Jev's decision history per song, from the stored performances; tools/worktree-samples/ — a worktree's own samples in the headless tools.
  • website/src/jev/ — the song browser, jev() (TypeSafe's API as Strudel patterns) and link previews.
  • worker/ — the Cloudflare Worker: the Jev relay, and the MCP hub in dev.
  • nix/, flake.nix — how jevstrudel is built and run.
  • BUCK, .buckconfig, toolchains/, tools/dev/, tools/check-songs/ — the //:dev, //:preview and //:check-songs targets.