Repository navigation
feat(publish): check a song for release, and write a release kit for a distributor - #48
Merged
Merged
Conversation
devlato
enabled auto-merge (squash)
October 20, 2026 05:00
devlato
added a commit
that referenced
this pull request
Oct 20, 2026
…API (#49) This brings `claudius publish` ([#48](#48)) to the studio, to assistants over MCP, and to the HTTP API. ## In the studio **publish** in the toolbar opens a Publish dialog: - the cover, dropped onto the studio (the native studio also takes a path), with a preview and what it is ("3000 × 3000 JPEG"); - the details stores ask for, each sent when its field is left; - how the song was made, as three choices that only the person can answer; - what stores would say of the latest render: problems in red, warnings in yellow, notes in grey; - **Write the release kit**, enabled once nothing stops the release. The browser studio reads a dropped cover asynchronously and sends it the same way. The demo keeps the details, and says that it checks nothing and writes no files. ## In the session - The release in the making belongs to the song: its genre, seed and folder. Generating, remaking or opening another song starts afresh; edits, mutations and evolution keep the details. - Opening a song folder reads its `release.json` and its artwork. - Saving the song, or writing the kit, puts `release.json` and `artwork.jpg` (or `.png`) in the song's folder. That happens only once something was given for the release, so ordinary saves write nothing new. - Renders check the release only once something was given for it, so songs nobody publishes don't pay for the checks. Opening the dialog counts as asking. ## Over MCP and HTTP - **MCP:** a `publish` tool. It takes what the person said: the artist, the songwriters, the artwork file, `made`, and the other details. With `write`, it also writes the kit. What it leaves out stays as it was. Its description, and the claudius-songs skill, tell the assistant never to choose `made` for the person. - **HTTP commands:** `set_release` (the details, and optionally an artwork path, read under the session's file policy) and `write_kit`. - **HTTP routes:** - `POST /api/release/artwork` takes the cover's bytes. It requires an image or octet-stream content type, so a cross-site form can't post one without a preflight, which CORS refuses; the limit is 40 MB. - `GET /api/release/artwork` returns the cover as given. - `GET /api/release/preview.png` returns it at most 512 pixels on a side. - **State:** `State.release` holds the details, the artwork, the checks, the render they're of, and where the last kit went. ## How I checked it - `cargo xtask ci` passes: formatting, clippy on all three builds, the headless check, 217 tests, the doctests and the docs examples. `cargo clippy -p claudius-ui --target wasm32-unknown-unknown -D warnings`, `cargo deny check`, `typos`, `cargo xtask site` and `lychee --offline` (0 broken links) pass too. - A new session test runs the whole flow: 1. renders don't check a release nobody asked for, and saving doesn't keep one; 2. the details are checked, and the only problem left is the artwork; 3. writing the kit is refused until there's artwork; 4. a cover sent as `text/plain` is refused, and one sent as `image/png` is taken; 5. the release is then ready, and the preview is 512 pixels; 6. the kit goes into `release/`, and `release.json` and `artwork.png` into the song's folder; 7. another song starts afresh, and reopening the folder brings back the artist and the artwork. - The MCP test calls `publish` and gets the artwork and "how the song was made" problems. The shared-session test refuses an artwork path from outside the session's folders. - Scripted studio runs (a new `publish` plan step) with screenshots: - with a cover uploaded over HTTP, the dialog shows its preview and size, the details, the chosen "made" answer and the checks; - with nothing given, opening the dialog brings the checks: no artwork, no artist, no answer about how it was made.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Spotify, Apple Music and the other stores take music only from distributors, and the distributors musicians use (DistroKid, CD Baby, TuneCore, Amuse) have no API. What all of them do have is the same upload form.
claudius publish SONGchecks a rendered song the way stores and distributors check a release, then writes a release kit with everything that form takes. The studio and MCP get this in the next PR; uploads to SoundCloud and YouTube come after that.What it checks
Problems block the kit, and the command fails; warnings and notes are listed.
The kit
release.txt: the form's answers, what to tell a distributor about AI, the credits, the artwork rules claudius can't check, and the checks;release.json: the same, for programs.What the person gives is kept in the song's
release.json. A song without one takes the artist's details from the newest release among its sibling song folders, so there's no global settings file.The sharpness check
It measures the width of strong edges. A sharp image's sharpest 5% of edges are 1 to 3 pixels wide; in an image enlarged k times, none is narrower than about k pixels. I tuned it on macOS wallpapers and an aerial photo, against copies
sipsenlarged from a half, a third and a quarter of their size:An earlier version compared energy across frequency bands. It couldn't separate originals from enlarged copies, because JPEG's 8-pixel blocks put energy back into exactly the frequencies an enlargement empties.
How I checked it
cargo xtask cipasses: formatting, clippy on all three builds, the headless check, 216 tests, the doctests and the docs examples.cargo deny checkandtypospass,cargo xtask sitebuilds, andlychee --offlinefinds 0 broken links.--check --jsonneeds nothing given again.release.txt;publishis added to the telemetry Worker's list of commands; I'll redeploy the Worker after merge.