OOLOI.ORG
Menu

OOLOI

An Organism Evolved.

OVERVIEW

DOCUMENTATION

NEWSLETTER

Taking Stock at Two Years

9/7/2026

2 Comments

 
Creating a wind quintet with score and parts in Ooloi.
​Then adding doublings. No dialogs.

Two years ago today, on 9 July 2024, the first commit to Ooloi went in. Time to take stock.

There's no music on screen. Two years in, and still not one printed note. No noteheads. No beams. No slurs. No page of music. All true, all planned, and all completely beside the point.

Why? A notehead drawn in the first year would've been a comfort object, not evidence. So the visible surface stayed sparse on purpose while the real work went on underneath it. The absence of staves was never the interesting fact about this project. It was the cost of getting the interesting facts right, and this anniversary is the point at which they start becoming visible.

This isn't an eccentric way to build notation software. It's how the serious ones are built, and the record is consistent. Sibelius took its two founders about seven years before the first release in 1993. MuseScore was carved out of a sequencer in 2002 and did not reach a stable 1.0 until 2011. Dorico, built by most of the old Sibelius team after they were let go, took close to four years and shipped its first version deliberately slow and incomplete, engine and engraving model first; the field judged the decision sound. Three programs, three decades, open source and commercial alike, and in every case the foundational years came before anything a user would recognise as finished.

The counter-example proves the same point from the other side. Finale shipped fast in 1988, did more than anything before it, and became the industry standard for a generation. It was also, by wide agreement, punishing to use, and when its owners finally discontinued it in 2024 they said plainly that decades of accumulated code had made each new version harder to deliver and worth less. Feature piled on feature until the architecture could no longer move. That's the ceiling a notation program hits when the surface is built before the foundations are right.

Two years isn't a long time to spend getting the foundations of a fifty-year program right, and I've never regarded it as a delay.

Now, the bet on which Ooloi is built is functional programming. Music notation is a genuinely hard computer science problem wearing a friendly costume, and Clojure's properties looked to me like the right machinery for the parts of it that commercial programs have learned to manage rather than solve. Ooloi is my first Clojure project, though not my first Lisp by a long way, so the syntax was familiar ground; an old hand picks up a new dialect quickly.

The deeper reorientation was immutability. Fully embracing immutable data structures, rather than merely tolerating them, changed how I thought about the whole domain, and almost everything architecturally distinctive about Ooloi fell out of that one shift. Undo, collaboration across machines, full use of multi-core parallelism, pervasive structural sharing: none of these is a feature bolted onto mutable objects. Each is a consequence of representing musical facts as immutable values. Learning to think that way was the real work of the first stretch.

The harder part was psychological. A screenshot of notation would've been reassuring, and I could've produced something theatrical early on if theatre had been the goal. I grew up around theatre. I know a backdrop when I see one. I also know there's never a wall behind it.

So the project spent a long time with most of its real work below the surface. The documentation was public, the ADRs were public, the blog was public, but the evidence still required reading. And the focus on the yet invisible might have given the impression that progress had been slow. So I drew up a list of what's been completed over the past two years.

I expected it to be useful. I did not expect it to be quite so long.

