ScoreScript Language wiki

Checking, formatting, and fixing mistakes

Read a chapter in the terminal

scorescript docs --list
scorescript docs first-score
scorescript docs connectors

The docs command prints one chapter as Markdown, without needing a network connection. It is included in builds containing this wiki; an older installed CLI may need updating. MCP readers can list the same chapters under scorescript://docs/, starting with scorescript://docs/index.

The loop, for an agent that cannot look at the page

Write it, check it, prove it, then look only if a picture is still wanted:

scorescript check piece.scorescript
scorescript proof piece.scorescript
scorescript png   piece.scorescript --all

Everything is in this CLI. Never script around it with Python or other tools: proof and check already answer in text, and a wrapper that parses their output is a second engine that will disagree with this one.

check ends every text run with one line saying what the engine understood — the parts, the bars, the events, the notes, the rests, the lyric syllables, the tuplets, the named passages, the repeats it resolved, and source lines that produced no music: N with each line's file:line when N is not zero. That line is the fast double-check: a source addressing eight bars whose summary says bars 2 has lost six of them, and no diagnostics would never have said so. A run that FAILED prints it too — when the file does not compile, how much of the piece survived is the next thing you want to know.

proof is the listing behind it — what was ENGRAVED, from the same resolved model the PDF path prints:

proof · piece.scorescript · "Lost name" · pitch concert · parts 1 · bars 2 · …
part 1 "Voice" · voice · bars m1-m2 (2) · clef bass · key C major · meter none
p1 m1 v1 · (>)8C3 8D3 8E3 8F3 (>)8G3 8F3 8E3 8D3 · lyrics v1: nee _ _ _ neh _ _ _
p1 m2 v1 · 1C3 · lyrics v1: nee
no music · piece.scorescript:17 · m3-m4 addressed, none engraved

Four bars were addressed there and two came out, because m3-4 = nothing borrows a passage no block names. The diagnostic says why (error[span.not-found]); the no music row says which line lost its bars.

One line per bar per voice, in the language's own notation, so comparing it with the source is a diff and not a translation. --format json is the same rows one object per line; --part, --movement, --concert/--transposed select exactly what pdf would print. Everything else reads the model only, so a proof costs about what a check costs.

--systems: the pages, and the words on the ones that have no music

--systems engraves as well, and reports the volume's own page plan — the same plan pdf prints:

engraved · systems 2 · pages 2
page 1 · text =study-sheet
t1 b1 heading · Study One
t1 b2 excerpt · =study m1-m8
t1 b3 paragraph · Play this twice: the second time softer, and breathe only at the double bar.
page 2 · music =study · sheet 1 of 1

One page line per printed page, in printing order, so the page this listing calls 2 is scorescript png --page 2 and the PDF's page 2. A page holds front matter, a movement's music sheet, or an authored text page.

A text page is then read out one line per block: t1 is the volume's first text page, b3 is its third block (b3.1.2 inside a column), then the word the source wrote in front of that block and what the block holds — the words for prose, the bar range for an excerpt. The word is echoed, never interpreted: this listing says what is on the page, not what kind of thing it is. --format json carries the same as page and text rows.

png writes the sheets pdf prints, one PNG per page (sheet-1.png, sheet-2.png), for a reader that can look at a picture — including a volume's text pages, at the same page numbers.

Check the actual file

scorescript check piece.scorescript
scorescript proof piece.scorescript
scorescript format piece.scorescript
scorescript format piece.scorescript --write
scorescript render piece.scorescript -o piece.svg
scorescript pdf piece.scorescript -o piece.pdf
scorescript midi piece.scorescript -o piece.mid

Without --write, formatting reports canonical source without replacing the file. Keep a saved revision before a broad edit. After formatting, check again and inspect the rendered music. MIDI output is useful for checking sounding duration and instrumentation but cannot certify printed spelling or layout.

For a whole book, a compact check includes an inventory of every movement:

scorescript check book.scorescript --format json
scorescript check book.scorescript --format json > before.jsonl
scorescript check book.scorescript --delta before.jsonl

