From April 23-26, 2026, the invite-only Perl Toolchain Summit (PTS) brought together about 30 of the ecosystem's most active maintainers including four first-timers in Vienna, Austria for four days of uninterrupted deep-dive collaboration in pair-programming sessions, consensus discussions, and critical infrastructure work. Attendees tackled security tooling and infrastructure, modernization and redesign proposals, several CI and test harness improvements, Perl core optimizations, and metadata/spec updates.Thanks to all the sponsors’ support (financial, in-kind, and community), this year’s Summit was a success. It produced multiple module releases, consensus on future smoke-testing and CPAN Testers architecture, and a new CPANSec advisory feed that will allow developers to quickly assess any Perl project’s security using either CLI tools or the MetaCPAN website itself. Those advancements benefit all organizations relying on Perl directly or indirectly.
PTS 2026 Key Results & Deliverables
Security
CPANSec took it to another level, getting faster at discovering vulnerabilities (in modules, infrastructure and core) and improving its process:
Vulnerability triage;
CNA improvements;
Meta V3 is moving forward;
Deprecated Module::Signature, considered “security theater”.
Recent years brought the topic of funding to the front of the stage. In particular to ensure the sustainability of Perl maintenance funds, accelerate some initiatives (e.g. CPAN Security efforts) and finance community events (like this one!).A lot of things happened on this front during the Perl Toolchain Summit:
A strong effort towards funding security work;
General discussions about funding of the community.
Group discussions
The Perl Toolchain Summit also provides a lot of opportunity for interaction.Whether they’re corridor discussions, small talk to get to know each other and build trust, discussions around a drink or group discussions (that led in the past to “consensus” or “amendment” papers), it all ends up strengthening the Perl toolchain.During this PTS in particular, there were a lot of group discussions, probably helped by having a dedicated meeting room.
On the topic of Toolchain
META V3
CPAN clients
On the topic of AI
AI Policies Materials
AI Policies Governance
Share your AI tooling and tips!
On the topic of Security
CRA presentation and Q&A
On the topic of Perl core
Perl Ongoing and future features
Perl core class/roles implementation
Configure
UTF-8
Plan for Perl Platforms
Podcasts
As in 2025, PTS 2026 was an opportunity to record new episodes for The Underbar.There were over five hours of conversations recorded, about:
Configure
Vienna.pm
PPI
the Perl Steering Council
Karl Williamson
Why Sponsor Support Matters
Bringing 30-35 experts under one roof enabled unprecedented collaboration with real-time problem solving, saving months of remote coordination and alignment. That kind of accelerated development and knowledge transfer not only brings the community together but fuels the contributors of critical open source projects for the rest of the year so they can renew their shared goals and work in the same direction. Having four first-time attendees gaining direct mentorship is also fundamental to seed future contributions and expand the volunteer base, ensuring the longevity of the Perl ecosystem and toolchain.The continued support of our sponsors ensures that the Perl Toolchain Summit remains a catalyst for Perl sustainability translating sponsor investment into tangible improvements in performance, security, and ecosystem features and coherence. We look forward to partnering again to power the next wave of innovation in Perl’s toolchain.
Let’s Make a Drum Machine application! Yeah! :DThere are basically two important things to handle: A MIDI “clock” and a groove to play.Why asynchronous? Well, a simple while (1) { Time::HiRes::sleep(); ... } will not do because the time between ticks will fluctuate, often dramatically. IO::Async::Timer::Periodic is a great timer for this purpose. Its default scheduler uses system time, so intervals happen as close to the correct real-world time as possible.
Clocks
A MIDI clock tells a MIDI device about the tempo. This can be handed to a drum machine or a sequencer. Each clock tick tells the device to advance a step of a measured interval. Usually this is very short, and is often 24 pulses per quarter-note (four quarter-notes to a measure of four beats).Here is code to do that, followed by an explanation of the parts:
#!/usr/bin/env perluse v5.36;use feature 'try';use IO::Async::Loop ();use IO::Async::Timer::Periodic ();use MIDI::RtMidi::FFI::Device ();my= shift ||'usb'; # MIDI sequencer devicemy= shift ||120; # beats per minutemy=60/ /24; # time / bpm / clocks-per-beat# open the named midi device for outputmy= RtMidiOut->new;try { # this will die on Windows but is needed for Mac->open_virtual_port('RtMidiOut');}catch ($e) {}->open_port_by_name(qr/\Q/i);->start; # start the sequencer{INT} =sub { # halt gracefully say "\nStop"; try {->stop; # stop the sequencer->panic; # make sure all notes are off } catch ($e) { warn "Can't halt the MIDI out device: $e\n"; } exit;};my= IO::Async::Loop->new;my= IO::Async::Timer::Periodic->new( interval => , on_tick =>sub { ->clock }, # send a clock tick!);->start;->add();->run;
The above code does a few things. First it uses modern Perl, then the modules that will make execution asynchronous, and finally the module that makes real-time MIDI possible.Next up, a variable is captured for a unique MIDI device. (And to see what the names of MIDI devices on the system are, use JBARRETT’s little list_devices script.) Also, the beats per minute is taken from the command-line. If neither is given, usb is used for the name, and the BPM is set to “dance tempo.”The clock needs a time interval to tick off. For us, this is a fraction of a second based on the beats per minute, and is assigned to the variable.To get the job done, we will need to open the named MIDI device for sending output messages to. This is done with the provided.In order to not just die when we want to stop, {INT} is redefined to gracefully halt. This also sends a stop message to the open MIDI device. This stops the sequencer from playing.Now for the meat and potatoes: The asynchronous loop and periodic timer. These tell the program to do its thing, in a non-blocking and event-driven manner. The periodic timer ticks off a clock message every . Pretty simple!As an example, here is the above code controlling my Volca Drum drum machine on a stock, funky groove. We invoke it on the command-line like this:
perl clock-gen-async.pl
Grooves
What we really want is to make our drum machine actually play something of our own making. So it’s refactor time… Let’s make a 4/4 time groove, with 16th-note resolution, that alternates between two different parts. “4/4” is a “time signature” in music jargon and means that there are four beats per measure (numerator), and a quarter note equals one beat (denominator). Other time signatures like the waltz’s 3/4 are simple, while odd meters like 7/8 are not.In order to generate syncopated patterns, Math::Prime::XS and Music::CreatingRhythms are added to the use statements. “What are syncopated patterns?”, you may ask. Good question! “Syncopated” means, “characterized by displaced beats.” That is, every beat does not happen evenly, at exactly the same time. Instead, some are displaced. For example, a repeated [1 1 1 1] is even and boring. But when it becomes a repeated [1 1 0 1] things get spicier and more syncopated.The desired MIDI channel is added to the command-line inputs. Most commonly, this will be channel 9 (in zero-based numbering). But some drum machines and sequencers are “multi-timbral” and use multiple channels simultaneously for individual sounds.Next we define the drums to use. This is a hash-reference that includes the MIDI patch number, the channel it’s on, and the pattern to play. The combined patterns of all the drums, when played together at tempo, make a groove.Now we compute intervals and friends. Previously, there was one . Now there are a whole host of measurements to make before sending MIDI messages.Then, as before, a named MIDI output device is opened, and a graceful stop is defined.Next, a Music::CreatingRhythms object is created. And then, again as before, an asynchronous loop and periodic timer are instantiated and set in motion.The meaty bits are in the timer’s on_tick callback. This contains all the logic needed to trigger our drum grooves.As was done in the previous clock code, a clock message is sent, but also we keep track of the number of clock ticks that have passed. This number of ticks is used to trigger the drums. We care about 16 beats. So every 16th beat, we construct and play a queue of events.Adjusting the drum patterns is where Math::Prime::XS and Music::CreatingRhythms come into play. The subroutine that does that is adjust_drums() and is fired every 4th measure. A measure is equal to four quarter-notes, and we use four pulses for each, to make 16 beats per measure. This routine reassigns either Euclidean or manual patterns of 16 beats to each drum pattern.Managing the queue is next. If a drum is to be played at the current beat (as tallied by the variable), it is added to the queue at full velocity (127). Then, after all the drums have been accounted for, the queue is played with ->note_on() messages. Lastly, the queue is “drained” by sending ->note_off() messages.
#!/usr/bin/env perluse v5.36;use feature 'try';use IO::Async::Loop ();use IO::Async::Timer::Periodic ();use Math::Prime::XS qw(primes);use MIDI::RtMidi::FFI::Device ();use Music::CreatingRhythms ();my= shift ||'usb'; # MIDI sequencer devicemy= shift ||120; # beats-per-minutemy= shift //9; # 0-15, 9=percussion, -1=multi-timbralmy= { kick => { num =>36, chan =><0 ? 0 : , pat =>[] }, snare => { num =>38, chan =><0 ? 1 : , pat =>[] }, hihat => { num =>42, chan =><0 ? 2 : , pat =>[] },};my=16; # beats in a measuremy=4; # divisions of a quarter-note into 16thsmy=24; # PPQNmy=60/ / ; # time / bpm / ppqnmy=/ ; # clocks per 16th-notemy %primes = ( # for computing the pattern all => [ primes() ], to_5 => [ primes(5) ], to_7 => [ primes(7) ],);my=0; # clock ticksmy=0; # how many beats?my=0; # part A or B?my @queue; # priority queue for note_on/off messages# open the named midi output devicemy= RtMidiOut->new;try { # this will die on Windows but is needed for Mac->open_virtual_port('RtMidiOut');}catch ($e) {}->open_port_by_name(qr/\Q/i);{INT} =sub { # halt gracefully say "\nStop"; try {->stop; # stop the sequencer->panic; # make sure all notes are off } catch ($e) { warn "Can't halt the MIDI out device: $e\n"; } exit;};# for computing the patternmy= Music::CreatingRhythms->new;my= IO::Async::Loop->new;my= IO::Async::Timer::Periodic->new( interval => , on_tick =>sub {->clock;++;if ( % $sixteenth ==0) {# adjust the drum pattern every 4th measureif ( % ($beats * ) ==0) { adjust_drums(, , \%primes, \); }# add simultaneous drums to the queueformy (keys %) {if (->{}{pat}[ % $beats ]) { push @queue, { drum => , velocity =>127 }; } }# play the queueformy (@queue) {->note_on(->{ ->{drum} }{chan},->{ ->{drum} }{num},->{velocity} ); }++; }else {# drain the queue with note_off messageswhile (my= pop @queue) {->note_off(->{ ->{drum} }{chan},->{ ->{drum} }{num},0 ); } @queue = (); # ensure the queue is empty } },);->start;->add();->run;subadjust_drums(, , , ) {# choose random primes to use by the hihat, kick, and snaremy ($p, $q, $r) = map { ->{$_}[ int rand ->{$_}->@*]} sort keys %;if ($ ==0) { say 'part A';->{hihat}{pat} =->euclid($p, );->{kick}{pat} =->euclid($q, );->{snare}{pat} =->rotate_n($r, ->euclid(2, )); $ =1; # set to part B }else { say 'part B';->{hihat}{pat} =->euclid($p, );->{kick}{pat} = [qw(1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1)];->{snare}{pat} = [qw(0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0)]; $ =0; # set to part A }}
(You may notice the inefficiency of attempting to drain an empty queue 23 times every 16th note. Oof! Fortunately, this doesn’t fire anything other than a single while loop condition. A more efficient solution would be to only drain the queue once, but this requires a bit more complexity that we won’t be adding, for brevity’s sake.)On Windows, this works fine:
perl clocked-euclidean-drums.pl "gs wavetable"90
To run with fluidsynth and hear the General MIDI percussion sounds, open a fresh new terminal session, and start up fluidsynth like so (mac syntax):
fluidsynth -a coreaudio -m coremidi -g 2.0 ~/Music/soundfont/FluidR3_GM.sf2
The FluidR3_GM.sf2 is a MIDI “soundfont” file and can be downloaded for free.Next, enter this on the command-line (back in the previous terminal session):
perl clocked-euclidean-drums.pl fluid 90
You will hear standard kick, snare, and closed hihat cymbal. And here is a poor recording of this with my phone:To run the code with my multi-timbral drum machine, I enter this on the command-line:
perl clocked-euclidean-drums.pl usb 90 -1
And here is what that sounds like:
The Module
I have coded this logic, and a bit more, into a friendly CPAN module. Check out the eg/euclidean.pl example program in the distribution. It is a work in progress. YMMV.
Credits
Thank you to Andrew Rodland (hobbs), who helped me wrap my head around the “no-sleeping asynchronous” algorithm.
To-do Challenges
Make patterns other than prime number based Euclidean phrases.
Let’s talk about music programming! There are a million aspects to this subject, but today, we’ll touch on generating rhythmic patterns with mathematical and combinatorial techniques. These include the generation of partitions, necklaces, and Euclidean patterns.Stefan and J. Richard Hollos wrote an excellent little book called “Creating Rhythms” that has been turned into C, Perl, and Python. It features a number of algorithms that produce or modify lists of numbers or bit-vectors (of ones and zeroes). These can be beat onsets (the ones) and rests (the zeroes) of a rhythm. We’ll check out these concepts with Perl.For each example, we’ll save the MIDI with the MIDI::Util module. Also, in order to actually hear the rhythms, we will need a MIDI synthesizer. For these illustrations, fluidsynth will work. Of course, any MIDI capable synth will do! I often control my eurorack analog synthesizer with code (and a MIDI interface module).Here’s how I start fluidsynth on my mac in the terminal, in a separate session. It uses a generic soundfont file (sf2) that can be downloaded here (124MB zip).
fluidsynth -a coreaudio -m coremidi -g 2.0 ~/Music/soundfont/FluidR3_GM.sf2
So, how does Perl know what output port to use? There are a few ways, but with JBARRETT’s MIDI::RtMidi::FFI::Device, you can do this:
use MIDI::RtMidi::FFI::Device ();my= RtMidiIn->new;my= RtMidiOut->new;print"Input devices:\n";->print_ports;print"\n";print"Output devices:\n";->print_ports;print"\n";
This shows that fluidsynth is alive and ready for interaction.Okay, on with the show!First-up, let’s look at partition algorithms. With the part() function, we can generate all partitions of n, where n is 5, and the “parts” all add up to 5. Then taking one of these (say, the third element), we convert it to a binary sequence that can be interpreted as a rhythmic phrase, and play it 4 times.
Not terribly exciting yet.Let’s see what the “compositions” of a number reveal. According to the Music::CreatingRhythms docs, a composition of a number is “the set of combinatorial variations of the partitions of n with the duplicates removed.”Okay. Well, the 7 partitions of 5 are:
That is, the list of compositions has, not only the partition [1, 2, 2], but also its variations: [2, 1, 2] and [2, 2, 1]. Same with the other partitions. Selections from this list will produce possibly cool rhythms.Here are the compositions of 5 turned into sequences, played by a snare drum, and written to the disk:
Here we play generated kick and snare patterns, along with a steady hi-hat.Next up, let’s look at rhythmic “necklaces.” Here we find many grooves of the world.Image from The Geometry of Musical RhythmRhythm necklaces are circular diagrams of equally spaced, connected nodes. A necklace is a lexicographical ordering with no rotational duplicates. For instance, the necklaces of 3 beats are [[1, 1, 1], [1, 1, 0], [1, 0, 0], [0, 0, 0]]. Notice that there is no [1, 0, 1] or [0, 1, 1]. Also, there are no rotated versions of [1, 0, 0], either.So, how many 16 beat rhythm necklaces are there?
my=->neck(16);print scalar @, "\n"; # 4116 of 'em!
Okay. Let’s generate necklaces of 8 instead, pull a random choice, and play the pattern with a percussion instrument.
Here we choose from all necklaces. But note that this also includes the sequence with all ones and the sequence with all zeroes. More sophisticated code might skip these.More interesting would be playing simultaneous beats.
And that sounds like:How about Euclidean patterns? What are they, and why are they named for a geometer?Euclidean patterns are a set number of positions P that are filled with a number of beats Q that is less than or equal to P. They are named for Euclid because they are generated by applying the “Euclidean algorithm,” which was originally designed to find the greatest common divisor (GCD) of two numbers, to distribute musical beats as evenly as possible.
Now we’re talkin’ - an actual drum groove! To reiterate, the euclid() method distributes a number of beats, like 2 or 11, over the number of beats, 16. The kick and snare use the same arguments, but the snare pattern is rotated by 4 beats, so that they alternate.
So what have we learned today?
That you can use mathematical functions to generate sequences to represent rhythmic patterns.
That you can play an entire sequence or simultaneous notes with MIDI.
2025 was a tough year for The Perl and Raku Foundation (TPRF). Funds were sorely needed. The community grants program had been paused due to budget constraints and we were in danger of needing to pause the Perl 5 core maintenance grants. Fastmail stepped up with a USD 10,000 donation and helped TPRF to continue to support Perl 5 core maintenance. Ricardo Signes explains why Fastmail helped keep this very important work on track.
Perl has served us quite well since Fastmail’s inception. We’ve built up a large code base that has continued to work, grow, and improve over twenty years. We’ve stuck with Perl because Perl stuck with us: it kept working and growing and improving, and very rarely did those improvements require us to stop the world and adapt to onerous changes. We know that kind of stability is, in part, a function of the developers of Perl, whose time is spent figuring out how to make Perl better without also making it worse. The money we give toward those efforts is well-spent, because it keeps the improvements coming and the language reliable. Ricardo Signes, Director & Chief Developer Experience Officer, Fastmail
One of the reasons that you don’t hear about Perl in the headlines is its reliability. Upgrading your Perl from one version to the next? That can be a very boring deployment. You code worked before and it continues to “just work” after the upgrade. You don’t need to rant about short deprecation cycles, performance degradation or dependencies which no longer install. The Perl 5 core maintainers take great care to ensure that you don’t have to care very much about upgrading your Perl. Backwards compatibility is top of mind. If your deployment is boring, it’s because a lot of care and attention has been given to this matter by the people who love Perl and love to work on it.As we moved to secure TPRF’s 2025 budget, we reached out to organizations which rely on Perl. A number of these companies immediately offered to help. Fastmail has already been a supporter of TPRF for quite some time. In addition to this much needed donation, Fastmail has been providing rock solid free email hosting to the foundation for many years.While Fastmail’s donation has been allocated towards Perl 5 Core maintenance, TPRF is now in the position to re-open the community grants program, funding it with USD 10,000 for 2026. There is also an opportunity to increase the community grants funding if sponsor participation increases. As we begin our 2026 fundraising, we are looking to cast a wider net and bring more sponsor organizations on board to help support healthy Perl and Raku ecosystems.Maybe your organization will be the one to help us double our community grants budget in 2026. To become a sponsor, contact:olaf@perlfoundation.org