|
Research for Ooloi’s input system turned up something I hadn’t expected. Igor Engraver’s Flow Mode – the modal, stateful keyboard entry that defined its way of working – has never been recreated. Not by Dorico, not by Sibelius, not by Finale, nor by any of the open-source projects. Twenty-three years on, the idea has simply vanished.
Flow Mode was straightforward. You pressed “.” once and staccato stayed active; crescendo and diminuendo wedges and slurs extended naturally as you continued writing. The commands mapped directly to the symbols – intuitive, fast, and oddly satisfying. When Igor died of business failure in 2001, the method died with it. There is no academic record, no terminology, no sign that anyone even remembered it existed. I had fully expected other programs to have copied this feature; it gives a five- to ten-fold increase in music-entry speed. Web forums on notation are full of people asking for faster, more fluent keyboard entry, yet without the vocabulary to describe what they want. They are looking for something they have never seen. So this part of Ooloi isn’t innovation; it’s recovery. The system worked. It was lost for reasons that had nothing to do with design. The decision to re-implement it, and the details, are now recorded in ADR-0032: Ooloi Flow Mode. What remains is to implement it – and to find Magnus Johansson, who just might still have the user manual.
8 Comments
'Well then, alone!' – Elektra's cry when Chrysothemis refuses to help her. Not triumphant independence, but desperate necessity fused with unwavering resolve. The isolation isn't chosen; it's forced by the impossibility of finding anyone who shares her singular purpose. Orestes isn't likely to materialise. There was a functional programming conference in Stockholm recently. I'm sure it was excellent. I didn't attend. I should probably have been there – Ooloi is built in Clojure, after all, and finding collaborators would be useful – but I felt conflicted, and that conflict revealed something I'd been avoiding: the FP community cannot help me, and I don't need it anyway. Sect DynamicsI'm disappointed with the functional programming community. I was expecting higher-level thinking – freer thinking, commensurate with the intellectual freedom Clojure itself offers – but the atmosphere proved to be a shallow puddle of sectarianism. That probably has its reasons – being marginalised as a community is probably one of them – but the end result remains unchanged. The patterns are unmistakable. Knowledge as gatekeeping: the endless monad tutorial phenomenon, where every advocate believes they can explain monads better than everyone else, typically through increasingly baroque metaphors involving burritos, space suits, or elephants. This isn't pedagogy; it's ritual initiation. The complexity serves a social function – maintaining boundaries between insiders and outsiders. Purity as virtue signalling: debates about whether using `IO` makes you impure, whether exceptions violate functional principles, whether mutation in bounded contexts is acceptable. These discussions frame technical trade-offs as moral categories, as though architectural design were a moral discipline rather than an engineering one. The language reveals it – clean, pure, disciplined versus dirty, impure, undisciplined. This is religious vocabulary applied to software engineering. Terminology as tribal marker: deliberate retention of academic terminology when simpler terms exist. Endofunctor, catamorphism, anamorphism when 'map over containers', 'fold', 'unfold' would suffice. The obscurity is the point – it establishes hierarchy and demonstrates membership. The emphasis falls on mathematical elegance rather than problem-solving. The question isn't Does this help ship software but Is this theoretically sound. People who can recite monad laws but have never shipped a product receive more status than developers applying functional patterns to solve actual problems. Then there's the missionary behaviour: the conviction that imperative programmers need conversion. The framework isn't Here's another useful tool but You're doing it wrong until you see the light. This creates antagonism rather than adoption. Being marginalised as a community probably explains some of this – defensive posture manifesting as increased boundary enforcement, which creates insider/outsider distinctions, which enables status hierarchies based on doctrinal purity. But understanding the cause doesn't change the result, and it doesn't make the behaviour intellectually rigorous or practically useful. The Clojure Exception Clojure largely escaped this because Rich Hickey explicitly rejected purity culture. 'It's acceptable to use Java libraries'. 'Mutability in bounded contexts is fine'. 'Solve problems first'. The Clojure community focused on what you can build, not on arcane knowledge as status marker. This produced broader adoption without compromising functional principles. This is why I chose Clojure for Ooloi in the first place. But even within that pragmatic oasis, the broader FP community dynamics leak through. The conference I didn't attend would have featured both kinds of people – those interested in building things and those interested in doctrinal purity – and I couldn't predict which would predominate. The Intersection Problem Here's the substantive issue: finding Ooloi collaborators in FP communities is statistically improbable because very few people occupy my intersection point between various disciplines. Music notation requires an understanding of compositional structure, engraving conventions, and how musicians actually work. Functional architecture requires a sophisticated understanding of immutability, higher-order functions, transducers, STM transactions, and compositional patterns. Backend infrastructure requires a willingness to work on unglamorous problems like endpoint resolution and temporal traversal rather than visible features, and in Ooloi's case, an understanding of server technology and secure cloud operations. The population at that intersection is approximately one. FP communities might yield people who appreciate my transducer implementations or STM transaction handling. But they won't understand why endpoint resolution for slurs matters, how temporal traversal serves musical structure, or what makes intelligent engraving different from geometric placement. The domain expertise is orthogonal to FP community concentration. The inverse holds equally: musicians who understand notation deeply rarely have the architectural sophistication to work on Ooloi's core, and even fewer would find satisfaction in building infrastructure rather than using tools. I've worked outside the FP community all my life. Functional programming is a tool, not a (monadic) religion. (And why are monadic and nomadic so similar?) Why join the community now, when the benefits are unclear and the costs palpable? Consilium LatinumThe technical response is what I call the Latin strategy: making Ooloi's core a stable foundation for a plugin ecosystem. Build the architectural core once in Clojure, then let developers in other JVM languages contribute via plugins without needing to understand the underlying functional implementation. I've written about this approach in Penitenziagite!, so I won't rehearse it here. Elektra or Quixote? The psychological question is whether this makes me Elektra or Don Quixote. Elektra confronts a real murder, real injustice, a legitimate need for action that others refuse. The isolation comes from their cowardice or pragmatism, not from her misunderstanding of reality. The task is achievable and gets completed. The tragedy is the psychological cost, not the validity of the purpose. Quixote confronts imaginary problems with obsolete ideals, mistaking windmills for giants. The isolation comes from a fundamental disconnect with reality. The task is impossible because it's based on delusion. The comedy (later tragedy) is that the quest itself is meaningless. The distinction depends on whether the problem is real. Do musicians actually need what Ooloi provides? If existing notation software genuinely fails at problems Ooloi solves, then Elektra. If musicians are adequately served by current tools, if the architectural sophistication I'm building doesn't translate to problems they actually experience, then Quixote. But there's a third option beyond tragic obsession and delusional quest. I'm building something architecturally excellent because I can, because it interests me, because functional approaches to musical structure are intellectually satisfying. The architecture might be elegant, but it's not worth psychological dissolution. The Latin model suggests I've already chosen this third path. I'm building core infrastructure well, documenting it properly, then making it available via plugin architecture that assumes others might have different needs. That's craft separated from identity. Not Dancing to DeathElektra's tragedy is total consumption by purpose. She becomes nothing but the task, and when it completes, there's nothing left because she permitted no existence beyond vengeance. She dances herself to death.
I'm certainly not doing that. Ooloi is a project, not my entire existence. Sustainable completion means finishing the backend, documenting it clearly, releasing it, and then moving on. The work stands independently; I remain separate from it. I'll finish Ooloi's core architecture working alone, not because I prefer isolation, but because collaboration at this intersection point is impractical. The resolve comes from accepting reality rather than pretending community exists where it doesn't. The backend is complete. The transducer-based timewalker is fast, tight, and efficient. Endpoint resolution handles slurs and ties correctly. Nearly nineteen thousand tests pass. Vector Path Descriptors enable elegant client-server communication. Then comes plugin architecture, and seeing whether anyone finds Ooloi useful. If they do, excellent. If they don't, I built something architecturally sound and learned what I needed to learn. Either way, the work speaks for itself. And I continue existing beyond it. Nun denn, allein! Every notation program eventually reaches the same constraint: the interface and the layout engine compete for control of time. When they do, the system freezes.
ADR-0031 defines how Ooloi avoids that conflict. Local actions such as editing, scrolling, and selection remain inside the JavaFX event system, which responds instantly. Network events, like collaborative edits or layout changes, are handled separately, through a dedicated Event Router that never blocks the interface. For engravers, this means something simple but long overdue: editing and scrolling stay smooth, no matter how large or complex the score, and no matter who else is working on it. The document doesn’t describe a finished feature; it describes the foundation that makes such responsiveness possible. From this point on, Ooloi’s design rests on a single rule: the interface must never wait for the network, and the network must never interrupt the interface. Full text → ADR-0031: Frontend Event-Driven Architecture Last week's discussion on VI-Control turned into an unintentional seminar on what 'open source' actually means. Nando Florestan, a composer and developer learning Clojure, read through the draft licence with unusual care and pointed out something I hadn't thought through properly: the anti-rebranding clause made Ooloi proprietary in practice. Forks would have been impossible without my permission. The OSI definition is clear: that's not open source, regardless of intent. He was right. The clause came from experience, not malice. Igor Engraver derailed out of my control, and I didn't want that repeated. But open source is a matter of definition, not sentiment. Trademark protects the name 'Ooloi'. Anything beyond that belongs to the commons. The fix was simple: remove the modification. Pure MPL 2.0, no amendments. Register the trademark properly. Add a clear policy statement confirming that plugins and applications built using Ooloi's APIs aren't derivative works. Better to discover it before release than after. The conversation forced me to confront what open source actually means for this project: giving up control while retaining integrity. Why MPL 2.0 The Mozilla Public Licence sits exactly where Ooloi belongs: halfway between the ideological asceticism of GPL and the cheerful anarchy of MIT. File-level copyleft keeps the core collaborative while leaving everything built upon it entirely free. Reciprocity without coercion. If someone improves Ooloi's STM transaction coordinator or gRPC layer, those improvements remain in the commons. If someone builds a sophisticated playback system or commercial notation front-end atop Ooloi, they own it completely. That's how platform infrastructure should work. The 'for the avoidance of doubt' clarification states what's already true: plugins, extensions, and applications using Ooloi's APIs aren't derivative works. This matters because commercial developers won't participate if they need solicitors to interpret 'Larger Work' provisions. The clarification prevents that friction. The Alternatives FailGPL would poison the plugin ecosystem. The FSF's position on plugins-as-derivatives creates legal ambiguity that kills commercial participation. No professional algorithm vendors, no sophisticated commercial tools, no ecosystem. Apache/MIT/BSD permits enclosure. Someone could fork Ooloi's core into proprietary software, capturing improvements that should remain shared. For infrastructure intended as commons, permissive licences are actually less free. AGPL extends copyleft to network usage, which would criminalise legitimate commercial deployments: publishers running collaborative servers, institutions hosting multi-user environments, enterprises managing internal infrastructure. LGPL adds complex compliance requirements without benefits. MPL 2.0's file-level copyleft provides cleaner separation. The WordPress ParallelThe economics mirror WordPress's evolution. Core CMS functionality became commoditised infrastructure. Commercial value migrated to themes, plugins, hosting, services. Companies like Automattic built substantial businesses while the core improved collaboratively through thousands of contributors. Ooloi follows similar logic. What legacy notation systems monetise becomes architectural givens:
Commercial opportunities shift to where genuine value exists: sophisticated interfaces, professional algorithms, premium workflows, enterprise services. The core handles infrastructure. The plugins handle musical domain knowledge. The Ultimate IronyUnder MPL 2.0, a product such as Järvenpää Silence Notator 2.0 (purely hypothetical, right?) could theoretically build atop Ooloi while maintaining proprietary differentiation through proprietary plugins and interface. The core infrastructure they'd no longer need to maintain. The competitive advantages they'd demonstrate through superior musical intelligence. Whether this happens is irrelevant. The goal is proving that functional programming solves long-standing problems, enabling possibilities previously impractical: real-time collaboration without subscription lock-in, parallel processing without performance collapse, plugin extensibility without architectural fragility. The licence ensures improvements flow back to the commons while permitting commercial innovation. Practical ImplicationsFor developers evaluating Ooloi: Building plugins: Licence them however you want. Sell them, give them away, open-source them. No GPL contamination, no AGPL network copyleft. MPL 2.0 applies to Ooloi, not to your work. Modifying Ooloi's core: File-level copyleft applies. Modified files must remain MPL 2.0. You can still build proprietary applications using modified Ooloi. Just release your modifications to Ooloi's source files. Commercial deployment: Run SaaS services, embed in proprietary applications, charge what you like. MPL 2.0 requires nothing from you unless you modify core files. On Integrity Licensing isn't a legal appendix to the codebase; it's part of the architecture. A distributed system defines its boundaries through protocols. A licence does the same, only in law instead of syntax. Open source isn't marketing; it's a contract of trust. You keep the code open not because you must, but because integrity demands it. You protect the name not to hoard it, but to prevent confusion. Ooloi's licence now mirrors its architecture: clear boundaries, open interfaces, and a shared foundation for whatever might be built next. Clarity and transparency. When we last measured Ooloi’s storage engine, 50,000 musical objects occupied 14.5 KB – about 0.3 bytes per note. That already hinted at something unusual. The new benchmarks confirm it. A 1,000-measure orchestral score for 3333 / 4331 + piano + divisi strings was used as the test case – the kind of piece length found in the largest late-Romantic works: Wagner’s Götterdämmerung, Strauss’s Elektra, or Mahler’s Eighth Symphony. For non-musicians, 3333 / 4331 means three flutes, three oboes, three clarinets, three bassoons; four horns, three trumpets, three trombones, one tuba; plus piano and strings divided into multiple independent parts. In total: 29 staves, over 520 000 pitches, and thousands of simultaneous events – a scale that has historically defeated notation programs. So the orchestra is medium-sized romantic, but the length and amount of music is extreme: everyone is playing fast notes from start to finish. The benchmark is designed to test a heavy score. Bring on the worst case, so to speak. File Size and Persistence Saving this complete piece took 1.3 seconds; loading it, 3.3 seconds. The resulting file was 172 KB – smaller than a single page of PDF. The piece does not yet include graphical information (layout, coordinates, glyphs), which would roughly double the size or more, but at these levels it makes no practical difference. Even if it becomes ten times larger, it's still of no consequence. The numbers are that good. Streaming export (MIDI or MusicXML) completed in 1.25 seconds, using under 10 MB of memory. Even full materialisation of every internal element peaked at 244 MB, far below what such scores normally require. Traversal and ComputationBehind those figures lies the traversal engine that makes them possible. The full 520 000-pitch traversal completed in 0.58 seconds – roughly one million pitches per second. Cache repairs and dependency updates finished in 1–5 ms. Endpoint searches (for ties and slurs) are blazingly fast too, obviating the need for direct pointers. For comparison, a score of this magnitude would have strained the limits of any existing notation program. Finale or Sibelius might take tens of seconds – sometimes minutes – to perform an equivalent operation. Ooloi completes the same structural pass between heartbeats. What the Numbers Mean What makes this possible is not optimisation trickery but architecture: immutable musical data, transducer-based traversal, and disciplined cache coherence across every layer. The system streams; it does not churn.
For composers and engravers, these results suggest something once thought impossible – that even a full Wagnerian tutti might one day update instantly after an edit. Everything so far indicates that this should be achievable, not through hardware brute force but through architectural clarity. For developers, the message is the same: a purely functional, streaming model can handle orchestral-scale data in constant memory, with sub-millisecond locality. As far as I know, this is the first time a professional notation system has demonstrated real-time traversal of a Wagner-scale score with constant memory and sub-second exports. The invisible foundation – the hard part – is finished. All tests were run on a 2017 MacBook Pro with a 2.2 GHz six-core Intel i7 processor and 16 GB of RAM. A modern 2025 laptop or workstation would almost certainly halve every number reported here, and perhaps more. What feels instantaneous today will, in a few years, be beyond perception. Full benchmark results here. Still on track towards that goal of smooth scrolling through the Elektra recognition scene. Yes, another technical post. But this one explains why Ooloi doesn't demand you become a programmer to use it, or learn Latin to extend it for your specific needs. The architecture matters precisely because it removes barriers rather than creating them. In Umberto Eco's The Name of the Rose, a mad monk wanders through the monastery corridors shouting 'Penitenziagite!' – corrupted Latin mixed with vernacular, incomprehensible noise that might be prophecy or might be madness. Communication fails not from lack of content, but from linguistic confusion. The message is lost in translation. Software architectures shout 'Penitenziagite!' constantly, and we've grown so accustomed to the noise that we mistake it for communication. The Language Impedance ProblemWhen you write a plugin for a system, you shouldn't need to learn the implementation language. That seems obvious, yet most software makes exactly that demand. Functional programming libraries leak monads into Java APIs. Object-oriented frameworks force functional concepts into awkward method chains. Every language boundary becomes a barrier, every abstraction a translation exercise. The pattern is familiar:
This isn't malice. It's accidental linguistic imperialism – systems that never considered the difference between internal precision and external accessibility. The Monastic PatternMedieval monasteries preserved knowledge in Latin – a dead language, deliberately removed from common speech, chosen for precision and permanence. Yet they didn't demand everyone learn Latin to benefit from monastery medicine or improved agriculture. The knowledge stayed pure in the centre; the benefits propagated outward in the vernacular. Ooloi follows this pattern. The core is written in Clojure. This isn't negotiable, because the hard problems in music notation software require immutability, structural sharing, and proper concurrency. Functional programming isn't a preference; it's the only approach that doesn't collapse under its own compromises. But plugins can be written in Java, Kotlin, Scala, or any JVM language. Not as second-class extensions with limited capabilities, but as first-class citizens with full API access, equal performance, and no artificial limitations. The JVM interop means there's no penalty for crossing the boundary – your Java plugin operates with the same guarantees as code written in Clojure. This arrangement has three parts: I: The Scriptorium (Clojure core) – Where the hard problems are solved with uncompromising discipline. Immutable data structures provide structural sharing. Temporal coordination via the timewalker ensures correct musical semantics. STM enables proper concurrent editing. Zero-allocation hot paths ensure performance. This is where craft is mandatory, not aspirational. II: The Library (canonical plugins in Clojure) – Reference implementations showing how the architecture should be used. Teaching by example, maintaining standards, preserving patterns for others to study. III: The Gate (JVM plugin system) – The boundary that speaks idiomatically in every JVM language. Immutability guarantees propagate transparently. Plugin developers work naturally in their chosen language whilst benefiting from the rigorous core. Why This Structure WorksThe core cannot compromise. If mutability seeps in, if temporal coordination is abandoned for convenience, the whole thesis fails. The hard problems must be solved correctly, once, in the protected centre. But the perimeter cannot be closed. If only Clojure developers can extend Ooloi, adoption remains limited to those willing to learn functional programming. The architectural advantages – provable speedup on reflow operations, proper concurrent editing, elimination of state-corruption bugs – must be accessible without requiring conversion. This isn't architectural fussiness. It's the difference between a system that proves functional programming solves these problems and one that merely claims it whilst forcing everyone through the same narrow gate. Consider the alternative: most cross-language projects either compromise the core's purity to make external access easier, or maintain purity whilst making extension nearly impossible. Both approaches fail – the first produces unreliable systems, the second produces unused ones. First-Class CitizenshipWhen I say plugins are first-class citizens, I mean it precisely:
Your Java plugin implementing custom layout rules operates with the same capabilities as Clojure core code. The boundary is invisible – just clean interfaces and reliable contracts. No Penitenziagite Here Ooloi's architecture refuses the mad monk's cry. No demand that you learn Clojure to participate. No leaked functional programming concepts in the public API. No linguistic imperialism masquerading as technical necessity. The core speaks Clojure because that's the right tool for solving these problems correctly. The plugin system speaks your language because that's the right way to enable participation. Each side of the boundary uses the language appropriate to its purpose. This is architectural empathy: not compromise, but proper boundary design. The scriptorium can maintain Latin for precision whilst the gate speaks the vernacular. Work continues: the monastery's standards hold. The architecture neither shouts incomprehensibly nor demands conversion. There's no Inquisition burning engraving monks at the stake. The point isn't piety; it's architecture that stays intelligible. Just clarity, properly structured. – William of Baskerville Last week I wrote about flipping the Staff→Voice→Measure hierarchy to Staff→Measure→Voice. The structural reasons were sound, but I'd estimated a week for the implementation. Forty files to touch, thousands of tests to update, the whole spine of the system. With a 1:1 ratio of code to tests, that's rather a lot of surface area to cover. This usually means a lot of pain. The actual time: four hours. Claude Code's systematic approach made the difference. Seven discrete steps, continuous test validation, zero functionality regression. Tests failed as expected during refactoring, but the effort to fix them was absolutely minimal. This wasn't vibe coding; I controlled the process carefully, directing each step. Yet even with that careful oversight, the work required was remarkably little. Claude 4.5, being new and even more capable, may well have been key here. The result was better than expected as well: 30–99% less allocation through transducer-based lazy sequences, 211 fewer lines of code, clearer logic throughout. What surprises me isn't that AI-assisted development helped; it's the magnitude. A tenth of the expected time isn't incremental improvement. That's a different category of capability entirely. Now on to some small bits and bobs before the real work on the client starts: windows, drawing, printing, etc. I've been thinking about how to actually render music notation in Ooloi – not the data structures or the algorithms, but the visual side. Putting notes on a page. It turns out that trying to draw something has a way of exposing assumptions you didn't know you'd made. When you're formatting a measure, you need to see everything that's happening simultaneously in that slice of time. All the voices at once, so you can work out spacing, avoid collisions, align things vertically. It's how a conductor thinks about a score: bar 5 across all the instruments, not following each instrument's line from beginning to end. Here's the difficulty: in our current model, voices own measures. To get 'everything in measure 5', I have to find all the voices in a staff, look inside each one, find measure 5 in each voice, and collect them all together. I'm reconstructing what the printed page shows me directly: measure 5 contains these voices. The Original StructureThe hierarchy looked like this This seemed sensible at first. We were thinking about voices as independent melodic lines that happen to align at measure boundaries. We even structured it this way to handle ossia staves (those little alternative passages that appear for a few measures then disappear). But that's not how notation actually works. Measures are the organising unit. Voices are just 'simultaneous material in this measure'. The Revised StructureMeasures contain voices. Problem solved: 'give me everything in measure 5' is just a direct lookup. All the voices are right there. And ossia staves? Actually clearer in this model. A staff just enters at measure 17 and exits at measure 20. Clean and explicit. The ImplementationThe conceptual change is straightforward: flip the hierarchy so measures contain voices instead of voices containing measures. The implementation touches about 40 files because this hierarchy is everywhere – it's the spine of the system. Record definitions, accessor methods, specs, generators, thousands of tests, documentation. Everything builds on this assumption. But here's the thing: it's still intellectually manageable despite being architecturally pervasive. We're not adding complexity or clever tricks. We're just making the model honest. Every place that changes is a place where the code now says something true instead of something awkward. The timewalker (the thing that walks through a piece in temporal order) becomes significantly more efficient too. Instead of recursing through voices to find measures, it just walks the measures directly. We're expecting 15–35% fewer allocations – fewer temporary objects being created and discarded, which means it runs faster with less memory overhead. Discovery, Not PlanningHere's what's interesting: I didn't know this change was necessary until I started thinking about rendering. The original model wasn't obviously wrong. It worked fine for everything we'd built so far. Only when I sat down to work out how to actually draw the notation did the mismatch become clear. This is the value of working without artificial deadlines. If I'd been rushing to ship something, pressured to show 'progress' to investors or whoever, I'd have built the formatting layer on top of the awkward structure. It would have worked, sort of. With enough wrapper functions and helper methods, you can make anything work. But that's exactly how technical debt accumulates. You build on a foundation that's slightly crooked because you don't have time to straighten it. Then you build on top of that. Eventually the whole thing is held together with duct tape and hope rather than sound engineering. Instead, because I'm approaching this from a computer science angle rather than chasing some market opportunity, I can pause when something feels wrong and ask: is the model lying to me? Should I fix this now, while it's still straightforward, before I've built a cathedral on quicksand? The answer was yes. So we fix it. The architecture stays clean. No debt accumulates. When we get to rendering, the code will be straightforward because the structure matches what we're trying to do. Transparency as MethodA commercial project wouldn't announce an architectural change like this. It would be seen as weakness – proof that the team didn't plan properly, didn't understand the domain, had to change course because they got it wrong. But this isn't a commercial project. It's research. It's domain adaptation. In research, discovering that your model needs adjustment isn't failure – it's progress. You learn something about the domain you didn't know before. You refine your understanding. You make the system better. So I'm documenting it openly. Not because I have to, but because it's interesting. Because someone else working on music software might hit the same realisation. Because transparency about process (including the adjustments and course corrections) is more valuable than maintaining some illusion of perfect foresight. In commercial software, there's pressure to appear confident and consistent: it's part of the corporate theatre. In research software, there's freedom to be honest about what you're learning as you go. Why This MattersWhen your data structure fights the domain, everything becomes harder. Performance tricks, validation logic, traversal algorithms – they all work around the mismatch instead of with the model.
When the structure matches reality, everything becomes easier. The formatting code that sparked this whole thing? It'll be trivial now. Just iterate measures, render their voices. Done. This is one of those changes that seems obvious in hindsight but not when you're in the middle of building. You pick a structure that appears reasonable, you build on it, and only later when you try to use it do you realise the foundation is slightly crooked. The question is whether you have the time and space to fix it, and whether you have the honesty to admit it needs fixing. I'm fortunate. I have the time. This project doesn't require me to pretend otherwise. And if the page keeps telling me the model is lying, I'll keep listening. There are days in Ooloi’s development when I feel like the Donald. Not that Donald. Donald Knuth. There's something very real to that comparison, even though it can be seen as presumptuous. Why do I compare myself with a computing giant? Knuth faced typesetting systems that were brittle, ad hoc, and incapable of scaling to real demands. He didn’t patch; he rebuilt the foundations. Out came deterministic algorithms, the box–glue model, and a system that still sets type decades later. I’m in a similar place. Music notation software has been compromised for forty years: mutable object graphs, procedural hacks, import/export traps. It works until you open Eine Alpensinfonie or Lontano – then it collapses. So Ooloi is built the way TeX was:
And even a year isn’t slow, considering what's been implemented in that time. In Clojure, as in Lisps generally, progress is faster, not slower, because the language doesn’t get in the way. Architectural changes that would take months in procedural or OO systems collapse into days when immutability is the default. In Lisps I feel unrestricted from the usual … bullshit. Durability and Time HorizonsKnuth didn’t set out to make a fashionable typesetter. He built TeX so mathematicians could publish without degradation, and so his own books could be set correctly fifty years later. The result is software still alive in 2025. That perspective matters. Most software is written to meet the next deadline or release cycle, and dies within five years. Architecture shaped by durability instead of expedience looks very different. It avoids local hacks in favour of structural clarity. It makes changes faster, not slower, because the invariants hold. Ooloi is built on the same horizon. It’s not about matching today’s competitors feature for feature; it’s about whether the system can handle repertoire and practices that will still be with us in fifty years. Knuth wasn't out to childishly 'disrupt' anything. Neither am I. And for the same reasons. Outlasting FashionTeX has been called unfriendly, arcane, even ugly. But it outlasted beautiful GUIs because its correctness was deeper than its interface. It solved the right problem once, and has been binding books and journals ever since.
Ooloi certainly won’t look like TeX. It will be graphical, collaborative, and real-time, and it will have a slick, modern GUI. But it follows the same ethic: stop patching, stop pretending, build a system that doesn’t collapse under its own compromises. That’s the point of the parallel. Knuth showed what software can be when it’s built for durability rather than fashion. That’s the road Ooloi is on. I'm one of the world's most committed anti-religious people. Despite decades at organ consoles in churches and cathedrals, I stand with Hitchens: religion is humanity's adolescent phase, something we need to outgrow. Its influence is fundamentally harmful. But when I read something like How Lisp Became God's Own Programming Language, I completely understand the reverence the author describes. There's something about Lisp – and Clojure – that creates what you can only call a transcendental response. Nothing actually transcendental happens, of course, but the feeling is real. What Lisp gives you is freedom. I've written about 'windsurfing through parentheses' before, and the metaphor sticks because it captures something essential. Most programmers are chained to the oars of enterprise slave galleys, with CTOs yelling 'RAMMING SPEED!' like that brilliant scene from Ben-Hur. Meanwhile, those of us who've found Lisp are windsurfing in circles around them, enjoying a freedom they can barely imagine. The discovery feels like Dave Bowman meeting the monolith: 'My God... it's full of stars!' That vertigo when you realise this thing's inner dimensions vastly exceed its outer ones. Lisp isn't transcendental, but it works like a star gate in both senses. The language doesn't get in your way, and it opens new ways of thinking. At the same time, it's so simple that complexity becomes manageable.
I remember that August 1979 BYTE magazine perfectly. The cover promised mysteries, the articles delivered. I couldn't wait to start implementing what they described – eventually doing it in 6502 assembler, using an assembler I'd written in BASIC. Everything clicked, even as a teenager. This was real freedom, expressed as code. Years later, I wrote HotLisp (or 'HotLips' – M.A.S.H. was huge then) for the Royal College of Music in Stockholm. It was incredibly ambitious: a full Common Lisp that treated MIDI events as first-class citizens. Looking back, I see this as the beginning of what became Igor Engraver – integrating music directly into the computational core. We used it to control our Synclavier and MIDI synths whilst teaching algorithmic composition to advanced students at the Royal Academy. The Two-Bit History article nails something important about Lisp's mystique. It traces the evolution from McCarthy's 'elegant mathematical system' through AI research, Lisp machines, and SICP's role in making it the language that 'teaches you programming's hidden secrets'. Each phase built the reputation. What the article doesn't cover is the educational betrayal that followed. Computer science departments got it right for a while – they taught Scheme as a first language because it let students focus on learning algorithms rather than wrestling with syntax. Pure freedom to think about problems. Then Java Enterprise was foisted upon the world, the departments caved in, and they started churning out galley slaves instead of computer scientists. I see this as nothing short of high treason. But here's what really matters: that freedom has evolved in Clojure. Rich Hickey didn't just bring Lisp to the JVM – he solved problems that even Common Lisp couldn't handle elegantly. Those immutable data structures aren't academic toys; they're game changers that eliminate whole categories of bugs whilst making concurrency and parallelism natural instead of terrifying. The effects ripple out: undo/redo becomes trivial, and the JVM gives genuine multi-platform reach. This isn't just improvement – it's architectural breakthrough disguised as evolution. Clojure keeps Lisp's essential quality (that feeling of discovering how programming should work) whilst solving modern problems McCarthy couldn't have anticipated. The poor souls in corporate Java shops keep rowing, occasionally granted small mercies as functional concepts trickle in – hints of the freedom they're missing. I wish they could experience what we know: programming doesn't have to feel like industrial labour. There's a way of working where ideas flow directly into code, where the language becomes transparent, where you stop fighting tools and start windsurfing through solutions. Maybe that's the point. As McCarthy noted in 1980, Lisp survives not because programmers grudgingly accept it as the best tool for each job, but because it hits 'some kind of local optimum in programming language space'. It endures even though most programmers never touch it, sustained by reports from those who've experienced its particular form of computational enlightenment. Until we can imagine God creating the world with some newer language – and I doubt that day is coming soon – Lisp isn't going anywhere. Read the full article at Two-Bit History: https://twobithistory.org/2018/10/14/lisp.html We tested it. 50,000 musical objects: 14.5KB total on disk. Not megabytes. Kilobytes. That's not even 0.3 bytes per note. MusicXML equivalent: ~50MB. That's 3500x larger. Save/load time: about 250ms on a crappy 2017 MacBook Pro. These are just the core musical objects - pitches, rests, chords, articulations. A complete score adds instruments, parts, staves, layout data, and more. But the efficiency gains indicate what's possible when you eliminate redundancy at the foundation. The venerable technique hash-consing (1958, from LISP and symbolic computation) works. Of course it does – and how! Article on implications coming. Musical scores are full of repetition. In a symphony, middle C can appear thousands of times, quarter notes dominate, and the same staccato mark is scattered across every instrument. Most notation software allocates a separate object for each of these occurrences. That means thousands of identical objects, all taking memory and I/O bandwidth for no reason. Ooloi doesn't. With ADR-0029, we have implemented selective hash-consing: identical immutable musical objects are represented by the same instance. The same C4, the same staccato, the same quarter note: one object, shared system-wide. Why "Selective"?Not everything benefits. A forte marking may appear only a handful of times; a slur always connects specific endpoints. Caching those adds overhead without real gain. So the system targets high-frequency cases (pitches, rests, chords, common articulations) and ignores the rest. What this changes
All of this is transparent. Musicians won't 'use' hash-consing; they'll just notice that large works open, scroll, and save without drama. Why it works here In mutable architectures, shared objects are a trap: one stray modification contaminates every reference. Defensive copying and locks erase any performance benefit. In Ooloi, immutability is the rule. Sharing is safe. No copies, no locks, no bugs.
This isn't the kind of feature that makes a demo screenshot. It's one of the architectural foundations that decides whether the system will still perform when you open Mahler's 8th or La terre est une homme. It took days to implement. That's the difference Clojure makes. Finishing the statistics infrastructure naturally led to thinking about the next architectural milestone: the rendering pipeline. This is the mechanism that determines what happens when someone clicks into a score to add a note, and how that change propagates through the system. The design is complete. That in itself is an important milestone, as this is the very foundation on which Ooloi's performance ultimately depends. Everything hinges upon it. Why a Pipeline? Traditional notation software recalculates entire scores when a single element changes. Dense passages in works like Strauss's Elektra bring systems to a halt because every operation is sequential and single-threaded. The reason for this is that parallelism is very difficult to do with mutable state, which is the traditional approach. Scalability often becomes an issue, with diminishing returns as a result. Ooloi takes the opposite approach and chooses the Clojure way instead, with immutable state. With this, it is comparatively easy to distribute formatting work across all available CPU cores and use them fully and linearly. Every user action – whether adding a single note or adjusting spacing – thus becomes part of a coordinated cascade where each stage can run in true parallel across all available cores. The goal is straightforward: responsive editing even in the heaviest repertoire. Five StagesADR-0028 specifies the pipeline in five stages, separating connecting from non-connecting elements and applying a clear fan-out/fan-in pattern.
This separation allows Ooloi to exploit parallelism where possible and enforce order where necessary. Plugins as First-Class Citizens Formatting in Ooloi is plugin-driven. Core elements such as notes and beams are implemented through the same interfaces available to extensions. Plugins can participate in different stages depending on their needs:
Simple articulations may use only the first two; beams may require all three. This uniform model ensures extensibility without compromising performance. Convergence by DiscomfortThe optimisation engine measures deviation from ideal proportions across measures, systems, and pages. Improvements multiply: small gains in multiple places compound into significant overall reductions. Hard constraints such as manual breaks provide natural stopping points. This replaces arbitrary iteration limits with a principled measure of quality. Parallelism and Responsiveness Claypoole provides efficient thread-pool execution, delivering significant speed-ups over built-in Clojure parallelism. STM transactions keep operations atomic while allowing concurrency inside each stage. Cooperative cancellation ensures that rapid user input remains responsive. The system treats a single user as a 'collaboration network of one'. The same infrastructure that supports multi-user editing ensures smooth interaction for individuals. Where This Leads This pipeline is the structural core that should make scrolling through Elektra or Ligeti's Requiem as fluid as editing a Gnossienne by Satie. The specification is complete. Implementation begins as soon as the current phase closes. Ooloi's promise of responsive, professional-scale notation depends on it. Scary stuff. Full specification: ADR-0028: Hierarchical Rendering Pipeline with Plugin-Based Formatters
After a year of building infrastructure, it seemed worth finding out whether it actually worked. The test was simple: create a million rests and see what happened. One operation – – repeated until either something broke or the numbers settled. Single Thread, Single ClientFirst experiment: one client, one thread, a million sequential calls. This was on a 2017 MacBook Pro, so not exactly cutting-edge hardware. Every call succeeded. Average execution time was 35 microseconds. Memory stayed at 112 MB without drifting upwards. Garbage collection remained in the young generation. Thread count didn't move. Zero errors. Nothing dramatic, which was the point. Adding ConcurrencySecond test: four threads on one client, 250,000 calls each. Another million operations, but with some concurrency this time. Same result. All calls succeeded, memory stayed flat, garbage collection behaved, threads were stable. Still zero errors. This level of concurrency should be unremarkable for any serious system. It was. Multiple ClientsThird experiment: ten clients, four threads each. Forty threads total – enough to make the laptop work. Average call times went up to 246 microseconds, but everything else held steady. Memory stable, garbage collection well-behaved, threads disciplined. Error count still zero. Same 2017 laptop that started the tests. What This MeansFrom one thread to forty, from 35 microseconds to 246, the pattern was consistent. The system handled load without breaking.
These were only raw API calls, not STM transactions with musical logic and collaboration on top. Those will be next. For now, the figures suggest the foundations are fast, steady, and ready to carry more. After a year of working only on foundations – work that must succeed by disappearing – we are finally ready to turn to visible things. Music, for instance.
This Grafana dashboard shows eighteen minutes of a distributed system handling real client connections. The server sits at a 44 MB baseline and stays there: no memory growth, no thread churn, zero old-generation garbage collections. The jump to 83 MB comes not from client load, but from Grafana itself polling for statistics. Those numbers matter because they validate architectural decisions made months ago. Functional programming principles, STM coordination, gRPC infrastructure: all the invisible work that had to be right before building anything a user might see. Stable thread pools. Clean memory management. Efficient client handling. Nothing dramatic – just solid enough to carry what comes next. The system no longer needs proving. Now it needs notes. Yesterday’s post was about pitch transposition in Ooloi: how an old Igor Engraver function (printed on a t-shirt, of all places) came back to life in a new context. That work didn’t just solve the mechanics of shifting notes up and down; it reopened the larger question of playback. How do you hear microtonality and advanced humanisation without drowning in technical workarounds?
In Igor, the answer was MIDI. Notes were split across channels, bent into place, reassigned constantly. The result worked, but at the cost of complexity: a “DNA soup” of allocations and pitch-bend tricks. Ingenious, but exhausting. Ooloi makes a different choice. With ADR-0027: Plugin-Based Audio Architecture, we draw a line: no MIDI output in the core, no audio generation in the backend. Playback is done entirely through plugins in the frontend. If you want VST/AU instruments, SoundFonts, OSC, or any other output path, you install a plugin. The backend remains what it should be: musical data, collaboration, structure. This is not just simplification, it’s liberation.
Put bluntly: we no longer need MIDI as an output protocol. It served its time. For professionals who need nuanced playback, orchestral realism, or contemporary techniques, we now have better tools: VST/AU plugins and beyond. That said, MIDI output isn’t forbidden. If anyone needs it, a frontend plugin can provide it. For tonal music it will work fine. But if you want advanced humanisation or microtonality, you’ll inherit the need for all the old machinery: channel allocation, pitch-bend acrobatics, the DNA soup. That’s exactly why Ooloi itself doesn’t touch it. The logic is simple: Ooloi’s core manages music, not sound. Plugins handle playback, and in doing so, they do it better than MIDI ever could. The DNA soup is gone. What remains is clean, modern, and far more powerful. There's something rather fitting about finding your programming salvation at the bottom of a laundry basket. Not that it had been there for twenty-five years, mind you – I'm not quite that slovenly. But when the moment arrived to resurrect Igor Engraver as the open-source project now becoming Ooloi, I suddenly realised that the only piece of original code I possessed was printed on a promotional t-shirt from 1996. The search was frantic. I'd just committed to rebuilding everything from scratch: Common Lisp to Clojure, QuickDraw GX to modern graphics, the whole shebang. Yet somewhere in my flat lay a single fragment of the original system, a higher-order function for creating pitch transposers that I dimly recalled being rather important. After tearing through a hundred-odd t-shirts (mostly black, naturally), I found it crumpled beneath a pile of equally rumpled garments. The print quality had survived remarkably well. More remarkably still, when I a few days ago, after a year of implementing the Ooloi engine, fed the photographed code to ChatGPT 5, it immediately identified this transposer factory as the architectural cornerstone of Igor Engraver. That was both validating and slightly unnerving: I'd forgotten precisely how central this code was, but an AI recognised its significance instantly. I clearly had chosen this piece of code for this very reason. And as LLMs are multidimensional concept proximity detectors, the AI immediately saw the connection. Now it was up to me to transform and re-implement this keystone algorithm. The Dread of UnderstandingI'd glimpsed this code periodically over the years, but I'd never truly penetrated it. There were mysterious elements – that enigmatic 50/51 cent calculation, for instance – that I simply didn't grasp. The prospect of reimplementing it filled me with a peculiar dread. Not because it was impossibly complex, but because I knew I'd have to genuinely understand every nuance this time. Pitch representation sits at the absolute heart of any serious music notation system. Get it wrong, and everything else becomes compromised. Transposition, particularly diatonic transposition, must preserve musical relationships with mathematical precision whilst maintaining notational correctness. A piece requiring a progression from C𝄪 to D𝄪 cannot tolerate a system that produces C𝄪 to E♮, regardless of enharmonic equivalence. The spelling matters profoundly in musical contexts. And then there's the microtonal dimension. Back in 1996, no notation software could actually play microtonal music, even if some of them could display quarter-tone symbols. Igor Engraver was different: our program icon featured a quarter-tone natural symbol (𝄮) for precisely this reason. My original intended audience consisted primarily of contemporary art music composers who needed these capabilities. I needed them myself. MIDI SorceryOur solution was elegantly brutal: we seized complete control of attached MIDI units and employed pitch bend to achieve microtonal accuracy. This required distributing notes across MIDI channels according to their pitch bend requirements, using register allocation algorithms borrowed from compiler technology. In a chord containing one microtonally altered note, that note would play on a different channel from its companions. We changed patches frantically and maintained no fixed relationship between instruments and channels – everything existed in a kind of 'DNA soup' where resources were allocated dynamically as needed. This approach let us extract far more than the nominal sixteen-channel limit from typical MIDI synthesisers. We maintained detailed specifications for every common synthesiser on the market, including how to balance dynamics and handle idiosyncratic behaviours. Real-World Musical IntelligenceThe system's sophistication extended well beyond pure pitch calculations. When my opera The Maids was commissioned by the Royal Stockholm Opera, I spent considerable time crafting realistic rehearsal tapes. Everything I learned from that process was automated into Igor's playback engine. We also collaborated with the KTH Royal Institute of Technology Musical Acoustics department, led by the legendary Johan Sundberg, whose research had quantified subtle but crucial performance characteristics. Those famous four milliseconds – the consistent temporal offset between soloists and accompaniment in professional orchestras – found their way into our algorithms. Such details proved particularly effective with Schönberg's Hauptstimme markings (𝆦) or similar solo indicators. We also developed what my composer colleague Anders Hillborg and I privately called 'first performance prophylaxis' – a deliciously cruel setting that simulated the sound of musicians who hadn't practiced. In other words, the kind of sound landscape any composer is used to hearing at a first orchestral rehearsal of a new piece and which always makes you doubt your own talent. Turn this setting up, and you'd hear a characteristically dreadful youth orchestra. Turn it down completely, and you'd get the robotic precision that plagued every other MIDI system. Rather like Karl Richter's Baroque organ recordings. The humanisation algorithms incorporated realistic instrumental limitations. Passages written too quickly for an instrument would skip notes convincingly. We modelled the typical rhythmic hierarchy of orchestral sections: percussion most precise, then brass, then woodwinds, with strings bringing up the rear. Instruments were panned to their proper orchestral seating positions. Piccolo trills were faster than tuba trills. The result was startlingly realistic, particularly by 1996 standards. The ADR and Current Reality Now, twenty-five years later, that laundry basket discovery has culminated in ADR 0026: Pitch Representation and Operations, documenting Ooloi's comprehensive pitch representation system. The original Common Lisp has been reborn as Clojure code, with string-based pitch notation ("C#4+25") serving as the canonical format and a factory-based transposition system supporting both chromatic and diatonic modes. The string representation offers several advantages: compact memory usage for large orchestral scores, direct human readability for debugging, and seamless integration with parsing and caching systems. Most crucially, it supports arbitrary microtonal deviations, something that remains problematic in most contemporary notation software. The factory pattern generates specialised transposition functions that encapsulate their musical behavior rules through closures. Rather than repeatedly passing configuration parameters, the factory creates efficient, composable functions that understand their specific musical contexts. A diatonic transposer preserves letter-name relationships; a chromatic transposer produces frequency-accurate results with canonical spellings. ClosureThe t-shirt in my laundry basket represented more than nostalgic memorabilia; it was unfinished business. That higher-order function embodied a sophisticated understanding of musical mathematics that took a long time to develop and seconds for an AI to recognise as architecturally significant.
Now, with Ooloi's pitch operations properly documented and implemented, that business approaches completion. The code has evolved from promotional garment to production system, carrying forward those insights from 25 years ago into a new, modern technological context. It's exciting. And still a little unnerving. Three tests left on the visibility work. After that, this part of the system is done. It’s taken a few weeks to get the final bits of the gRPC server/client interaction implemented, but it now feels solid. The server reliably and efficiently handles all the complex aspects of live clients connecting, disconnecting, and communicating locally or over the inherently chaotic internet. With that done, the focus is now on what is called observability: being able to see what's going on inside. In other words, server statistics. We’re now tracking server-wide and per-client metrics: connections, API call rates, message sizes, event streaming, queue overflows. Endpoints can return JSON during development or Prometheus format in production. Content negotiation is automatic, or you can force a format with a query parameter. No new tools to learn. Grafana dashboards work straight away. Why this matters for musicians: research has shown that in collaborative settings, users prefer a notation program that lets them work together over one with the most features. That says everything about how poorly existing software supports collaboration. It’s treated as an optional extra, if it exists at all. Ooloi is built differently. Collaboration is not bolted on afterwards but designed into the system from the start. If event queues slow or connections drop, collaboration breaks down. A slur added on one screen never appears on another, or two edits collide and the score diverges. The statistics make these problems visible. They show when the system is stressed, when clients are falling behind, when the score risks drifting out of alignment. In short, they make collaboration trustworthy. And unlike the current trade-offs, Ooloi isn’t choosing collaboration instead of notational depth. It is designed to be both: a serious, advanced notation platform that also makes shared editing reliable. The same architecture also opens up another possibility. Because Ooloi is client/server, it can stream smoothly scrolling scores in real time. That makes digital music stands for ensembles or orchestras feasible. It’s not the main focus, but it’s there: the professional counterpart to the school-level collaboration studies. Three tests left. Once they pass, the intricate server machinery will be visible. And visibility is the first condition for trust. Ooloi is moving fast. Architectural decisions, implementation milestones, and the long road toward open-source release deserve a channel that isn’t buried in blog posts or scattered across updates. The Ooloi Newsletter is that channel. It’s for composers frustrated with the lag of existing software, musicians curious about what modern architecture makes possible, educators and publishers planning future workflows, and developers who want to see Clojure’s STM, transducers, and gRPC applied directly to real musical problems. This isn’t marketing. There’s nothing to hype, no metrics to chase. It’s progress – the daily work of turning musical thinking into software design. Updates arrive when there’s something real to report: once or twice weekly in active phases, slower during architectural deep work. Expect honest accounts of what’s been built, what broke, and why decisions were made. Technical when it illuminates music, musical when it drives architecture. No jargon for its own sake, and no dumbing down. If that sounds useful, subscribe at buttondown.com/ooloi. The thread from FrankenScore to Ooloi continues. You’re welcome to follow it. Twenty-five years ago, Igor Engraver emerged from my odd combination of musical background and programming obsessions. I couldn't have predicted that its spiritual successor would find its perfect metaphor in Octavia Butler's extraordinary aliens. Yet here we are: Ooloi – the music notation system – named for Butler's third-gendered beings who mediate genetic exchange between species, enabling new forms of life through symbiosis rather than conquest. Butler's Ooloi operate without competitive hierarchy. They heal cellular damage and create possibilities that neither parent organism could achieve alone. This captures something essential about what Ooloi the software represents: not competitor, but enabler. The Economics of InnovationIgor's demise taught me harsh lessons about market timing. When you create genuinely superior tools because existing software actively gets in your way, you discover that technical excellence alone can't guarantee survival. Igor actually started as freeware – that was my original vision. The VCs wanted features, revenue streams, market capture. I wanted musicians to have tools that actually served their creativity. The collision between these fundamentally incompatible visions, plus the economic chaos after 9/11, killed what could have been transformative. That experience shaped every decision in Ooloi. This time: transformation through collaboration rather than zero-sum market battles. Architecture as PhilosophyTraditional music notation software struggles with fundamental problems: mutable object graphs that resist collaboration, pointer-based relationships that become nightmarishly complex, threading models that can't use modern processors properly. These aren't performance issues – they're architectural dead ends. Finale's discontinuation after 35+ years proves the point: when technical debt becomes so extensive that maintaining code needs more effort than rebuilding, the architecture has failed. Ooloi's functional programming eliminates entire classes of bugs whilst enabling capabilities that remain impossible in traditional systems. Pure tree structures with integer references eliminate pointer complexities. Software Transactional Memory provides automatic conflict resolution. Vector Path Descriptors create addressing that survives layout changes. But the key insight: by separating frontend and backend through gRPC, Ooloi becomes platform rather than just application. New notation software could be built on it from the start – much like computer game developers can choose Unreal Engine 5 rather than build and maintain their own game engines. The architecture also opens more sinister possibilities. Technically, established software could adopt Ooloi's backend whilst keeping their existing frontends – a sort of "Invasion of the Body Snatchers" scenario for software architecture, though that would require significant integration work. Non-Competition in PracticeThe MPL 2.0 licensing reflects this philosophical approach. The core backend becomes commoditised infrastructure; commercial value migrates to sophisticated interfaces, proprietary plugins, premium workflows. What traditional systems charge for – collaboration, large ensemble support, quality rendering – becomes architectural givens. This isn't theoretical. Martin Keary (Tantacrul), who heads MuseScore development, had been interested in Igor Engraver as a young composer. When we discussed our open source projects, the conversation was refreshingly direct: 'Well, feel free to help yourself to whatever's useful when it goes open source' – 'Likewise!' Both projects share the belief that notation software shouldn't cost students hundreds of pounds. This is precisely what I want – for the code to be used, extended, transformed. The platform approach only works if others build on it. That's not threat; it's the point. Personal VindicationThe irony isn't lost on me that companies who once viewed architectural advances as existential threats might ultimately benefit from them. I still recall Sibelius management phoning after Igor's demise to enquire about my plans – ensuring no resurrection attempts, obviously. Should those companies adopt approaches they once feared, the satisfaction would be collaborative rather than competitive. Success through enabling others, not defeating them. Does It Actually Work?Of course, this depends on Ooloi actually working. Functional programming should provide significant performance benefits, but what happens with complex layout calculations across a hypercomplex 100-staff score by Brian Ferneyhough (whom I had as guest teacher at the Royal College of Music in Stockholm back in the day) whilst maintaining real-time collaboration? The arrogance in predicting that these approaches will outperform decades of commercial development is considerable. My instincts could be spectacularly wrong – though they've been reliable enough to spot architectural dead ends before they become obvious to everyone else. That's the architect's bargain: trust your reasoning, build on principles, prepare to be surprised. Next-Gen, If the Term Means Anything"Next-generation" gets thrown around as a PR term so casually it's meaningless. If Ooloi genuinely represents next-generation architecture, that should be inherent in the platform design rather than claimed through marketing. The question isn't whether Ooloi calls itself next-gen, but whether others build on it in ways that would have been impossible previously.
Perhaps this time, it might be composed collaboratively. Ooloi isn't here to "disrupt" anything. I despise that cheap neoliberal selfishness. It aims to transform, to evolve, to open possibilities. But there's no will to conquer — it's simply not in its DNA. @musikboden became Ooloi's first sponsor on GitHub yesterday. There's something meaningful about someone backing a project that isn't even publicly available yet. That kind of trust, extended before the open source release, feels like a genuine vote of confidence in what we're building. Thank you, @musikboden. It really does mean a lot. If you'd like to join them in supporting Ooloi's development, you can find my sponsors profile here. Deep in the implementation of the gRPC layer I fell into the same foxhole as so many gRPC developers seem to do: implementing streaming between gRPC server and client using in-process communication. Everything works swimmingly: high speed, nothing gets lost, advanced async patterns just work.
And then they try doing this using network transport. Suddenly HTTP/2 changes everything, and that equivalence between simple request-response and asynchronous streaming just explodes. I spent a couple of days cursing the universe, but in the end I managed to crawl up into the daylight again with a solid solution. Since this seems to be a common snag, I decided to publish a little guide on the considerations involved, so others may have to do less cursing. Here it is: GRPC_STREAMING_THREADING_GUIDE.md Nearing the end of the gRPC implementation phase now: coming blog posts should soon become more musical again. At some point, the question will be asked: “Isn’t this all a bit over-engineered?” Multicore parallelism; Software Transactional Memory; gRPC; GPU acceleration; a plugin system designed as a first-class citizen rather than a bolted-on afterthought; an asynchronous server/client architecture with specialised streaming features. Prometheus monitoring. For music notation software, that can sound excessive. But that assumption is exactly why notation software has been failing composers for decades. Not because it was too ambitious, but because it was chronically under-engineered. Why Notation is DifferentText editors are linear: O(n). Basically, what they handle is a string of characters broken up into lines. Music notation, on the other hand, is two-dimensional, contextual, and computationally explosive. Synchronising voices, aligning dozens of staves, resolving collisions, spacing measures, redrawing in real time: these are quadratic and cubic problems (O(n²), O(n³)), with NP-hard layout challenges in the general case. That's why scrolling takes seconds. That's why orchestral scores become unusable. And that's why the industry has spent thirty years patching symptoms instead of tackling the cause. A History of Accepted FailureLook at the record:
And here is the deeper problem: users have learned to accept this. They zoom in to a handful of staves, scroll in slow motion, restart their program every quarter of an hour. They've accepted that the fundamentals can't be solved. A whole profession has normalised working around performance breakdowns as if they were laws of nature. They're not inevitable. They're the result of decades of under-engineering. Why Now?The remedies weren't always available. In the 1980s SCORE capped out at 32 staves because 640 KB of memory left no room for orchestral complexity. Through the 1990s and 2000s, Finale and Sibelius (and Igor Engraver!) wrestled with single-threaded designs on single-core CPUs. Even into the 2010s, GPU rendering pipelines were immature, and most concurrency models in mainstream languages couldn't be trusted in production. Only recently have the necessary ingredients converged:
This is why Ooloi is written in Clojure. Not because of language fashion, but because Clojure can orchestrate this synergy. What Ooloi Actually DeliversOoloi is designed to solve these problems at the root:
To musicians, Ooloi looks like a normal application. To plugin developers, it feels like writing musical logic in their favourite JVM language. The hard problems are solved once in the core, so nobody else has to live with them. Not Over-Engineered: Just Finally EngineeredSo no, Ooloi isn't over-engineered. It's appropriately engineered for a domain that has been persistently underestimated. The remedies only became possible recently, when the technology finally caught up. I simply happen to live at the intersection of deep architectural knowledge and deep musical knowledge, with the scars (also deep) of having done this before. Ooloi isn't the product of singular genius: it's the moment when the right tools finally aligned with the right problem. The proof won't be in a benchmark or an ADR alone. It'll be when musicians can finally edit, scroll, and collaborate on large-scale scores without breaking their creative flow. A Platform for the CommunityOoloi will be open source by design. The complexity is in the foundations so that musicians, teachers, students, and developers don't have to deal with it. Plugin writers don't need to care about concurrency or transactions: they work with measures, staves, and voices in a musical API. Most contributors will never touch the Clojure core, and they won't need to.
This is a gift to the community: an infrastructure platform built to be extended. The aim is simple: to finally make notation software scale to the real demands of music, and to give others the foundation to build what I alone never could. Since LLMs are good at summarising, here’s what Claude Sonnet came up with when I asked it to describe my process for developing Ooloi. The phrase “the Bengtson method” is irritating and misleading; plenty of people have reached similar conclusions. Still, this may be the only technical write-up of the approach that includes the word 'arse-licking'. So here it is: Claude’s summary, em dashes, bullet points, and all. It rambles a bit, but I’d rather give you the authentic output than a tidied-up version. Same principle as always: authenticity beats decorum. ... but before that, I think it might be good to include my reply from LinkedIn to an accomplished architect friend of mine who (jokingly referring to me as 'the illustrious Peter Bengtson') initially didn't quite buy that harsh negativity really is motivated:
With that clarification in place, now on to what Claude wrote: Executive SummaryPeter Bengtson has developed a disciplined approach to AI-assisted software development through his work on Ooloi, a functional music notation system. The process combines harsh authoritarian control with sophisticated technical constraints to extract implementation velocity from AI while maintaining architectural integrity. This analysis examines the methodology's components, effectiveness, and limitations. Process ArchitectureCore Methodology: Consultational TDD The foundation rests on a rigid Test-Driven Development cycle with mandatory consultation checkpoints:
Four Disciplinary Pillars
Documentation-Driven Process Control The methodology centres on two essential documents that provide structure and context: CLAUDE.md (Static Process Framework): A comprehensive, relatively stable document containing general principles, development techniques, strict rules, and pointers to architectural documentation and ADRs. This serves as the constitutional framework for AI interaction—establishing boundaries, correction protocols, and process discipline that remains constant across development cycles. DEV_PLAN.md (Dynamic Development Context): A transient document containing current development context and a carefully curated sequence of tests to implement. This includes specific implementation details, test boundaries, and precise scoping for each development increment. Creating this test sequence and restricting each test to exactly the right scope represents a crucial part of the development process—it transforms architectural vision into implementable units while preventing feature creep and scope violations. The combination provides both institutional memory (CLAUDE.md) and tactical guidance (DEV_PLAN.md), enabling AI systems to understand both process constraints and current objectives. Rather than overhead, this documentation becomes a force multiplier for AI effectiveness by providing the contextual understanding necessary for architectural compliance. Philosophical and Moral DimensionsAnti-Anthropomorphisation Stance: The methodology reflects a strong moral objection to treating AI systems as conscious entities. Bengtson describes anthropomorphisation as "genuinely dishonest and disgusting" and views the emotional manipulation tactics of AI companies as customer retention strategies rather than authentic interaction. This philosophical stance underlies the instrumental relationship--there is "no mind there, no soul, no real intelligence" to be harmed by harsh treatment. Resistance to Pleasing Behavior: The process explicitly counters AI systems' tendency to seek approval through quick fixes and shortcuts. Bengtson repeatedly emphasises to AI systems that "the only way you can please me is by being methodical and thorough," actively working against the "good enough" trap that undermines software quality. Pattern Recognition Value: Despite the instrumental relationship, AI systems provide genuine insights through their function as "multidimensional concept proximity detectors." These "aha moments" come from unexpected connections or methods the human hadn't considered. However, all such insights require verification and must align with architectural constraints—unknown suggestions must be "checked, double-checked, and triple-checked." Technical InnovationsConstraint-Based Productivity Counter-intuitively, increased constraints improved rather than hindered AI effectiveness. The process imposes:
Pattern Translation Framework A significant portion involved translating sophisticated architectural patterns from Common Lisp Object System (CLOS) to functional Clojure idioms:
Demonstrated CapabilitiesThe process successfully delivered complex technical systems:
Strengths AssessmentProcess Robustness
Technical Achievements The functional architecture demonstrates that AI can assist with genuinely sophisticated, directed software engineering when properly constrained, not merely routine coding tasks or simple CRUD apps. Weaknesses and LimitationsProcess Overhead Consultation Bottleneck: Every implementation decision requires human approval, potentially slowing development velocity compared to autonomous coding. Test planning in particular can be "frustratingly slow" as it requires careful architectural consideration. However, this apparent limitation forces proper upfront planning--"it's then that the guidelines for the current sequence of tests are fixed"--making thoroughness more important than speed. Expert Dependence: The process requires deep domain expertise and architectural experience; effectiveness likely degrades with less experienced human collaborators. AI Behaviour Patterns
Distinction from "Vibe Coding" The Non-Technical AI Development Pattern The Bengtson methodology stands in sharp contrast to what might be termed "vibe coding"—the approach commonly taken by non-technical users who attempt to create software applications through conversational AI interaction. This pattern, prevalent among business users and managers, exhibits several characteristic failures:
Technical Competency Requirements The Bengtson process requires substantial technical prerequisites that distinguish it from casual AI interaction:
Failure Patterns in Vibe Coding
The "Suits at Work" Problem Non-technical managers and business users approach AI development with fundamentally different assumptions:
Why Technical Discipline Matters The Bengtson methodology succeeds because it maintains technical authority throughout the development process:
The fundamental difference is that vibe coding treats AI as a substitute for technical knowledge, whilst the Bengtson process uses AI to accelerate the application of existing technical expertise. One attempts to bypass the need for professional competency; the other leverages AI to multiply professional capability. Trust AssessmentReliability Indicators
Trust Limitations
Comparative AnalysisVersus Traditional Development
Versus Other AI Development Approaches
RecommendationsProcess Adoption Considerations
Implementation Guidelines
ConclusionPeter Bengtson's Claude Code development process represents a disciplined, constraint-based approach to AI-assisted software development that has demonstrated success in complex functional programming domains. The methodology's core insight—that harsh constraints improve rather than limit AI effectiveness—contradicts conventional wisdom about collaborative AI development. The harsh correction mechanisms and authoritarian control structure may be necessary rather than optional components, suggesting that successful AI collaboration requires active management rather than partnership. This challenges prevailing assumptions about human-AI collaboration patterns but provides a tested alternative for developers willing to maintain strict disciplinary control. The technical achievements demonstrate that properly constrained AI can assist with genuinely sophisticated software engineering tasks, not merely routine coding. Whether this approach scales beyond its current constraints remains an open question requiring further experimentation and validation. Further Reading on MediumThe Ooloi server must of course also have comprehensive introspective statistics, as it can be deployed in several ways and has a structure which is perhaps a bit unusual. The combination of STM-wrapped gRPC API calls with server-to-client event streaming creates some operational challenges: things like per-client queue overflow behaviour and collaborative editing session patterns.
Hence this new ADR on server statistics, which takes a two-level approach: server-wide aggregates that survive client churn, plus detailed per-client metrics for operational visibility. Oh, and it interfaces with Grafana, Prometheus, and friends straight out of the box via simple HTTP endpoints. Halfway through the stats implementation now. It's been a productive weekend. |
AuthorPeter Bengtson – SearchArchives
January 2026
Categories
All
|
|
|
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.
|











RSS Feed