The summary totals all movements and lists their titles, bar counts, and part counts, plus the number of authored text pages. Part totals count each movement's roster; they are not a count of unique instruments. Diagnostic rows name the movement containing the source location, so m1 in one study cannot be confused with m1 in another. --delta shows added and removed findings after an edit, even when the two studies use the same part and bar numbers. Use a fresh baseline if an older CLI produced it without movement IDs. When reused source belongs to several bars, the diagnostic retains its message and exact source location but leaves an ambiguous bar field empty.

What the exit status means

check exits 1 when the file has any error-severity diagnostic, and so do render, pdf, png and musicxml. Those four still produce what the source does describe — a broken file is worth looking at — but the pages, the picture and the exported file are a DRAFT, and the last line on stderr says so:

piece.scorescript:5:20: error[pitch.invalid]: “Q9” is not a pitch. — …
scorescript pdf: wrote piece.pdf (1 page, 296784 bytes)
scorescript: DRAFT — piece.scorescript has 2 errors, the first at piece.scorescript:5:20. What was produced holds only the music this source does describe.

A script or an agent that reads only $? is therefore never told that a broken source printed cleanly, and scorescript pdf piece.scorescript -o piece.pdf && send piece.pdf cannot send a draft. Warnings and information alone exit 0: they describe the music, they do not say it was not understood. Exit 2 means the command line itself was wrong.

Read diagnostic severity

An error means the requested source was not fully understood or is inconsistent. A warning can describe unfinished or ambiguous notation. Information may explain a derived rest or other normal completion. Read the code, location, and message together; do not just look for a green preview, since the engine can draw the portions it did understand.

Common mistakes

SymptomCheck
A note is in the wrong octaveThe previous pitch, apostrophe/comma, and first-note octave anchor
A rhythm exceeds the barSticky duration, dotted values, tuplet ratio, and current meter
Eight bars of rest instead of an eighth restr8 versus 8r
Several short slurs instead of one long slurMark only the opening and closing endpoint
A chord becomes a labelPreserve its duration and use clear bracketed pitch members
Text lands on the other sideBefore the node is above; after is below for text/dynamics
Extra silent measuresAddressed range gaps and misplaced physical row breaks
A dynamic prints but does not sound as expectedPlayback interpretation and the selected sound source

What formatting does

It normalizes accepted duration spellings, groups measures compactly, anchors the first sounding pitch of each authored section and voice, and condenses equivalent timeline points into maps where useful. It preserves the selected sanctioned arrangement and the order of chord members. Formatting is not a substitute for choosing the right musical notes.

Plain formatting is not automatic musical consolidation. The normalization menu separately controls orientation, maps, duration spelling, whitespace density, shared readers, and named reuse.

Import and export

The native reader can import MusicXML and the exporter can produce MusicXML for interchange. Check diagnostics and the full piece after a conversion; another notation program can carry constructs that this engine cannot yet represent. A successfully opened first page does not prove every part or movement survived.

scorescript import source.musicxml -o piece.scorescript
scorescript check piece.scorescript
scorescript musicxml piece.scorescript -o roundtrip.musicxml

Installation, editor connections, and host APIs are covered in integration. Website display is covered in embedding.

Unsupported or limited notation

Do not assume that arbitrary drum-kit pitch names, multi-staff rh:/lh: instruments, cue-note styling, arpeggio roll marks, or alternating two-note tremolo have a supported compact spelling. Figured bass and custom lines have the limits described in their chapters. Named bracket lines and navigation can have rendering or playback limitations. Treat a diagnostic or render report as part of the result, and verify the delivered pages and audio for the features you use.

For AI-assisted writing, use this same wiki and the actual compile/format tools. Supply complete source and address the exact file, movement, part, and measures being edited. Never substitute a similar instrument or score revision because its filename looks close. Everything needed is in this CLI; never script around it with Python or other tools. Read the bar count on the understood line before anything else, and read proof before calling a page finished — a clean check is not evidence that the music arrived.

To hold a part to a boundary rather than be advised about one, declare its range (range written C4-C7); see declared ranges. A note outside a declared range is an error, which is what makes the declaration useful as a guard when an agent writes the part.