ScoreScript Language wiki

CLI reference

The command list below is emitted by the native CLI built with this wiki. Start with check, use format to inspect canonical text, and add --write only when you want to save it.

scorescript — the ScoreScript toolchain

EVERYTHING IS IN THIS TOOL. Write ScoreScript, run these commands. Never write
a Python script around ScoreScript, never reach for image tooling, never build
a second transport. There is no step below that needs one. New here? Run
`scorescript docs agent` — one page, and it is enough to write four bars
correctly on the first try.

USAGE
    scorescript docs agent                   # ONE page: read this first
    scorescript docs [<chapter>|--list|--manifest]
    scorescript docs --search <words>        # where that is, with the example
    scorescript migrate <file.scorescript> [-o output.scorescript]
  scorescript import <file.musicxml|file.mxl> [-o <out>]
    scorescript book --template <file> --input <id> <file> [--input <id> <file>...] [-o <new-master>]
    scorescript musicxml <file> [-o <out>] [--movement <id|number>] [--layout <name> | --part <name> --concert]
    scorescript check  <file|dir> [--severity error|warning|info]
                              [--format text|json] [--delta <baseline.jsonl>]
    scorescript proof  <file> [--format text|json] [--part <name>] [--movement <id|number>]
                              [--concert|--transposed] [--systems]
    scorescript inspect <file> [--format text|json]
    scorescript format <file> [--write] [--durations numbers|letters]
                              [--no-align]
                              [--normalize <pass>[,<pass>...]]
    scorescript format --list
    scorescript render <file> [-o <out>] [--movement <id|number>] [--staff-space <n>] [--width <n>] [--transposed] [--layout <name>]
    scorescript pdf    <file> [-o <out>] [--page letter|a4|tabloid|a3] [--part <name>] [--concert|--transposed]
                              [--book] [--movement <id|number>] [--layout <name>] [--save-layout <name>]
                              [--pages <index.txt>] [--expect-pages <index.txt>]
    scorescript png    <file> [-o <out>] [--page <n>|--all] [--width <px>] [--part <name>]
                              [--movement <id|number>] [--layout <name>] [--concert|--transposed]
    scorescript parts  <file>
    scorescript layouts <file>
    scorescript geometry <file> [--flowing] [--systems]
    scorescript to-grid  <file> [-o <out>] [--by measures|systems|rehearsals]
    scorescript to-parts <file> [-o <out>]
    scorescript part get <file> "<name>" [-o <out>]
    scorescript part put <file> "<name>" <edited> [--write]
    scorescript expand <file> --part "<name>" --bars <a>[-<b>] [--write]
    scorescript explode <file> [--part "<name>"] [--measures <a>[-<b>]] [--players] [--write]
    scorescript reduce  <file> [--part "<name>"] [--measures <a>[-<b>]] [--write]
    scorescript composition strip <file> [--bars m1-8] [--parts fl,tbn] [--movement <id|number>] [--json]
    scorescript composition readings <file> [--bars m1-8] [--parts fl,tbn] [--readings contour,texture]
                              [--movement <id|number>] [--json]
    scorescript composition projections <file> [--bars m1-8] [--parts fl,tbn] [--projections phrase,form]
                              [--movement <id|number>] [--json]
    scorescript composition evaluate <file> --request <json|@file> [--json]
    scorescript composition evaluate <file> --template [--bars m1-8]
    scorescript composition enumerate <file> --request <json|@file> [--bars m1-8] [--json]
    scorescript composition enumerate <file> --template [--bars m1-8]
    scorescript composition matrix [--json]
    scorescript composition operators [--json]
    scorescript composition events <file> --package <package.json>
    scorescript composition migrate <package.json> --to <1|2|3>
    scorescript composition journal <score> [--json]
    scorescript composition pin <score> (--decision <sha256> | --package <package.json>) --label <text> --reason <text>
    scorescript composition supersede <score> --old <sha256> --new <sha256> [--packages] --reason <text>
    scorescript composition retract <score> --decision <sha256> --reason <text>
    scorescript composition export <score> [--out <export.jsonl>] [--include-private]
    scorescript composition verify <export.jsonl> [--json]
    scorescript composition rebase <score> [--json] | --seal @preview.json --reason <text>
    scorescript composition search <dir> [--subject <id>] [--reading <name>] [--bars m9-16]
                              [--include-private] [--limit <n>] [--after <journal>#<seq>] [--json]
    scorescript composition judgments <score> [--bars m1-8] [--parts fl,tbn] [--movement <id|number>] [--json]
    scorescript composition restore <score> --decision <sequence|sha256> [--base] [--out <file>]
    scorescript midi   <file> [-o <out>] [--movement <id|number>]
    scorescript play   <file> [--movement <id|number>]
    scorescript jam    <file> [--loop m9-16] [--part <name>] [--mute <name>] [--program [<name>=]<n>]
                              [--movement <id|number>] [--soundfont <path>] [--audio-driver <name>]
                              [--render <path>] [--for <seconds>] [--dry-run] [--tick <ms>]
                              [--view code|score|none] [--score] [--gfx kitty|braille|blocks|none]
    scorescript view   <file> [--port <n>] [--no-open]
    scorescript scales
    scorescript install-desktop [--uninstall]
    scorescript lsp

COMMANDS
    scales   print the built-in music objects — `@scale-major`, every mode,
             `@scale-chromatic` — each with its title, the signature it prints
             at a tonic, and its one octave in C as the compiler spells it.
    docs     read a wiki chapter offline as Markdown; --list prints chapter names; --manifest identifies the bundled docs.
             Uses the same teaching documents as the website and MCP resources.
    import   read MusicXML and print the canonical ScoreScript it becomes
             (stdout when no -o). Everything the language cannot hold is a
             diagnostic on stderr, named and counted. Compressed .mxl follows
             META-INF/container.xml and is opened with bounded decompression.
    musicxml write uncompressed MusicXML 4.0 (stdout when no -o) — the door
             out, so a score is never hostage to this toolchain. Each part is
             written at the pitch its player READS, with a <transpose> saying
             how to reach concert; --concert writes the sounding score with no
             transposition instead. A two-staff piano is ONE part with two
             staves, as the format means it. Anything that cannot make the
             crossing is named on stderr as `not exported: …`, never dropped.
    check    print diagnostics as file:line:col: severity[code]: message — teaches
             (exit 1 when any of them is an error). --severity prints that tier
             and everything more serious, and --severity error skips the
             layout-borne alignment check, so it is parse + analyze only.
             --format json prints one object per line — severity, code,
             message, file, line, column, part, bar, range — with no teaching
             prose and a trailing {"summary"} line. --delta <baseline.jsonl>
             prints only what a previous --format json run did not have, keyed
             on (code, part, bar, message) so an edit that shifts lines
             reports nothing.
             A DIRECTORY is a project: every .scorescript under it, in path
             order, each resolved against its own directory, with one summary.
    inspect  the book as a database: the files a score read through `use`,
             `movement from` and `exercise from`, which file owns each
             definition and chapter, every relation (variant-of,
             range-variant-of, derived-from, appears-in, reading-of) and the
             range families `fit` chooses from. --format json is one row per fact.
    format   print the canonical spelling; --write rewrites the file in place.
             A source with errors is left untouched and its errors are printed.
             The skin flags re-spell the same music without changing it:
             --durations letters writes w h q e s ss sss for whole notes through sixty-fourths,
             and --no-align stops padding the grid's columns. Every skin
             re-reads as the same score, and every one of them is idempotent.
             --normalize runs named passes from the normalization menu on top
             of the canonical form (hoist-breaks, key=open, chromatic,
             strip-dev-text, jargon-lint …); what each pass did is reported on
             stderr as file:line:col. `format --list` prints the whole menu.
    render   write a self-contained SVG, one long page (stdout when no -o).
    pdf      write a paginated PDF (stdout when no -o). --part prints one
             player's part, laid out for that part alone AND transposed to the
             pitch that player reads; it still carries the tempo, the rehearsal
             marks and the repeats, wherever they were written. Nothing is
             embedded: notation is vector outlines and words use the standard
             PDF faces.
             --pages <file> writes the printing's page index beside it: the
             settings it was printed under (paper, margins, the effective
             staff size, spacing, gaps, fonts), one row per page — a sheet of
             music with its staff size and its system count — then, for a
             volume, every contents line with the page this printing gave it.
             --expect-pages <file> fails, naming each row, when the index
             differs from an approved one — the page verifier, read off the
             same pagination the PDF was written from. A last sheet carrying
             one system is reported as a pagination decision to make.
    parts    print the parts' printed names, one per line — what --part accepts.
    layouts  print this score's layout configurations, one per line, from the
             sidecar beside it (<stem>.engraving.json). A score with no sidecar
             prints the built-in configuration and how to write one. `*` marks
             the one a viewer opens on.
    geometry print where every event landed on the printed pages, one per
             line: id, page (1-based), then x y w h in that page's own
             coordinates — one unit per staff space, the origin at the top-left
             of the sheet. The pages are the ones `pdf` prints and the ids are
             the ones `play` sounds, so this is the map a click, a selection
             and a playhead are built from. --flowing measures the OTHER
             layout instead — the one tall picture `render` draws — because
             the two put a note in different places. --systems prints the
             system bands rather than the events: system, page, x y w h, and
             how many events the band holds, which is the vertical extent a
             playhead spans and the region a click resolves into.
    to-grid  print the same program as editable measure blocks: one row per
             part. --by measures uses compact structural ranges, --by systems
             follows authored \n / \p cuts, and --by rehearsals follows rehearsal
             sections. Each is one formatting of the same score.
    to-parts print the same program part-first: one `Part { … }` group each,
             with compact `mN-M { … }` ranges that can span mapped changes.
             Both directions are checked by
             analysing before and after — the music may not move.
    part get print ONE part as a score of its own, carrying the tempo, the key
             changes, the rehearsal marks and the repeats that were written on
             other players' lines. Edit that file, then:
    part put re-weave the edited part into the score and print the result
             (--write rewrites the score). It moves NOTES: a different bar
             count, meter, key or tempo is refused by name, never reconciled.
    expand   print the ScoreScript one player would carry if they wrote a
             shared line's bars out themselves — the head's music with their
             interval and register applied, as the block that overrides it
             (--write splices it in). A head is taken WHOLE, because a part
             that writes one of its bars stops reading all of them, so the
             bars it covers are usually more than were asked for; the
             whole-document form is `format --normalize expand`.
    explode  open a divided part's chords into one note per voice: `[Bb G]`
             becomes `v1 { Bb } v2 { G }`, top down, one voice per player.
             Single notes and rests reach every voice, the dynamics and the
             directions stay once on voice 1, and the ties, slurs and
             articulations follow their notes. Default: every part, every bar,
             as many voices as the widest chord asks for; --players opens to
             the roster's player count instead, so a `1,2` part divides even
             where it wrote one note. A bar that already divides, a cue, and a
             `%` bar are left exactly as they are.
    reduce   the way back: voices that agree note for note become one chord,
             top down, with unisons written once and coinciding rests written
             once. A bar whose voices diverge keeps them and says which beat
             they part company at, so nothing is ever quietly re-rhythmed.
             Both verbs are idempotent, both print canonical source, and the
             score's MIDI is identical before and after — that is the contract.
    composition strip  the composition strip of a bar range: one line per
             bar — each lane's rhythm, contour and register, the coincident
             attacks, the harmony reading — the map every surface draws.
             --bars as written in the score (m9-16, m0 for a pickup), --parts
             by roster word, printed name or index, --json for the wire.
    composition readings  the ear's named observations over that selection:
             rhythmic independence, contour, register, voice motion, the
             harmonic reading, range fit, texture, set equivalence, twelve-
             class coverage and expression. One block per reading, under the
             reading's own name; nothing here ranks, sums or prefers.
    composition projections  what is written around the notes of that
             selection: expression (the dynamic, hairpin, slur, articulations
             and words in force at each attack), phrase (each lane's line cut
             where a slur ends, a breath or rest or cadence falls, with the
             roles' hypotheses as hints that decide nothing) and form
             (rehearsal marks, repeats, endings, barlines, sections, the
             exercise containers). Every row names its evidence.
    composition evaluate  what a candidate does: the invariant checks, the
             readings before and after, and the goal's fit per item, with
             `unmet` a LIST — while it is not empty the original stands. It
             never applies: applying is the document owner's.
    composition enumerate  the kernel proposes: at most budget.candidates
             alternatives to the bars, each made by a named move over the
             kernel's projections, each a patch Apply takes unchanged, each
             judged by the same evaluate. Candidate 0 is always the original;
             the list is ordered by the goal's own terms and says so. A
             candidate that breaks a range or loses a mark is refused with
             the reason. It never applies.
    composition matrix  the compatibility matrix: every composition door x
             surface (native, wasm, cli, mcp-stdio, mcp-hosted) x wire
             version x read/write x the bounds it holds, and the capability
             table with this host's on/off state. Generated from the kernel.
    composition operators  the registered native operators a composer's typed
             program may call, each with its reading, arguments and output.
    composition events  where a package's event subjects are in this document.
    composition migrate  re-seal a knowledge package under another schema
             version, explicitly, reporting both digests.
    composition journal  the journal beside a score, opened and verified:
             its segments, decisions, governance records and every finding
             — a cut-off journal recovers to its last verified state and
             says so here (exit 1 when something was lost).
    composition pin | supersede | retract  governance over the journal's
             history as records beside the sealed segments: keep a package
             or decision at an exact digest (a pinned package with its
             bytes), name the newer one that replaces an older, or lay a
             tombstone that says what and why. No segment is rewritten.
    composition export  the journal as one verifiable JSON Lines stream;
             a private decision stays behind as a stub unless
             --include-private says otherwise. `verify` reads one back.
    composition rebase  what every decision's inverse means on the score as
             it is now (the preview, a sealed document), and --seal writes
             the lineage record naming the old base, the new base and the
             preview the composer saw. Never silent.
    composition search  which decisions, in every journal under a directory,
             touched a subject, a reading or these bars — with their
             evidence rows, bounded and paged, private ones withheld.
    composition judgments  the journal's decisions over a score's bars in the
             projections' row shape, so a judge reads them beside
             expression, phrase and form.
    composition restore  the source ONE decision recorded, back out of the
             journal: the candidate it wrote, or with --base the source it
             was made on. The bytes go to stdout or --out; who made it, when
             its segment was sealed, why, and whether it still stands go to
             stderr beside them. It reads only — the journal is never
             written, and nothing is re-decided.
    midi     write a Standard MIDI File (stdout when no -o).
    play     say what the performance contains, and how to hear it. There is
             no audio engine in this toolchain, by design — `jam` sequences an
             external one rather than becoming one.
    jam      the live session: loop a bar range and keep playing while you
             write. On every save the file is recompiled; a clean save is
             swapped in AT THE NEXT BARLINE without the clock stopping, and a
             broken one prints its diagnostics and keeps the last good take
             sounding. A typo never causes silence. --loop takes a bar range
             (m9-16); --part solos and --mute excludes, both repeatable, so
             'play me just the strings' is one flag. Sound is fluidsynth's,
             driven over a pipe on our clock; --dry-run prints the loop and
             starts nothing. While it plays the terminal shows YOUR SOURCE,
             and the notes light up in it as they sound — the loop's lines,
             with the currently sounding events in reverse video. It is pure
             ANSI, so every terminal gets it. --view score instead engraves
             the loop's bars and sweeps a playhead over real notation (kitty
             graphics where the terminal has them, braille cells everywhere
             else; --gfx forces a tier), and --view none draws neither.
    view     open the file as a living page: real sheets on a dark desk, a
             Play button, and a redraw within half a second of ANY editor
             saving the file. A local server on 127.0.0.1, GET only; stop it
             with Ctrl-C or by visiting /quit.
    install-desktop
             register the file type with the desktop, so a double-click opens
             the viewer: writes ~/.local/share/mime/packages (the MIME type
             text/x-scorescript for *.scorescript, *.ss and *.score) and
             ~/.local/share/applications (the launcher), and nothing else.
             --uninstall removes exactly those two files.
    lsp      speak the Language Server Protocol over stdio.

EXIT STATUS
    0  the work was done and the source had no errors
    1  the work failed, or the source it was done FROM has errors
    2  the command line itself was wrong

    render, pdf, png and musicxml degrade honestly — a source with errors
    still yields the music it does describe — but they exit 1 and close
    stderr with one line: `DRAFT — <file> has N errors, the first at
    <file>:<line>:<col>`. The pages are there to look at; the status says
    they came from a file that does not read, so `scorescript pdf x -o x.pdf
    && send x.pdf` can never send a draft. Warnings and info alone exit 0.

OPTIONS
    -w, --write          format / part put: rewrite the file instead of printing
        --durations <k>  format: numbers (default, canonical) or letters
        --no-align       format: leave the grid's cells unpadded
    -o, --output <path>  render/pdf/midi/to-grid/to-parts/part get: write here
                         instead of stdout
        --movement <id>  render/pdf/midi/play: select one authored movement
        --by <landmark>  to-grid: measures, systems, or rehearsals
        --staff-space <n>  render: pixels per staff space (default 8)
        --width <n>        render: the width systems wrap inside, in pixels
        --page <size>      pdf: letter (default), a4, tabloid or a3, 0.75in margins
        --part <name>      pdf: one part, by printed name ("Flute 1") or by
                           instrument key when it names only one part
        --transposed       render/pdf: the transposed-score view — every part
                           at the pitch its player reads. The text is concert
                           pitch, so a score is concert unless you ask.
        --concert          pdf: keep concert pitch, even for --part
        --layout <name>    render/pdf: draw this score the way the named
                           configuration says — paper, margins, staff size,
                           spacing, the engraving flags, concert or written,
                           and its part if it has one. It IS the page decision,
                           so it is refused alongside the flags it would
                           overrule. `scorescript layouts <file>` lists them.
        --save-layout <name>
                           pdf: store this command line as a configuration in
                           the sidecar, creating it if there is none — the
                           other knobs start at the engine's defaults, and the
                           file is yours to edit. The PDF is still printed.
    -p, --port <n>       view: listen here (default 4321; a port in use moves
                         to the next free one)
        --no-open        view: print the URL instead of opening a browser
        --uninstall      install-desktop: remove the two files it wrote
    -h, --help           print this
    -V, --version        print the tool and spec versions
        --identity       [--json] the build's identity: crate version, the
                         commit a release was cut from (or `unknown`, never a
                         guess), spec, and every composition wire with the
                         versions this build reads
        --capabilities   [--json] the composition capabilities this host
                         declares, on or off; SCORESCRIPT_CAPABILITIES_OFF=a,b
                         switches any off without a rebuild, and a door that
                         is off refuses with `capability.off`
        --next           composition strip|projections|evaluate|enumerate:
                         the typed next queries ride on the --json wire

Read checking and fixing mistakes for the normal workflow.