That surprised me, which is perhaps the point of doing the accounting at all. Daily work doesn't feel like accumulation. It feels like the next ticket, the next invariant, the next small refusal to leave a problem in a shape that'll charge interest later. Only when the pieces sit next to each other does the scale become visible:
​​
  • Core musical model: Pieces, musicians, instruments, staves, measures, voices, rhythmic items, attachments, traits, hierarchy, and the basic vocabulary for representing musical facts.
  • VPD addressing: Vector path descriptors, giving operations precise structural addresses inside a piece.
  • STM coordination: Transactional backend state, with Clojure STM used as the coordination model for musical mutation.
  • Timewalking: Temporal traversal of nested score structure, including the transducer-based breakthrough that made the score streamable in musical order.
  • Pitch representation: Exact spelling, rational arithmetic, transposition machinery, and round-trip integrity.
  • Time signatures: Ordinary, additive, mixed-unit, fractional, irrational, historical, and descriptor-preserving signatures.
  • Key signatures: Standard modes, keyless notation, custom signatures, per-octave variants, and microtonal systems.
  • Remembered alterations: Deterministic accidental handling built on pitch, time, key context, and traversal.
  • Measure distribution: Formal specification of measure distribution as a Knuth-Plass-style optimisation problem.
  • Persistence and compression: Serialisation, structural sharing, hash-consing, and the 50,000-note compression test.
  • gRPC API: Generated method exposure, Protocol Buffers conversion, streaming, bounded queues, events, and the unified value transport.
  • Server statistics: HTTP metrics, health endpoints, and the monitoring machinery used to validate server behaviour. Grafana and Prometheus support.
  • TLS and transport hardening: Secure transport foundations, connection handling, shutdown correctness, friendlier errors, and combined-app collaboration TLS.
  • Reference-passing transport: Near-zero-overhead in-process calls by removing the Clojure-to-protobuf conversion path inside the desktop app.
  • Integrant system architecture: Component lifecycle, dependency wiring, startup, shutdown, and the shared/backend/frontend division.
  • Frontend event architecture: Event bus, backend event router, category batching, wildcard subscription, invalidation routing, and JavaFX-thread discipline.
  • Backend-authoritative rendering design: Terminal frontend execution, paintlist boundary, cache hierarchy, and backend ownership of musical layout decisions.
  • Localisation: PO-file workflow, strict translation-key discipline, canonical UK English, runtime locale switching, build-time checks, and 22 bundled locales: Czech, Danish, German, Greek, UK English, US English, Spanish, Finnish, French, Hungarian, Icelandic, Italian, Japanese, Korean, Norwegian Bokmål, Dutch, Polish, Brazilian Portuguese, European Portuguese, Swedish, Ukrainian, and Simplified Chinese.
  • Frontend settings: Persistent application settings, registry-driven defaults, validation, generated Settings window, and reactive updates.
  • Window lifecycle: Declarative window opening, persistent geometry, fade behaviour, modal gating, and centralised stage management.
  • UI styling: Semantic styles, no hardcoded colour seepage, custom cljfx components, and Java interop confined to boundary files.
  • Notifications and chrome: Splash screen, platform menus, notification overlay, menu-bar host, About window, settings UI, and orderly shutdown.
  • Frontend undo and redo: Local undo history for application settings, integrated into the same menu surface as backend undo.
  • Backend undo and redo: Resource-level undo manager, coordinated history, localised descriptions, frontend routing, clock-offset adjustment, and cross-client undo.
  • Instrument Library: Real instrument and staff records, editing, validation, persistence, conflict retry, drag-and-drop, deletion tombstones, ordering, multilingual contents, and a complete populated default library.
  • Font management: Bundled SMuFL fonts, associated text fonts, font registry, and glyph-selection architecture.
  • Transaction-driven distributed updates: The whole update model. A change is a transaction against authoritative backend state; committing it names what's now stale, and every subscribed client, on the same machine or across the network, refetches the canonical structure and replaces its view. No deltas, no merge logic, no distributed-specific code paths. Collaboration is not a separate engine; it falls out of this for free.
  • ​Collaboration architecture: Dual-server model, local and network transports sharing backend state, frontend transport switching, host and guest roles, connection UI, and shared resource editing.
  • Two-laptop proof: Guest edit, host observation, host undo of the guest's change, propagation back to the guest; and, at the two-year mark, musicians created and rearranged in a shared piece window on one machine and appearing on another.
  • Post-demo hardening: Collaboration menu enablement, backend-switch undo-cache invalidation, standalone backend wiring, collaboration palette behaviour, anchor-first selection, modal menu gating, TLS routing, friendly errors, and headless test mode.
  • Platform support: macOS Apple Silicon, Windows x86_64, Linux x86_64, native bundles, Windows application build, and an explicit platform policy.
  • Documentation: ADRs, guides, development log, reading path, and Librarian, built as part of the system's survival machinery.
  • Test infrastructure: Shared, backend, and frontend tests, now around 24,400 passing cases.
  • Piece Window: Structural entity identity and cloning, opaque backend filesystem navigation, a component-owned piece-manager store, a custom Open/Save picker that never sees paths, a complete piece file menu (New, Open, Save, Save As, Close) with typed and translated failure messages, transport-blind file commands that work unchanged in a collaboration, deterministic backend close-on-last-release, and a piece window that's now a live view of authoritative backend state, updating across every subscribed client on any structural change.

