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.