During daily work, a subsystem closes and vanishes from attention. That's partly the method: finish something completely enough that it stops sharing the desk. The Instrument Library no longer asks to be designed. Localisation no longer asks to be invented, and the interface already speaks twenty-two locales. Undo no longer waits behind every future feature (with a small knife). Transport no longer converts itself through protobuf in-process for no reason. Window lifecycle no longer belongs to individual windows. Each closed subsystem removes one more thing from the cognitive field.

The list makes visible what the surface hid. Ooloi hasn't spent two years waiting to become a notation program. It's spent two years removing the taxes a notation program would otherwise pay forever.

This is also where the unusual working conditions matter. I've been ... unburdened by people. That sounds harsher than I mean it, though perhaps not by much. Not unburdened by readers, musicians, criticism or conversation, which have all mattered, but by the organisational forms that force software to explain itself before it has finished thinking. No investors, no release calendar, no committee, no inherited user base demanding that a workaround stay sacred because muscle memory has mistaken it for design.

A team would have made some things faster and some things impossible, or at least premature. There's a stage in a project like this where the architecture has to be held whole in one mind, not because one mind is superior to several, but because dividing the thing too early changes the thing. Ooloi needed a period before that could happen.

That period has had its own cost. Solitude removes obstruction, but it also removes alibis. Every accepted decision is mine. Every inconsistency in the documents is mine to catch. Every time Claude Code proposes a convenient shortcut, I have to know whether it's harmless, local, or the kind of thing that looks harmless now and grows teeth later. There's no one else to blame, which is excellent architecture and poor comfort.

The AI has made the solitude more productive, though only because the architecture constrains it. Claude works best as an implementor inside settled boundaries. Give it one subsystem, clear invariants, failing tests, and a narrow target, and it moves with astonishing speed. Ask it to hold the whole system in its head at once, and it becomes what all of us become under those conditions: less intelligent than advertised. Every subsystem sealed below the musical floor is one fewer thing it has to juggle when the visible engraving work begins.

That's another reason the long groundwork was worth doing. The cleared desk isn't a metaphor I use lightly. It's how the next phase becomes possible.

The 3 June proof mattered because it compressed much of this into one modest action. Two laptops. One Ooloi hosting, one connected. A flute name changed on the guest, visible on the host. Undo on the host, reverting the guest's edit. The revert appearing on the guest.

As cinema, it will not trouble Bergman. As architecture, it was the exact kind of evidence I had been waiting for.

That little proof did not show engraving, and it did not pretend to. It showed authority, transport, shared state, invalidation, fetch, undo routing, and cross-machine propagation acting together without ceremony. Nearly two years of decisions appeared as a small correction to the name of a flute. Software milestones are sometimes like that: not fireworks, just a door opening without sticking because someone spent a very long time caring about the hinge.

Now the work is moving towards the page.

The custom picker is already visible and operable. It's not a native file chooser with new paint. It asks the backend what exists, receives opaque tokens, and never sees paths. Local storage and remote storage go through the same contract. The boring dialog is already the front edge of the piece model.

Behind it, the piece window is now a live view of authoritative backend state, and this anniversary comes with a second small proof to show it. The video accompanying this post was recorded on two machines. On one, a wind quintet is assembled in a handful of gestures: flute, oboe, clarinet, horn, and bassoon dragged out of the Instrument Library into the Musicians panel of a shared piece window, each becoming a musician with its staves beneath it, and then dragged across into the Layouts panel to define the full score and the five individual parts. On the other machine, the same piece window answers. No delta is sent between them: a structural change names what is now stale, and the other screen refetches the canonical structure and redraws.

It's the 3 June proof one storey higher. In June a flute changed its name and the plumbing held; here the same architecture carries piece structure rather than a library entry, edited collaboratively, with the invalidate–fetch–replace model the Instrument Library established generalising to the piece itself unchanged. And it's still, deliberately, not engraving. What crosses the wire and appears on the second screen is musical structure, not a rendered stave. There's no notehead in the video. The machinery that'll carry the music is running, and running across two machines, before the music arrives.

Next come piece preferences and window persistence, the rest of the Piece Window arc. After that, MusicXML, because real scores must drive real notation work. Then Skija and the rendering pipeline. Then the noteheads: spacing, stems, flags, dots, accidentals, voices, collisions, beams, ties, slurs, hairpins, lyrics, pedalling, ottavas, tuplets, and the geometry of the page.

The evidence will change again at that point. The collaboration you can already see in the video will still be there, but it'll be moving notation rather than structure. A slur will find space. A beam will sit, straddle, or hang. A note in a chord will change geometry around it. One screen will alter shared musical notation and another will answer with the same page. The program will make the argument in engraving, not only in structure.

I'm looking forward to that more than I can sensibly say.

Two years in, the thing that surprises me isn't that there's still no music on screen. I expected that. The noteheads were never beside the point as a goal, only as evidence; a program isn't proved by what it can draw first. The surprise is how much of the project is already behind the moment when music appears. The empty stave, seen from the surface, suggests absence. The inventory tells a different story: a great deal has already been decided, tested, closed, and made boring.

Boring is underrated. Boring is what a foundation becomes when it's doing its job.
​​
So, coming out from the darkness that never really was, the next part will be visibly brighter, and with any luck it will involve fewer ... certificate files.
2 Comments
Magnus Johansson
9/7/2026 10:16:18

Thanks, Peter, for the video and for the overview of the project this far. I agree with Rune Brynsholmen that following this development is one of the most interesting things I have done.

Regarding the Piece Window, what do you think of letting an instrument dragged into the Musicians pane get a musician's name so a clarinet becomes a clarinetist giving e.g. the following in the pane?:
v Clarinetist
> Clarinet in Bb

Reply
Peter Bengtson
10/7/2026 07:34:12

Thanks, Magnus.

The player-versus-instrument distinction is real, and something like it will be there. But the whole naming layer is still in flux: I want numbering to fall out of the structure rather than be typed in by hand, and what a part page actually shows at its head is a separate question again. Whatever the default turns out to be, the program won't fight you: you'll always be able to override it and set the name to whatever you want.

Reply



Leave a Reply.

    Author

    Peter Bengtson –
    Cloud architect, Clojure advocate, concert organist, opera composer. Craft over commodity. Still windsurfing through parentheses.

    Search

    Archives

    July 2026
    June 2026
    May 2026
    April 2026
    March 2026
    February 2026
    January 2026
    December 2025
    November 2025
    October 2025
    September 2025
    August 2025
    July 2025
    June 2025
    April 2025
    March 2025
    September 2024
    August 2024
    July 2024

    Categories

    All
    Accidentals
    Alfred Korzybski
    Architecture
    Backend
    Beaming
    Benchmarks
    Clefs
    Clojure
    CLOS
    Common Lisp
    DDD
    Death Of Igor Engraver
    Documentation
    Donald E Knuth
    Dorico
    Dynamic Programming
    Finale
    Fonts
    FrankenScore
    Franz Kafka
    Frontend
    Functional Programming
    Generative AI
    GRPC
    Igor Engraver
    Ingmar Bergman
    Instruments
    Jacques Derrida
    JVM
    License
    LilyPond
    Lisp
    Localisation
    MIDI
    MPL 2.0
    MuseScore
    MusicXML
    Ooloi
    Ortography
    Pitches
    Platforms
    Playback
    Plugins
    Python
    QuickDraw GX
    Rendering
    Rhythm
    Rich Hickey
    Road Map
    Scheme
    Semiotics
    Sibelius
    Silicon Valley
    Site
    Skia
    Sponsorship
    Transposition
    UI
    Umberto Eco
    Vertigo
    VST/AU
    Wednesday Addams

    RSS Feed

Home
​Overview
Documentation
About
Contact
Newsletter
Ooloi is an open-source desktop music notation system for musicians who need stable, precise engraving and the freedom to notate complex music without workarounds. Scores and parts are handled consistently, remain responsive at scale, and support collaborative work without semantic compromise. They are not tied to proprietary formats or licensing.
​
Ooloi is currently under development. No release date has been announced.


  • Home
  • Overview
    • Background and History
    • Project Goals
    • Introduction for Musicians
    • Introduction for Programmers
    • Technical Comparison
  • Documentation
  • About
  • Contact
  • Home
  • Overview
    • Background and History
    • Project Goals
    • Introduction for Musicians
    • Introduction for Programmers
    • Technical Comparison
  • Documentation
  • About
  • Contact