sbox32_hash.h: Add #undef's These case statements need not be visible outside this header. Putting these here avoids cluttering up embed.h, where the same #undef lines would otherwise be generated
embed.pl: Remove no longer used sub
embed.pl: Also consider #undef's This code looks to see what conditions must apply before a #define happens. This commit extends that to also look for #undef commands. The end result is that for symbols that are visible to XS code, but aren't supposed to be, embed.h contains an #undef so it isn't visible. But if it already has been #undef'ed, there is no need to do this. But a symbol can be defined and undefined many times, and the conditions for doing an #undef may be different than what the symbol was #defined under. The consequences of not realizing that a symbol gets undefined are simply that we generate an unnecessary #undef. The consequences of failing to generate one when the symbol is defined is that it is visibile when not intended to be so. So, there are various restrictions to try to make sure that we don't err in the latter direction.
embed.pl: Consider symbols visible only to extensions Two commits ago, the code was extended to compare the C preprocessor visibility of a symbol with what the desired visibility of a symbol is. It assumed that everything not constrained to core was visible everywhere. This commit extends that to look for being visible only to extensions. As a result, the large number of symbols added to the override list in that commit are now removed.
embed.pl: Add cpp constraints for .h files Many of the header files in our source have guards that keep them from being recursively called, with a convention as to how their name is derived from the file name. This commit changes to now consider these when computing what a cpp conditional evaluates to. It follows the convention, except in those few places where it is violated, and sets up the infrastructure so that this mechanism could be applied for other cases. Since this commit was originally written, all but one header file has been changed to follow the convention, so after rebasing, only one line is now being added.
I just released version 5 of Venus, (vns (https://github.com/usevenus/vns) on GitHub), along with two companion repos:
- bye: (https://github.com/usevenus/bye) An introduction to Venus by example
- cfu: (https://github.com/usevenus/cfu) A set of Claude Code instructions for writing Perl using Venus ideas and primitives
Venus is opinionated but pragmatic. The goal has always been to give modern Perl 5 developers a cohesive set of modern primitives for data modeling, validation, error handling, roles, CLI tooling, and functional-style helpers, without abandoning Perl idioms or core sensibilities.
v5 is the largest release so far and includes both new features and some intentional breaking changes to clean up long-standing design constraints.
Highlights from v5.01:
- First class support for private instance data
- Thoroughly documented type system and parser, see Venus::Type (https://metacpan.org/pod/Venus::Type), Venus::Check (https://metacpan.org/pod/Venus::Check)
- New core utilities: Venus::Map (https://metacpan.org/pod/Venus::Map), Venus::Set (https://metacpan.org/pod/Venus::Set), Venus::Range (https://metacpan.org/pod/Venus::Range), Venus::Collect (https://metacpan.org/pod/Venus::Collect), Venus::Result (https://metacpan.org/pod/Venus::Result)
- Myriad ways to validate data, e.g., Venus::Data (https://metacpan.org/pod/Venus::Data), Venus::Validate (https://metacpan.org/pod/Venus::Validate), and Venus::Schema (https://metacpan.org/pod/Venus::Schema)
- Improved error and fault handling with Venus::Error (https://metacpan.org/pod/Venus::Error), Venus::Try (https://metacpan.org/pod/Venus::Try), and Resultable roles
- Keyword functions like gets (https://metacpan.org/pod/Venus#gets), sets (https://metacpan.org/pod/Venus#sets), mask (https://metacpan.org/pod/Venus#mask), kvargs (https://metacpan.org/pod/Venus#kvargs), unpack (https://metacpan.org/pod/Venus#unpack), and cli (https://metacpan.org/pod/Venus#cli)
- Refactored container and factory model (i.e., dependency injection)
- Method modifiers, lifecycle hooks, coercion-by-type, and richer role composition
- A much more capable CLI framework with routing, dispatching, and spec-driven configuration
- Better configuration handling, including support for .env files and multiline environment variables
- Significant internal refactors to simplify extension and documentation
- Overhauled test framework with more features, automation, and POD generation
This project is very much for people who still like Perl, want stronger structure, and prefer libraries that help you model intent rather than just shuffle data.
Feedback, criticism, and questions are all welcome. If nothing else, I hope it sparks some interesting discussion about what "modern Perl" can look like today.
I'm getting
503 hostname doesn't match against certificate
Which makes the website look more like wall.org
[link] [comments]
I've released a new version of SBOM::CycloneDX with support for the OWASP CycloneDX 1.7 specification (ECMA-424).
This release includes the new elements introduced in 1.7, with a focus on:
- Enhancements to Cryptography Bill of Materials (CBOM)
- Citations: references and sources for evidence/metadata
- Intellectual Property Transparency: references to associated patents (number, jurisdiction, link, assignee) for compliance / due diligence needs
New experimental "SBOM::CycloneDX::Lite" interface: A lightweight module designed to generate BOMs with a simpler API, using the most common CycloneDX properties.
Examples included in the distribution (use them as a starting point to build your own applications/tools that generate BOM files): - "x509-to-cbom" : generates a CBOM from an X.509 certificate - "rpm-to-sbom" : generates a SBOM from installed RPM packages (on RHEL-based)
The goal of this module is to help the Perl community generate BOM files more easily, improving security and compliance across the ecosystem and making the software supply chain more transparent.
SBOM::CycloneDX is available on CPAN / MetaCPAN: https://metacpan.org/pod/SBOM::CycloneDX
Related projects: - App::CPAN::SBOM - https://metacpan.org/dist/App-CPAN-SBOM - Modules::CoreList::SBOM - https://github.com/giterlizzi/perl-Module-CoreList-SBOM
(cross-posted from my blog)
Last Monday I did the Perl Developer Release of Perl 5.43.7. As usual, I worked from the Release Managers Guide . Everything worked well, even if everything was cutting it a bit close. My video setup on the desktop was not suited for streaming anymore, so I had to do a stream consisting only of the console window and me talking over it, and no floating head of me available.
What worked well
The Twitch chat was the most active that I witnessed when streaming a Perl release. We chatted about organizing Perl conferences and also the Perl release process. One realization for me was that the RMG process is mostly there to exercise the Perl build machinery and testing that the generated tarball does not have deficiencies. This means that testing that Perl can build through Configure is important, but testing different Perl configurations like ithreads or userelocatableinc is not that important.
The dashboard for tracking my progress through the release worked well up to the release. I had modified it in the weeks leading up to the release to not only show the human step description but also to show the command line steps that should be undertaken, where applicable. I see this as a first step in automating these steps where possible and sensible.
What didn't work out
The dashboard can use some improvements:
The script did not cope well with the events after the release when the repo version number was bumped from 5.43.7 to 5.43.8. This part needs to be investigated but is easy to replicate by simply launching the dashboard with a version number before the current version number.
The script could highlight the current position in the sequence better. For console output this would likely mean inverting the line where the next applicable step is, but this means moving the output from
Text::Tableto a custom table generation or post-patching the string fromText::Tablewith the appropriate console commands.The script should generate HTML and terminal output at the same time. Having output visible in a browser feels less retro but makes things like publishing the progress elsewhere easier.
The script should have a feature to simply output the next step. This could be integrated into the shell prompt to give a guided message in the console window. Maybe the console output and the HTML output should be done as files when in "interactive" mode?
Improvements to the Perl Release Process
More parallelism - the current release manager guide uses
make testin many places. This runs the test suite in serial mode, which takes on my machine about 10 minutes. Running the test suite in parallel takes about 4-5 minutes. This is implemented using themake test_harnesscommand. Whether Perl should move the default of parallel testing tomake testfrommake test_harnessis debatable. Most likely everybody who cares about speed already runs the test suite in parallel.Remove sequences of shell commands - comparing the file names between the previous and current Perl version is done using a sequence of shell commands involving
sort,diff`. I have a patch that adds a small tool to do that within Perl (mostly powered by Algorithm::Diff ).
I’ve built mojoeye, a tiny Perl app to run system and security checks across our internal Linux hosts:
It’s built for environments where time, attention, and continuity are scarce. Checks are plain Perl scripts, the server is a single-file Mojolicious::Lite web app, and each host runs a small single-file client that reports back. There’s a short tutorial that gets someone productive in about 30 minutes.
Thank you, Mojolicious!
MIT licensed; currently tested on Debian- and Fedora-like systems.
— Gwyn

I just released version 5 of Venus, (vns on GitHub), along with two companion repos:
- bye: An introduction to Venus by example
- cfu: A set of Claude Code instructions for writing Perl using Venus ideas and primitives
Venus is opinionated but pragmatic. The goal has always been to give modern Perl 5 developers a cohesive set of modern primitives for data modeling, validation, error handling, roles, CLI tooling, and functional-style helpers, without abandoning Perl idioms or core sensibilities.
v5 is the largest release so far and includes both new features and some intentional breaking changes to clean up long-standing design constraints.
Highlights from v5.01:
- First class support for private instance data
- Thoroughly documented type system and parser, see Venus::Type, Venus::Check
- New core utilities: Venus::Map, Venus::Set, Venus::Range, Venus::Collect, Venus::Result
- Myriad ways to validate data, e.g., Venus::Data, Venus::Validate, and Venus::Schema
- Improved error and fault handling with Venus::Error, Venus::Try, and Resultable roles
- Keyword functions like gets, sets, mask, kvargs, unpack, and cli
- Refactored container and factory model (i.e., dependency injection)
- Method modifiers, lifecycle hooks, coercion-by-type, and richer role composition
- A much more capable CLI framework with routing, dispatching, and spec-driven configuration
- Better configuration handling, including support for .env files and multiline environment variables
- Significant internal refactors to simplify extension and documentation
- Overhauled test framework with more features, automation, and POD generation
This project is very much for people who still like Perl, want stronger structure, and prefer libraries that help you model intent rather than just shuffle data.
Feedback, criticism, and questions are all welcome. If nothing else, I hope it sparks some interesting discussion about what "modern Perl" can look like today.
[link] [comments]
I was on the schedule for 2025, but by swapping the release version, I skipped doing a release in 2025. This year, I'm doing the dev release live stream again on Twitch, for version 5.43.7.
And again, you can watch it live on Monday 19th of January on Twitch.
You can expect to watch me talk through the steps of the Perl Release Managers Guide and if you join the Twitch chat, or
p5p on irc.perl.org, we can chat a bit.
I assume I'll start Monday at 16:00 UTC (17:00 CET), and the whole thing will take around 4 hours unless there are some major mishaps. In the middle, I'll join a call of the organizers of the German Perl Workshop 2026 in Berlin, where we will likely go through organizing the social event and the pre-conference meeting.
All of us were present.
- We discussed the recent p5p thread about the proposed
class :abstractattribute. Paul wants to write that because it’s a simple addition on current code and avoids design complications about roles. Aristotle doesn’t wish to introduce a new special-purpose feature now that will become redundant when a more general one is available later and wondered whether it can be introduced as roles that currently only support a small subset of features. No call has been made. - The
classdiscussions also extended to looking at themetamodule and API, and the common idea between the two that it would be useful to get more people to use them and discuss future ideas. We would like people to step forward here. - We have PR #24059 to implement the retraction of the deprecation of being able to call undefined import methods (and the reinstatement of a default-enabled warning for that case), thanks to haarg. We are keen to get it merged so we will provide feedback soon.
- The maint-votes process came up. We pondered whether we can conceive of something less obscure and will post to the list about this.
Weekly Challenge 357
Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding.
Task 1: Kaprekar Constant
Task
Write a function that takes a 4-digit integer and returns how many iterations are required to reach Kaprekar's constant (6174).
My solution
This is where GitHub Copilot really scars me somewhat. Without mentioning "kaprekar" at all, and after typing while number != 6174: it auto-completed the rest of the code.
For this solution, I start by checking that the number is between 1 and 9999, and that it is not divisible by 1111. If any of these are false, I return -1.
I create a variable called count, starting at 0. If number is not 6174, I take the following steps
- Set
digitsto be the individual digits, left padded with zeros if needed. - Set
asc_digitsto the abovedigitslist, sorted numerically (lowest first). Setdesc_digitsto the same, but in reversed sorted order. - Set
small_numto the integer that concatenatesasc_digits. - Set
large_numto the integer that concatenatesdesc_digits. - Set number to be
large_numminussmall_num. - If this is not 6174, repeat the loop again.
def kaprekar_constant(number: int) -> int:
if not 0 < number < 10000:
return -1
if number % 1111 == 0:
return -1
count = 0
while number != 6174:
digits = [int(d) for d in str(number).zfill(4)]
asc_digits = sorted(digits)
desc_digits = sorted(digits, reverse=True)
small_num = int(''.join(map(str, asc_digits)))
large_num = int(''.join(map(str, desc_digits)))
number = large_num - small_num
count += 1
return count
The Perl solution is a little shorter, as I don't need to worry about finicky things like converting integers to strings :P
sub main ($int) {
if ($int < 1 or $int > 9999 or $int % 1111 == 0) {
say -1;
return;
}
my $count = 0;
while ($int != 6174) {
my $small_number = join("", sort { $a <=> $b } (split //, sprintf("%04d", $int)));
my $big_number = reverse($small_number);
$int = $big_number - $small_number;
$count++
}
say $count;
}
Examples
$ ./ch-1.py 3524
3
$ ./ch-1.py 6174
0
$ ./ch-1.py 9998
5
$ ./ch-1.py 1001
4
$ ./ch-1.py 9000
4
$ ./ch-1.py 1111
-1
Task 2: Unique Fraction Generator
Task
Given a positive integer n, generate all unique fractions you can create using integers from 1 to n and follow the rules below:
- Use numbers
1throughnonly (no zero) - Create fractions like numerator/denominator
- List them in ascending order (from smallest to largest)
- If two fractions have the same value (like
1/2and2/4), only show the one with the smallest numerator
My solution
Python has the fractions module as standard, while Perl has a CPAN module called Numbers::Fraction.
Both exhibit the same behaviors:
- Takes the numerator (top part) and denominator (bottom part) as input variables
- Will automatically convert to have the lowest unique values. For example,
Fraction(2, 4)automatically isFraction(1, 2). - Annoyingly for this task, will print a whole number if the denominator is 1.
- Two fractions variables can be compared to be sorted correctly (by the number they represent). For example
¼ < ½.
With that in mind, this task involves having a double loop for n and d (both from 1 to number), removing the duplicates with the set function, and then sorting them numerically. Finally, I turn the Fraction object into strings, and return the list.
def unique_fraction_generator(number: int) -> list[str]:
fractions = sorted(set(
Fraction(n,d)
for d in range(1, number + 1)
for n in range(1, number+1)
))
return [f"{frac.numerator}/{frac.denominator}" for frac in fractions]
The Perl solution follows the same logic. It uses grep to check if a fraction is added previously, and pushes it to the fractions array if it is not.
use Number::Fraction;
sub main ($int) {
my @fractions = ();
foreach my $n (1 .. $int) {
foreach my $d (1 .. $int) {
my $fraction = Number::Fraction->new($n, $d);
push @fractions, $fraction if not grep { $_ == $fraction} @fractions;
}
}
my @sorted_fractions = sort { $a <=> $b } @fractions;
say join(", ", map({ "$_->{num}/$_->{den}" } @sorted_fractions));
}
Examples
$ ./ch-2.py 3
1/3, 1/2, 2/3, 1/1, 3/2, 2/1, 3/1
$ ./ch-2.py 4
1/4, 1/3, 1/2, 2/3, 3/4, 1/1, 4/3, 3/2, 2/1, 3/1, 4/1
$ ./ch-2.py 1
1/1
$ ./ch-2.py 6
1/6, 1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 5/6, 1/1, 6/5, 5/4, 4/3, 3/2, 5/3, 2/1, 5/2, 3/1, 4/1, 5/1, 6/1
$ ./ch-2.py 5
1/5, 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 1/1, 5/4, 4/3, 3/2, 5/3, 2/1, 5/2, 3/1, 4/1, 5/1
Originally published at Perl Weekly 756
Hi there,
Perl continues to show remarkable momentum in early 2026, with Dean highlighting the language's improved position in the TIOBE Index, signaling renewed attention and ongoing relevance. This renewed visibility is supported by active development and innovative tooling, from Toby Inkster's performance-boosting Moose extensions to William McLean's demonstration of deploying Perl MCP servers on Cloud Run.
Community and ecosystem engagement remain strong, as seen with CosmoShop sponsoring the German Perl Workshop and the launch of the Thunderhorse web framework beta, offering modern features like WebSockets and SSE. Open-source contributions continue to thrive, exemplified by Corion's 2025 module releases and Robert Acock's work on practical data structures, helping developers build efficient, real-world applications.
The Perl community also places emphasis on knowledge-sharing and accessibility. Dave Cross's slide archives provide a wealth of training resources, while the Perl Ad Server enables easy promotion of community events, jobs, and podcasts, strengthening connections across the ecosystem.
Finally, discussions within the Perl Steering Council, such as those on experimental features like refaliasing and declared_refs, demonstrate ongoing efforts to evolve the language responsibly. Alongside a growing focus on transparency and sustainability, as highlighted in Makoto Nozaki's financial analysis of TPRF, these developments show a community that balances innovation, support, and stewardship.
Stay positive and healthy, enjoy rest of the newsletter.
--
Your editor: Mohammad Sajid Anwar.
Announcements
This week in PSC (211) | 2026-01-12
We mostly discussed the experimental refaliasing and declared_refs features to see if we can find a path towards declaring at least the latter non-experimental.
Cosmoshop supports the German Perl Workshop 2026
Max Maischein announces that CosmoShop, one of the world’s largest pure‑Perl shop systems, is once again sponsoring the German Perl Workshop in 2026, strengthening community support for this key Perl/Raku conference. This continued backing highlights the vibrant ecosystem and industry engagement around Perl events.
Thunderhorse Beta released!
The blog announces the beta release of Thunderhorse, a new Perl web framework drawing on lessons from Kelp and built natively on PAGI, with real‑time features like WebSocket and SSE support and a focus on extensibility and high code quality.
Slide archive: Learn with Dave Cross
Dave Cross has published an archive of slides from his long‑running technical training courses on Perl and other developer topics, going back many years and available for free download. These slide decks offer a valuable resource for anyone wanting concise, well‑structured material from experienced instruction.
The corner of Gabor
A couple of entries sneaked in by Gabor.
Perl code reading and open source contribution
One of the best ways to learn is by reading other people's code, making small contributions and getting feedback. That's exactly what we do at these online sessions. The next one taking place on January 24 in a Zoom near you. Join us!
Articles
What I released in 2025
In his year‑in‑review post, Corion reflects on a productive 2025 by highlighting several useful Perl modules he published, including Text::HTML::Turndown for converting HTML to Markdown and Date::Find for extracting dates from filenames. He also shares a paranoid Mojo::UserAgent extension and contributions to core modules, giving readers insight into both his releases and ongoing development work.
How can we make this Moose faster?
Toby Inkster introduces performance‑boosting extensions to Moose with MooseX::XSAccessor and the new MooseX::XSConstructor, showing significant speedups in object creation and method access. His benchmarks suggest up to ~76 % faster performance using XS‑based accessors and constructors, offering a practical way to accelerate Moose‑based Perl code.
Understanding TPRF's Finance, 2026 Edition
Makoto Nozaki takes a clear, numbers‑driven look at The Perl and Raku Foundation’s 2024 financials, showing a significant increase in revenue but expenses that far exceeded income and halved its assets. His breakdown highlights both positive trends in donations and a strong call for greater transparency to ensure the foundation’s long‑term sustainability.
Taking the Win - Perl in the TIOBE Index
Dean celebrates Perl’s improved position in the TIOBE Index during 2025 and highlights the ongoing momentum in the Perl community, from steady releases to vibrant events and tooling support. While acknowledging healthy skepticism about popularity metrics, he encourages readers to "take the win" and appreciate the positive signals for Perl’s ecosystem.
Firestore MCP Development with Perl, Cloud Run, and Gemini CLI
William McLean walks through building a minimal Perl‑based MCP (Model Context Protocol) server backed by Firestore, showing how to validate it locally and deploy it to Google Cloud Run using the Gemini CLI. The article highlights practical steps for integrating Perl with modern AI‑oriented workflows beyond the usual Python ecosystem and gives clear pointers for developers looking to experiment with MCP and Cloud Run deployments.
Doubly: Why Arrays Aren't Always Enough
Robert explores when traditional arrays fall short and makes a compelling case for using doubly linked lists instead, especially for operations like O(1) insertions and intuitive cursor navigation. Through Perl examples and performance trade‑offs across multiple implementations, from pure Perl to thread‑safe C registries, the article highlights practical data‑structure choices and when they pay off.
Perl Ad Server
The Perl Ad Server makes it easy to promote Perl‑related announcements, from events and podcasts to jobs and newsletters, by embedding a tiny JavaScript snippet that displays rotating banners on your website. It’s simple to style and control, and contributions are welcomed via GitHub for anyone who wants to add or manage ads for the community.
Grants
Maintaining Perl 5 Core (Dave Mitchell): December 2025
Maintaining Perl (Tony Cook) December 2025
PEVANS Core Perl 5: Grant Report for December 2025
The Weekly Challenge
The Weekly Challenge by Mohammad Sajid Anwar will help you step out of your comfort-zone. You can even win prize money of $50 by participating in the weekly challenge. We pick one champion at the end of the month from among all of the contributors during the month, thanks to the sponsor Lance Wicks.
The Weekly Challenge - 357
Welcome to a new week with a couple of fun tasks "Kaprekar Constant" and "Unique Fraction Generator". If you are new to the weekly challenge then why not join us and have fun every week. For more information, please read the FAQ.
RECAP - The Weekly Challenge - 356
Enjoy a quick recap of last week's contributions by Team PWC dealing with the "Kolakoski Sequence" and "Who Wins" tasks in Perl and Raku. You will find plenty of solutions to keep you busy.
Kolakoski Wins
The article clearly demonstrates a thoughtful Raku solution to generating the Kolakoski sequence and counting 1s, leveraging Raku’s gather/take constructs for elegant lazy sequence generation. The examples and code comments make the approach easy to understand.
Perl Weekly Challenge: Week 356
The post delivers a technically clear explanation of both the Kolakoski Sequence and Who Wins tasks with illustrative examples and thoughtful insight into simplifying the problem logic—showcasing an effective balance between correctness and practical Perl coding. The walkthroughs help demystify the challenge specifications and offer useful implementation perspectives for Perl developers.
Self-Generating Games
The post delivers clear, well-structured solutions to both tasks, especially with its concise explanation of generating the Kolakoski sequence and counting elements. The breakdowns and examples make the logic easy to follow and practically useful for coding challenges.
Perl Weekly Challenge 356
The post showcases concise and effective Perl implementations for both the Kolakoski‑Sequence and Who‑Wins tasks, with a compact self‑referential sequence generator and a structured playoff progression model. The code is thoughtfully organised and demonstrates practical mastery of sequence construction and game logic within Perl’s syntax.
Kolakoski called, he wants his sequence back(!)
The post offers a thoughtful, well-commented Perl exploration of the Kolakoski sequence that breaks down the generation logic with clear analogies and illustrative code, making the algorithm approachable even for those new to the concept. Its lively explanation paired with working examples enhances understanding and practical problem-solving.
Who’s Kolakoski?
The write-up presents a thoughtful multilingual exploration of the Kolakoski challenge with clear logic and practical code that demonstrates command over sequence generation and problem constraints, making it both accessible and instructive. Packy’s commentary and stepwise approach enhance readability and offer valuable insights for anyone tackling the Weekly Challenge tasks.
Sequence and consequence
The post provides a clear, well-reasoned implementation of both tasks, with the Kolakoski solution closely following the Wikipedia algorithm and demonstrating impressive performance at scale. The NFL playoff logic is neatly modeled with concise Perl code, showing careful handling of seeding, sorting, and edge cases in a readable and maintainable way.
The Weekly Challenge #356
The post offers clear, well-structured Perl solutions for both the Kolakoski sequence and "Who Wins" tasks, closely following the problem definitions with readable logic and solid use of Perl idioms. The explanations make the algorithms accessible while the included references help ground the implementation in established techniques.
Kolakoski Wins
The post presents elegant and thoughtfully implemented solutions to both tasks, with the Kolakoski sequence logic clearly articulated and efficiently expressed in Raku. The playoff "Who Wins" solution demonstrates solid handling of round progression and seed logic, showcasing clean algorithm design and practical Rust usage.
Winning sequence
The write-up delivers concise and effective Python solutions for both the Kolakoski Sequence and Who Wins tasks, with a clever analytical shortcut for the sequence count and a clean stepwise modeling of the playoff progression. The inclusion of examples and clear logic makes the implementations easy to follow and practically useful.
Rakudo
2026.02 Resolutions
Weekly collections
NICEPERL's lists
Great CPAN modules released last week;
MetaCPAN weekly report.
Events
Perl Maven online: Live Open Source contribution
January 24, 2025
Boston.pm - online
February 10, 2025
German Perl/Raku Workshop 2026 in Berlin
March 16-18, 2025
You joined the Perl Weekly to get weekly e-mails about the Perl programming language and related topics.
Want to see more? See the archives of all the issues.
Not yet subscribed to the newsletter? Join us free of charge!
(C) Copyright Gabor Szabo
The articles are copyright the respective authors.
Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in Perl with Google Cloud Run.
Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in Perl with Google Cloud Run.
Why not just use Python?
Python has traditionally been the main coding language for ML and AI tools. One of the strengths of the MCP protocol is that the actual implementation details are independent of the development language. The reality is that not every project is coded in Python- and MCP allows you to use the latest AI approaches with other coding languages.
Perl? Is that even a language anymore?
The goal of this article is to provide a minimal viable basic working MCP server in Perl that can be run locally without any unneeded extra code or extensions.
The Perl MCP module is here:
What Is Perl?
Perl is a general-purpose, high-level programming and scripting language, primarily known for its powerful text manipulation capabilities. Originally created by Larry Wall in 1987 for easier report processing, it has evolved to be used for a wide range of tasks, including system administration, web development, and network programming.
The main site for Perl is :
The Perl Programming Language - www.perl.org
Installing Perl
The step by step instructions vary by platform- for a basic Debian system here are the steps:
sudo apt-get install perl cpanminus
xbill@penguin:~/gemini-cli-codeassist/firstore-https-perl$ perl --version
This is perl 5, version 36, subversion 0 (v5.36.0) built for x86_64-linux-gnu-thread-multi
(with 60 registered patches, see perl -V for more detail)
Gemini CLI
If not pre-installed you can download the Gemini CLI to interact with the source files and provide real-time assistance:
npm install -g @google/gemini-cli
Testing the Gemini CLI Environment
Once you have all the tools and the correct Node.js version in place- you can test the startup of Gemini CLI. You will need to authenticate with a Key or your Google Account:
gemini
Node Version Management
Gemini CLI needs a consistent, up to date version of Node. The nvm command can be used to get a standard Node environment:
Perl MCP Documentation
The official MCP CPAN page provides samples and documentation for getting started:
Where do I start?
The strategy for starting MCP development is a incremental step by step approach.
First, the basic development environment is setup with the required system variables, and a working Gemini CLI configuration.
Then, a minimal Hello World Style Perl MCP Server is built with HTTP transport. This server is validated with Gemini CLI in the local environment.
This setup validates the connection from Gemini CLI to the local process via MCP. The MCP client (Gemini CLI) and the MCP server both run in the same local environment.
Next- the basic MCP server is extended with Gemini CLI to add several new tools in standard code.
Setup the Basic Environment
At this point you should have a working Perl environment and a working Gemini CLI installation. The next step is to clone the GitHub samples repository with support scripts:
cd ~
git clone https://github.com/xbill9/gemini-cli-codeassist
Then run init.sh from the cloned directory.
The script will attempt to determine your shell environment and set the correct variables:
cd gemini-cli-codeassist
source init.sh
If your session times out or you need to re-authenticate- you can run the set_env.sh script to reset your environment variables:
cd gemini-cli-codeassist
source set_env.sh
Variables like PROJECT_ID need to be setup for use in the various build scripts- so the set_env script can be used to reset the environment if you time-out.
Hello World with HTTP Transport
One of the key features that the standard MCP libraries provide is abstracting various transport methods.
The high level MCP tool implementation is the same no matter what low level transport channel/method that the MCP Client uses to connect to a MCP Server.
The simplest transport that the SDK supports is the stdio (stdio/stdout) transport — which connects a locally running process. Both the MCP client and MCP Server must be running in the same environment.
The HTTP MCP transport allows the client and server to be on the same machine or distributed over the Internet.
The connection over HTTP will look similar to this:
# Use HTTP transport via Mojolicious
any '/mcp' => $server->to_action;
Perl Package Information
The Perl code depends on several standard libraries for MCP and logging:
requires 'Mojolicious::Lite';
requires 'MCP::Server';
requires 'JSON::MaybeXS';
requires 'WWW::Google::Cloud::Auth::ServiceAccount';
requires 'URI::Encode';
requires 'LWP::Protocol::https';
Installing and Running the Perl Code
Run the install make release target on the local system:
xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl$ make
Installing dependencies...
--> Working on .
Configuring /home/xbill/gemini-cli-codeassist/firestore-https-perl ... OK
<== Installed dependencies for .. Finishing.
Running tests...
t/00_compile.t ................... ok
t/01_firestore_client_compile.t .. ok
All tests successful.
Files=2, Tests=2, 0 wallclock secs ( 0.01 usr 0.01 sys + 0.34 cusr 0.05 csys = 0.41 CPU)
Result: PASS
To test the code:
xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl$ make test
Running tests...
t/00_compile.t .. ok
All tests successful.
Files=1, Tests=1, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.19 cusr 0.05 csys = 0.26 CPU)
Result: PASS
Gemini CLI settings.json
In this example — the Perl source code uses a Perl interpreter that can be called directly from Gemini CLI.
The default Gemini CLI settings.json has an entry for the source:
{
"mcpServers": {
"firebase-https-perl": {
"httpUrl": "http://127.0.0.1:8080/mcp"
}
}
}
Start the Local Server
Open a new terminal to run the local MCP Perl server :
xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl$ make run
Running the application...
{"asctime":"2026-01-12T22:10:06.21872Z","levelname":"INFO","message":"Initializing Firestore for project: comglitn","name":"root"}
{"asctime":"2026-01-12T22:10:06.2188Z","levelname":"INFO","message":"Firestore initialized successfully","name":"root"}
{"asctime":"2026-01-12T22:10:06.21881Z","levelname":"INFO","message":"Starting MCP server","name":"root"}
{"asctime":"2026-01-12T22:10:06.22059Z","levelname":"INFO","message":"Listening at \"http://0.0.0.0:8080\"","name":"root"}
Web application available at http://0.0.0.0:8080
Validation with Gemini CLI
Leave the local server running and open a new Terminal window. Gemini CLI is used to validate the MCP connection over HTTP to the Perl Code:
> /mcp list
Configured MCP servers:
🟢 firebase-https-perl - Ready (8 tools)
Tools:
- add_product
- batch_delete
- delete_product
- find_products
- get_product
- greet
- list_products
- update_product
> find_products Coffee
✦ I will search for products matching "Coffee".
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ? find_products (firebase-https-perl MCP Server) {"name":"Coffee"} ← │
│ │
│ MCP Server: firebase-https-perl │
│ Tool: find_products │
│ │
│ Allow execution of MCP tool "find_products" from server "firebase-https-perl"? │
│ │
│ 1. Allow once │
│ 2. Allow tool for this session │
│ ● 3. Allow all server tools for this session │
│ 4. No, suggest changes (esc) │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I will search for "Coffee Beans" specifically, as it exists in the inventory.
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ find_products (firebase-https-perl MCP Server) {"name":"Coffee Beans"} │
│ │
│ {"products":[{"actualdateadded":"2026-01-07T16:53:00.672Z","id":"37kWbZHTwg5nbrSD13PB","imgfile":"product-images\/coffeebeans. │
│ png","name":"Coffee Beans","price":6,"quantity":375,"timestamp":"2024-11-30T08:40:02.515Z"}]} │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I found the product you were looking for: Coffee Beans (ID: 37kWbZHTwg5nbrSD13PB). It is priced at $6 and there are 375 in
stock.
Deploying to Cloud Run
After the HTTP version of the MCP server has been tested locally — it can be deployed remotely to Google Cloud Run.
First- switch to the directory with the HTTP MCP sample code:
cd ~/gemini-cli-codeassist/firestore-https-perl
Deploy the project to Google Cloud Run with the pre-built cloudbuild.yaml and Dockerfile:
cd ~/gemini-cli-codeassist/firestore-https-perl
xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl$ make deploy
The Cloud Build will start:
> make deploy
✦ I will read the Makefile to understand the deployment process and then execute make deploy.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ ReadFile Makefile │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I will read cloudbuild.yaml to verify the build configuration.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ ReadFile cloudbuild.yaml │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I will execute make deploy to submit the build to Google Cloud Build.
✦ I will execute make deploy to submit the build to Google Cloud Build and deploy the application.
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ⊶ Shell make deploy [current working directory /home/xbill/gemini-cli-codeassist/firestore-https-perl] (Submit build to Goog… │
│ │
│ Step #0: 7703c2863431: Pulling fs layer │
│ Step #0: d4d869c8f88d: Pulling fs layer │
│ Step #0: 8b22c905be5d: Pulling fs layer │
│ Step #0: 8b22c905be5d: Waiting │
│ Step #0: 7703c2863431: Download complete │
│ Step #0: 8b22c905be5d: Verifying Checksum │
│ Step #0: 8b22c905be5d: Download complete │
│ Step #0: d4d869c8f88d: Verifying Checksum │
│ Step #0: d4d869c8f88d: Download complete │
│ Step #0: 7bbf972c6c2f: Verifying Checksum │
│ Step #0: 7bbf972c6c2f: Download complete │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
It can take 15–30 minutes to complete the build.
The cloud build needs to pull in all Perl libraries in the build environment and generate the entire package from scratch.
When the build is complete- an endpoint will be returned:
│ Starting Step #2 │
│ Step #2: Already have image (with digest): gcr.io/cloud-builders/gcloud │
│ Step #2: Deploying container to Cloud Run service [firestore-https-perl] in project [comglitn] region [us-central1] │
│ Step #2: Deploying... │
│ Step #2: Setting IAM Policy.........done │
│ Step #2: Creating │
│ Revision...................................................................................................................... │
│ .............................................................................................................................. │
│ .................done │
│ Step #2: Routing traffic.....done │
│ Step #2: Done. │
│ Step #2: Service [firestore-https-perl] revision [firestore-https-perl-00002-v5g] has been deployed and is serving 100 percent │
│ of traffic. │
│ Step #2: Service URL: https://firestore-https-perl-1056842563084.us-central1.run.app │
│ Finished Step #2 │
│ PUSH │
│ Pushing gcr.io/comglitn/firestore-https-perl:latest │
│ The push refers to repository [gcr.io/comglitn/firestore-https-perl] │
The service endpoint in this example is :
https://firestore-https-perl-1056842563084.us-central1.run.app
The actual endpoint will vary based on your project settings.
Review Service in Cloud Run
Navigate to the Google Cloud console and search for Cloud Run -
and then you can detailed information on the Cloud Run Service:
Cloud Logging
The remote server writes logs to stderr in standard JSON format. These logs are available from the deployed Cloud Run Service:
Validate HTTP connection
Once you have the Endpoint — you can attempt a connection- navigate to in your browser:
https://firestore-https-perl-1056842563084.us-central1.run.app
You will need to adjust the exact URL to match the URL returned from Cloud Build.
You will get an error- this connection is expecting a message in the MCP format:
Not Found
Gemini CLI settings.json.cloudrun
Replace the default Gemini CLI configuration file — settings.json with a pre-configured sample- settings.json.cloudrun to use the Cloud Run version of the connection:
{
"mcpServers": {
"firestore-cloudrun-perl": {
"httpUrl": "https://firestore-https-perl-$PROJECT_NUMBER.us-central1.run.app/mcp"
}
}
}
Copy the Cloud Run version of the Gemini CLI configuration file:
xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl$ cd .gemini
cp settings.json.cloudrun settings.json
xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl/.gemini$
Validation with Gemini CLI
The final connection test uses Gemini CLI as a MCP client with the deployed Cloud Run Service in Perl providing the MCP server. Startup Gemini CLI with the updated settings :
gemini
> /mcp list
Configured MCP servers:
🟢 firestore-cloudrun-perl - Ready (8 tools)
Tools:
- add_product
- batch_delete
- delete_product
- find_products
- get_product
- greet
- list_products
- update_product
✦ I have retrieved the list of products from the inventory. There are currently 34 products available, ranging from fresh produce
like Apples and Bananas to pantry staples like Rice and Coffee Beans. Some items, such as Wasabi Party Mix and Jalapeno
Seasoning, are currently out of stock.
> how can I generate the most revenue from my inventory?
✦ Based on your current inventory, here is a breakdown of how to maximize revenue:
Top Revenue Drivers (High Price × High Volume)
These products currently hold the most value in your inventory. Prioritize selling these to unlock the most cash flow.
1. Whole Wheat Bread ($3,280 potential) — High price ($10) and good stock.
2. Pineapple Kombucha ($3,216 potential) — Premium price ($8) with high volume.
3. Green Tea ($2,844 potential) — Mid-range price ($6) but very high quantity.
4. Beef ($2,380 potential) — High price ($10) item.
5. Maple Almond Butter ($2,355 potential).
Strategic Opportunities
* Restock Alerts:
* Wasabi Party Mix and Jalapeno Seasoning are completely out of stock ($0 revenue).
* Walnuts (2 left) and Smores Cereal (23 left) are running low. Walnuts are a higher-price item ($7), so missing sales here
is a lost opportunity.
* Volume Movers (High Quantity / Low Price):
* Eggs (496 units @ $1) and Black Beans (486 units @ $3) are abundant. Consider bundling these or running "buy one get one"
promotions to clear space and generate liquidity.
* Premium Items:
* Cola and Whole Chicken are priced at $10. Even small increases in sales volume for these items will significantly impact
your bottom line.
Summary
MCP development with Perl using Gemini CLI was validated with an incremental step by step approach.
A minimal streaming HTTP transport MCP Server was built from source code and validated with Gemini CLI running as a MCP client in the same local environment.
Then — the MCP server was wrapped in a container and submitted to Google Cloud Build for deployment to Google Cloud Run. The remote MCP server was validated with a standard browser, and Gemini CLI.
Finally- remote MCP operations were performed from the local Gemini CLI installation to the Perl MCP server hosted in Google Cloud Run.
This approach can be extended to more complex deployments and Cloud based options.
-
CPANSA::DB - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
- Version: 20260110.003 on 2026-01-11, with 25 votes
- Previous CPAN version: 20260104.001 was 6 days before
- Author: BRIANDFOY
-
FFI::Platypus - Write Perl bindings to non-Perl libraries with FFI. No XS required.
- Version: 2.11 on 2026-01-12, with 69 votes
- Previous CPAN version: 2.10 was 1 year, 24 days before
- Author: PLICEASE
-
Firefox::Marionette - Automate the Firefox browser with the Marionette protocol
- Version: 1.70 on 2026-01-11, with 18 votes
- Previous CPAN version: 1.69 was before
- Author: DDICK
-
Module::Starter - a simple starter kit for any module
- Version: 1.82 on 2026-01-10, with 34 votes
- Previous CPAN version: 1.81 was before
- Author: XSAWYERX
-
Net::DNS - Perl Interface to the Domain Name System
- Version: 1.54 on 2026-01-16, with 29 votes
- Previous CPAN version: 1.53 was 4 months, 18 days before
- Author: NLNETLABS
-
Net::SSH::Perl - Perl client Interface to SSH
- Version: 2.144 on 2026-01-14, with 20 votes
- Previous CPAN version: 2.143 was 1 year, 10 days before
- Author: BRIANDFOY
-
Sidef - The Sidef Programming Language - A modern, high-level programming language
- Version: 26.01 on 2026-01-13, with 121 votes
- Previous CPAN version: 25.12 was 23 days before
- Author: TRIZEN
-
Sys::Virt - libvirt Perl API
- Version: v12.0.0 on 2026-01-16, with 17 votes
- Previous CPAN version: v11.10.0 was 1 month, 14 days before
- Author: DANBERR
-
utf8::all - turn on Unicode - all of it
- Version: 0.025 on 2026-01-16, with 30 votes
- Previous CPAN version: 0.024 was 8 years, 11 days before
- Author: HAYOBAAN
This is the weekly favourites list of CPAN distributions. Votes count: 89
Week's winner: Marlin (+6)
Build date: 2026/01/18 10:13:31 GMT
Clicked for first time:
- Acme::KMX::Test - Testing package
- App::DAVThis - Export the current directory over WebDAV
- App::FTPThis - Export the current directory over anonymous FTP
- App::HTTPSThis - Export the current directory over HTTPS
- App::sshca - Minimalistic SSH Certificate Authority
- App::Transpierce - backup and modify important files
- CLI::Cmdline - A minimal command-line parser with short and long options in pure Perl
- DBIx::Class::Async - Asynchronous database operations for DBIx::Class
- i18n - Perl Internationalization Pragma
- Mooish::AttributeBuilder - build Mooish attribute definitions with less boilerplate
- MooseX::XSConstructor - glue between Moose and Class::XSConstructor
- Net::Async::Redis - Redis support for IO::Async
- PAGI::Server -
- PostScript::Simple - Produce PostScript files from Perl
- Strada - Call compiled Strada shared libraries from Perl
- Term::ProgressSpinner - Terminal Progress bars!
Increasing its reputation:
- Acme::AsciiEmoji (+1=2)
- App::CGIThis (+1=5)
- App::HTTPThis (+1=25)
- Beam::Wire (+1=19)
- Cache::Cache (+1=4)
- Carton (+1=130)
- Class::DBI (+1=10)
- Command::Runner (+1=4)
- CPAN::Meta (+1=28)
- CryptX (+1=53)
- DBD::CSV (+1=26)
- DBD::DuckDB (+1=8)
- DBD::SQLite (+1=107)
- DBIx::Class (+1=293)
- Devel::NYTProf (+1=196)
- Email::Stuffer (+1=37)
- EV (+1=50)
- ExtUtils::Depends (+1=5)
- FFI::Platypus (+1=70)
- forks (+1=23)
- Future::AsyncAwait (+1=51)
- Future::XS (+1=3)
- GDGraph (+1=8)
- Graphics::Framebuffer (+1=6)
- IO::Async (+1=80)
- IO::K8s (+1=5)
- JQ::Lite (+2=8)
- kura (+1=2)
- List::Gen (+1=25)
- Log::Any (+1=69)
- Log::Handler (+1=10)
- Marlin (+6=6)
- Melian (+2=4)
- MIME::Base64 (+1=25)
- Module::CPANfile (+1=62)
- Module::Runtime (+1=31)
- Module::Starter (+1=34)
- Mojolicious (+1=510)
- Mojolicious::Plugin::HTMX (+1=6)
- Mojolicious::Plugin::OpenAPI (+1=47)
- Moose (+1=334)
- MooX::Singleton (+1=6)
- Net::Prober (+1=4)
- Object::Pad (+1=47)
- PAGI (+2=4)
- PDL::Opt::GLPK (+1=2)
- perl (+1=441)
- Perl::Types (+1=3)
- perlsecret (+1=55)
- Plack (+1=240)
- Prima (+1=46)
- Protocol::Sys::Virt (+1=2)
- Pry (+1=24)
- Statocles (+1=31)
- Storable (+1=57)
- strictures (+1=26)
- Sub::Quote (+1=12)
- Test::Perl::Critic (+1=16)
- Thread::Subs (+1=3)
- Tickit (+2=29)
- Type::Tiny (+3=148)
- Z (+1=3)
I have the following program with JSON:
use strict;
use warnings;
use Data::Dumper qw( );
use JSON qw( );
my $json_text = '[
{
"sent": "2026-01-16T17:00:00Z",
"data": [
{
"headline": "text1",
"displayText": "text2"
},
{
"displayText": "text3"
},
{
"displayText": "text4"
}
]
},
{
"sent": "2026-01-16T17:00:00Z",
"data": [
{
"headline": "text5",
"displayText": "text6"
},
{
"displayText": "text7"
},
{
"displayText": "text8"
},
{
"headline": "text9",
"displayText": "text10"
}
]
}
]';
my $json = JSON->new;
my $data = $json->decode($json_text);
print Data::Dumper->Dump($data);
# This is pseudocode:
foreach ( $data->[] ) {
print "\$_ is $_";
}
I would like to walk through elements in JSON and find all sent and all displayText values. But, I do not know how to dereference first element. First element is array without any name in this case.
Thunderhorse framework was just released as beta. Read more about it on my blog: https://bbrtj.eu/blog/article/thunderhorse-beta-released
Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in Perl with a local development…
Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in Perl with Google Cloud Run.

Dave writes:
During December, I fixed assorted bugs, and started work on another tranche of ExtUtils::ParseXS fixups, this time focussing on:
adding and rewording warning and error messages, and adding new tests for them;
improving test coverage: all XS keywords have tests now;
reorganising the test infrastructure: deleting obsolete test files, renaming the t/*.t files to a more consistent format; splitting a large test file; modernising tests;
refactoring and improving the length(str) pseudo-parameter implementation.
By the end of this report period, that work was about half finished; it is currently finished and being reviewed.
Summary:
* 10:25 GH #16197 re eval stack unwinding
* 1:39 GH #23903 BBC: bleadperl breaks ETHER/Package-Stash-XS-0.30.tar.gz
* 0:09 GH #23986 Perl_rpp_popfree_to(SV sp**) questionable design
* 3:02 fix Pod::Html stderr noise
* 27:47 improve Extutils::ParseXS
* 1:47 modernise perlxs.pod
Total: * 44:49 (HH::MM)

Tony writes:
``` [Hours] [Activity] 2025/12/01 Monday 0.23 memEQ cast discussion with khw 0.42 #23965 testing, review and comment 2.03 #23885 review, testing, comments 0.08 #23970 review and approve 0.13 #23971 review and approve
0.08 #23965 follow-up
2.97
2025/12/02 Tuesday 0.73 #23969 research and comment 0.30 #23974 review and approve 0.87 #23975 review and comment 0.38 #23975 review reply and approve 0.25 #23976 review, research and approve 0.43 #23977 review, research and approve
1.20 #23918 try to produce expected bug and succeed
4.16
2025/12/03 Wednesday 0.35 #23883 check updates and approve with comment 0.72 #23979 review, try to trigger the messages and approve 0.33 #23968 review, research and approve 0.25 #23961 review and comment 2.42 #23918 fix handling of context, testing, push to update,
comment on overload handling plans, start on it
4.07
2025/12/04 Thursday 2.05 #23980 review, comment and approve, fix group_end() decorator and make PR 23983 0.25 #23982 review, research and approve 1.30 #23918 test for skipping numeric overload, and fix, start
on force overload
3.60
2025/12/05 Friday
0.63 #23980 comment
0.63
2025/12/08 Monday 0.90 #23984 review and comment 0.13 #23988 review and comment 2.03 #23918 work on force overload implmentation
1.45 #23918 testing, docs
4.51
2025/12/09 Tuesday 0.32 github notifications 1.23 #23918 add more tests 0.30 #23992 review 0.47 #23993 research, testing and comment
0.58 #23993 review and comment
2.90
2025/12/10 Wednesday 0.72 #23992 review updates, testing and comment 1.22 #23782 review (and some #23885 discussion in irc) 1.35 look into Jim’s freebsd core dump, reproduce and find cause, email him and briefly comment in irc, more 23885
discussion and approve 23885
3.29
2025/12/11 Thursday 0.33 #23997 comment 1.08 #23995 research and comment 0.47 #23998 review and approve
1.15 #23918 cleanup
3.03
2025/11/15 Saturday 0.20 #23998 review updates and approve 0.53 #23975 review comment, research and follow-up 1.25 #24002 review discussion, debugging and comment 0.28 #23993 comment 0.67 #23918 commit cleanup 0.20 #24002 follow-up
0.65 #23975 research and follow-up
3.78
2025/12/16 Tuesday 0.40 #23997 review, comment, approve 0.37 #23988 review and comment 0.95 #24001 debugging and comment 0.27 #24006 review and comment 0.23 #24004 review and nothing to say
1.27 #23918 more cleanup, documentation
3.49
2025/12/17 Wednesday 0.32 #24008 testing, debugging and comment 0.08 #24006 review update and approve 0.60 #23795 quick re-check and approve 1.02 #23918 more fixes, address each PR comment and push for CI 0.75 #23956 work on a test and a fix, push for CI 0.93 #24001 write a test, and a fix, testing 0.67 #24001 write an inverted test too, commit message and push for CI 0.17 #23956 perldelta 0.08 #23956 check CI results, make PR 24010
0.15 #24001 perldelta and make PR 24011
4.77
2025/12/18 Thursday 0.27 #24001 rebase, local testing, push for CI 1.15 #24012 research 0.50 #23995 testing and comment
0.08 #24001 check CI results and apply to blead
2.00
Which I calculate is 43.2 hours.
Approximately 32 tickets were reviewed or worked on, and 1 patches were applied. ```

Paul writes:
A mix of focus this month. I was hoping to get attributes-v2 towards
something that could be reviewed and merged, but then I bumped into a
bunch of refalias-related issues. Also spent about 5 hours reviewing
Dave's giant xspod rewrite.
- 1 = Rename
THINGtoken in grammar to something more meaningful- https://github.com/Perl/perl5/pull/23982
- 4 = Continue work on
attributes-v2 - 1 = BBC Ticket on Feature-Compat-Class
- https://github.com/Perl/perl5/issues/23991
- 2 = Experiment with
refaliasparameters with defaults in XS-Parse-Sublike - 1 = Managing the PPC documents and overall process
- 2 = Investigations into the
refaliasanddeclared_refsfeatures, to see if we can un-experiment them - 2 = Add a warning to
refaliasthat breaks closures- https://github.com/Perl/perl5/pull/24026 (work-in-progress)
- 3 = Restore refaliased variables after foreach loop
- https://github.com/Perl/perl5/issues/24028
- https://github.com/Perl/perl5/pull/24029
- 3 = Clear pad after multivariable foreach
- https://github.com/Perl/perl5/pull/24034 (not yet merged)
- 6 = Github code reviews (mostly on Dave's xspod)
- https://github.com/Perl/perl5/pull/23795
Total: 25 hours
Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in Perl with a local development…
-
App::Greple - extensible grep with lexical expression and region handling
- Version: 10.02 on 2026-01-09, with 56 votes
- Previous CPAN version: 10.01 was 9 days before
- Author: UTASHIRO
-
App::Netdisco - An open source web-based network management tool.
- Version: 2.097002 on 2026-01-09, with 818 votes
- Previous CPAN version: 2.097001
- Author: OLIVER
-
App::Sqitch - Sensible database change management
- Version: v1.6.1 on 2026-01-06, with 3087 votes
- Previous CPAN version: v1.6.0 was 3 months before
- Author: DWHEELER
-
CPANSA::DB - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
- Version: 20260104.001 on 2026-01-04, with 25 votes
- Previous CPAN version: 20251228.001 was 6 days before
- Author: BRIANDFOY
-
DateTime::Format::Natural - Parse informal natural language date/time strings
- Version: 1.23 on 2026-01-04, with 19 votes
- Previous CPAN version: 1.23 was 5 days before
- Author: SCHUBIGER
-
Firefox::Marionette - Automate the Firefox browser with the Marionette protocol
- Version: 1.69 on 2026-01-10, with 19 votes
- Previous CPAN version: 1.68 was 3 months, 26 days before
- Author: DDICK
-
GD - Perl interface to the libgd graphics library
- Version: 2.84 on 2026-01-04, with 32 votes
- Previous CPAN version: 2.83 was 1 year, 6 months, 11 days before
- Author: RURBAN
-
IO::Socket::SSL - Nearly transparent SSL encapsulation for IO::Socket::INET.
- Version: 2.098 on 2026-01-06, with 49 votes
- Previous CPAN version: 2.097
- Author: SULLR
-
JSON::Schema::Modern - Validate data against a schema using a JSON Schema
- Version: 0.632 on 2026-01-06, with 16 votes
- Previous CPAN version: 0.631 was 12 days before
- Author: ETHER
-
MetaCPAN::Client - A comprehensive, DWIM-featured client to the MetaCPAN API
- Version: 2.037000 on 2026-01-07, with 27 votes
- Previous CPAN version: 2.036000
- Author: MICKEY
-
MIME::Lite - low-calorie MIME generator
- Version: 3.035 on 2026-01-08, with 35 votes
- Previous CPAN version: 3.034 was 2 days before
- Author: RJBS
-
Module::Starter - a simple starter kit for any module
- Version: 1.81 on 2026-01-09, with 34 votes
- Previous CPAN version: 1.80
- Author: XSAWYERX
-
Perl::Tidy - indent and reformat perl scripts
- Version: 20260109 on 2026-01-08, with 147 votes
- Previous CPAN version: 20250912 was 3 months, 26 days before
- Author: SHANCOCK
-
perlsecret - Perl secret operators and constants
- Version: 1.018 on 2026-01-09, with 55 votes
- Previous CPAN version: 1.017 was 4 years, 2 months before
- Author: BOOK
-
Type::Tiny - tiny, yet Moo(se)-compatible type constraint
- Version: 2.010001 on 2026-01-06, with 148 votes
- Previous CPAN version: 2.010000 was 7 days before
- Author: TOBYINK
-
UV - Perl interface to libuv
- Version: 2.001 on 2026-01-06, with 14 votes
- Previous CPAN version: 2.000 was 4 years, 5 months, 8 days before
- Author: PEVANS
In a script I'm using constants (use constant ...) to allow re-use ion actual regular expressions, using the pattern from https://stackoverflow.com/a/69379743/6607497.
However when using a {...} repeat specifier following such constant expansion, Perl wants to tread the constant as a hash variable.
The question is how to avoid that.
Code example:
main::(-e:1): 1
DB<1> use constant CHARSET => '[[:graph:]]'
DB<2> x "foo" =~ qr/^[[:graph:]]{3,}$/
0 1
DB<3> x "foo" =~ qr/^${\CHARSET}{3,}$/
Not a HASH reference at (eval 8)[/usr/lib/perl5/5.26.1/perl5db.pl:738] line 2.
DB<4> x "foo" =~ qr/^${\CHARSET}\{3,}$/
empty array
DB<5> x $^V
0 v5.26.1
According to https://stackoverflow.com/a/79845011/6607497 a solution may be to add a space that's being ignored, like this: qr/^${\CHARSET} {3,}$/x; however I don't understand why this works, because outside of a regular expression the space before { is being ignored:
DB<6> x "foo" =~ qr/^${\CHARSET} {3,}$/x
0 1
DB<7> %h = (a => 3)
DB<8> x $h{a}
0 3
DB<9> x $h {a}
0 3
The manual page (perlop(1) on "Quote and Quote-like Operators") isn't very precise on that:
For constructs that do interpolate, variables beginning with "$" or "@" are interpolated. Subscripted variables such as $a[3] or "$href->{key}[0]" are also interpolated, as are array and hash slices. But method calls such as "$obj->meth" are not.
foobar is a Perl script that prints to both standard output and standard error. In a separate Perl script echo-stderr, I run foobar and capture its standard error using IPC::Open3's open3 function, and simply echo it back.
Here's the code for echo-stderr:
#!/usr/bin/perl -w
use IPC::Open3;
use Symbol 'gensym';
$fh = gensym;
$pid = open3('STDIN', 'STDOUT', $fh, './foobar') or die "$0: failed to run ./foobar\n";
while ( <$fh> ) {
print STDERR $_;
}
close $fh;
waitpid($pid, 0);
The result is that whatever foobar writes to standard error is printed, nothing that it writes to standard output is.
And there is an error at the end:
<message written to STDERR>
<message written to STDERR>
...
Unable to flush stdout: Bad file descriptor
What is the reason for this error?
Version Control SVN
Whenever I’m building a static website, I almost never start by reaching for Apache, nginx, Docker, or anything that feels like “proper infrastructure”. Nine times out of ten I just want a directory served over HTTP so I can click around, test routes, check assets, and see what happens in a real browser.
For that job, I’ve been using App::HTTPThis for years.
It’s a simple local web server you run from the command line. Point it at a directory, and it serves it. That’s it. No vhosts. No config bureaucracy. No “why is this module not enabled”. Just: run a command and you’ve got a website.
Why I’ve used it for years
Static sites are deceptively simple… right up until they aren’t.
-
You want to check that relative links behave the way you think they do.
-
You want to confirm your CSS and images are loading with the paths you expect.
-
You want to reproduce “real HTTP” behaviour (caching headers, MIME types, directory handling) rather than viewing files directly from disk.
Sure, you can open file:///.../index.html in a browser, but that’s not the same thing as serving it over HTTP. And setting up Apache (or friends) feels like bringing a cement mixer to butter some toast.
With http_this, the workflow is basically:
-
cdinto your site directory -
run a single command
-
open a URL
-
get on with your life
It’s the “tiny screwdriver” that’s always on my desk.
Why I took it over
A couple of years ago, the original maintainer had (entirely reasonably!) become too busy elsewhere and the distribution wasn’t getting attention. That happens. Open source is like that.
But I was using App::HTTPThis regularly, and I had one small-but-annoying itch: when you visited a directory URL, it would always show a directory listing – even if that directory contained an index.html. So instead of behaving like a typical web server (serve index.html by default), it treated index.html as just another file you had to click.
That’s exactly the sort of thing you notice when you’re using a tool every day, and it was irritating enough that I volunteered to take over maintenance.
(If you want to read more on this story, I wrote a couple of blog posts.)
What I’ve done since taking it over
Most of the changes are about making the “serve a directory” experience smoother, without turning it into a kitchen-sink web server.
1) Serve index pages by default (autoindex)
The first change was to make directory URLs behave like you’d expect: if index.html exists, serve it automatically. If it doesn’t, you still get a directory listing.
2) Prettier index pages
Once autoindex was in place, I then turned my attention to the fallback directory listing page. If there isn’t an index.html, you still need a useful listing — but it doesn’t have to look like it fell out of 1998. So I cleaned up the listing output and made it a bit nicer to read when you do end up browsing raw directories.
3) A config file
Once you’ve used a tool for a while, you start to realise you run it the same way most of the time.
A config file lets you keep your common preferences in one place instead of re-typing options. It keeps the “one command” feel, but gives you repeatability when you want it.
4) --host option
The ability to control the host binding sounds like an edge case until it isn’t.
Sometimes you want:
-
only
localhostaccess for safety; -
access from other devices on your network (phone/tablet testing);
-
behaviour that matches a particular environment.
A --host option gives you that control without adding complexity to the default case.
The Bonjour feature (and what it’s for)
This is the part I only really appreciated recently: App::HTTPThis can advertise itself on your local network using mDNS / DNS-SD – commonly called Bonjour on Apple platforms, Avahi on Linux, and various other names depending on who you’re talking to.
It’s switched on with the --name option.
When you do that, http_this publishes an _http._tcp service on your local network with the instance name you chose (MyService in this case). Any device on the same network that understands mDNS/DNS-SD can then discover it and resolve it to an address and port, without you having to tell anyone, “go to http://192.168.1.23:7007/”.
Confession time: I ignored this feature for ages because I’d mentally filed it under “Apple-only magic” (Bonjour! very shiny! probably proprietary!). It turns out it’s not Apple-only at all; it’s a set of standard networking technologies that are supported on pretty much everything, just under a frankly ridiculous number of different names. So: not Apple magic, just local-network service discovery with a branding problem.
Because I’d never really used it, I finally sat down and tested it properly after someone emailed me about it last week, and it worked nicely, nicely enough that I’ve now added a BONJOUR.md file to the repo with a practical explanation of what’s going on, how to enable it, and a few ways to browse/discover the advertised service.
(If you’re curious, look for _http._tcp and your chosen service name.)
It’s a neat quality-of-life feature if you’re doing cross-device testing or helping someone else on the same network reach what you’re running.
Related tools in the same family
App::HTTPThis is part of a little ecosystem of “run a thing here quickly” command-line apps. If you like the shape of http_this, you might also want to look at these siblings:
-
https_this : like
http_this, but served over HTTPS (useful when you need to test secure contexts, service workers, APIs that require HTTPS, etc.) -
cgi_this : for quick CGI-style testing without setting up a full web server stack
-
dav_this : serves content over WebDAV (handy for testing clients or workflows that expect DAV)
-
ftp_this : quick FTP server for those rare-but-real moments when you need one
They all share the same basic philosophy: remove the friction between “I have a directory” and “I want to interact with it like a service”.
Wrapping up
I like tools that do one job, do it well, and get out of the way. App::HTTPThis has been that tool for me for years and it’s been fun (and useful) to nudge it forward as a maintainer.
If you’re doing any kind of static site work — docs sites, little prototypes, generated output, local previews — it’s worth keeping in your toolbox.
And if you’ve got ideas, bug reports, or platform notes (especially around Bonjour/Avahi weirdness), I’m always happy to hear them.
The post App::HTTPThis: the tiny web server I keep reaching for first appeared on Perl Hacks.
-
App::cpm - a fast CPAN module installer
- Version: 0.998003 on 2025-12-29, with 177 votes
- Previous CPAN version: 0.998002 was 24 days before
- Author: SKAJI
-
App::Greple - extensible grep with lexical expression and region handling
- Version: 10.01 on 2025-12-31, with 56 votes
- Previous CPAN version: 10.00 was 19 days before
- Author: UTASHIRO
-
App::Music::ChordPro - A lyrics and chords formatting program
- Version: v6.090.1 on 2026-01-03, with 432 votes
- Previous CPAN version: v6.090.0 was 2 months, 3 days before
- Author: JV
-
CPANSA::DB - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
- Version: 20251228.001 on 2025-12-29, with 25 votes
- Previous CPAN version: 20251221.001 was 7 days before
- Author: BRIANDFOY
-
DBD::SQLite - Self Contained SQLite RDBMS in a DBI Driver
- Version: 1.78 on 2026-01-02, with 107 votes
- Previous CPAN version: 1.76 was 1 year, 2 months, 14 days before
- Author: ISHIGAKI
-
Module::Starter - a simple starter kit for any module
- Version: 1.79 on 2026-01-03, with 33 votes
- Previous CPAN version: 1.78 was 7 months, 30 days before
- Author: XSAWYERX
-
Type::Tiny - tiny, yet Moo(se)-compatible type constraint
- Version: 2.010000 on 2025-12-30, with 148 votes
- Previous CPAN version: 2.009_003 was 7 days before
- Author: TOBYINK
-
WebService::Dropbox - Perl interface to Dropbox API
- Version: 2.10 on 2025-12-29, with 12 votes
- Previous CPAN version: 2.09 was 4 years, 6 months, 14 days before
- Author: ASKADNA
In an attempt to avoid switch /x for a complex regular expression, I tried to replace qr/string/ with the following expression:
(map { qr/$_/ } ("a more" . "complex regex"))[0]
As the latter expression uses double quoted strings, I thought I would have to duplicate any backslash that should go into the qr operator. Because of that, I tried something like this:
(map { qr/$_/ } (
"^Load key \"\\Q$host_CA\\E\": "
. 'incorrect passphrase supplied '
. "to decrypt private key$CRLF"
))
However, Perl 5.26 complains with the following error message:
Unrecognized escape \Q passed through in regex; marked by <-- HERE in m/^Load key "\Q <-- HERE ...
It seems I don't have to duplicate the backslash, but I don't understand why. The following examples illustrate the behavior I am seeing:
DB<3> $x='f*o'
DB<4> x qr/\Q$x\E/
0 (?^u:f\\*o)
-> qr/(?^u:f\*o)/
DB<5> x map { qr/$_/ } ("\\Q$x\\E/")
0 (?^u:\\Qf*o\\E/)
-> qr/(?^u:\Qf*o\E\/)/
DB<6> x map { qr/$_/ } ("\Q$x\E/")
0 (?^u:f\\*o/)
-> qr/(?^u:f\*o\/)/
-
App::DBBrowser - Browse SQLite/MySQL/PostgreSQL databases and their tables interactively.
- Version: 2.438 on 2025-12-25, with 18 votes
- Previous CPAN version: 2.437_05 was 7 days before
- Author: KUERBIS
-
Convert::Pheno - A module to interconvert common data models for phenotypic data
- Version: 0.29 on 2025-12-23, with 15 votes
- Previous CPAN version: 0.28 was 8 months, 4 days before
- Author: MRUEDA
-
Devel::MAT - Perl Memory Analysis Tool
- Version: 0.54 on 2025-12-26, with 30 votes
- Previous CPAN version: 0.53 was 1 year, 9 months, 19 days before
- Author: PEVANS
-
Finance::Quote - Get stock and mutual fund quotes from various exchanges
- Version: 1.68 on 2025-12-21, with 145 votes
- Previous CPAN version: 1.68 was 3 days before
- Author: BPSCHUCK
-
HTTP::Tiny - A small, simple, correct HTTP/1.1 client
- Version: 0.092 on 2025-12-27, with 115 votes
- Previous CPAN version: 0.091 was 14 days before
- Author: HAARG
-
JSON::Schema::Modern - Validate data against a schema using a JSON Schema
- Version: 0.631 on 2025-12-25, with 16 votes
- Previous CPAN version: 0.630 was 10 days before
- Author: ETHER
I am developing a Virtualmin plugin. But the problem is to have a link appear under the "Manage Virtual Server" category in the Virtualmin sidebar whenever the feature is enabled for a virtual server (domain).
Despite following the standard plugin structure, the menu item refuses to appear in the Virtualmin UI, although the module is accessible if I manually type the URL or find it in the Webmin "Tools" section (when not hidden).
Environment
- OS: Ubuntu 22.04 / 24.04
- Virtualmin version: Latest
- Webmin version: Latest
File Structure
/usr/share/webmin/my-plugin-folder/
index.cgimodule.infovirtual_feature.pl- ...
Relevant Code
virtual_feature.pl
require 'my-plugin-lib.pl';
sub feature_name {
return "plugin_name";
}
sub feature_label {
return "Plugin Name";
}
sub feature_disables {
return 1;
}
sub feature_check {
return undef;
}
sub feature_setup {
my ($d) = @_;
return undef;
}
sub feature_links {
my ($d) = @_;
# This is intended to place the link under "Manage Virtual Server"
return ({ 'mod' => $module_name,
'desc' => "Plugin Name",
'page' => "index.cgi?dom=" . $d->{'id'},
'cat' => 'server' });
}
1;
module.info
desc=Plugin Name Tool
os_support=*-linux
version=1.6
category=server
depends=virtual-server
virtualmin=1
hidden=1
Expected Behavior
After enabling the feature globally in System Settings -> Features and Plugins, a link should appear in the left-hand sidebar under the "Manage Virtual Server" category.
Actual Behavior
The feature shows up in the "Enabled features" list and can be toggled/saved successfully. However, the link never appears in the sidebar. No errors are logged in /var/webmin/miniserv.error.
What I have tried
- Restarting Webmin (
/etc/webmin/restart). - Hardcoding the module folder name in the
'mod'field offeature_links. - Changing the
'cat'field to'services'or'logs'. - Refreshing the Webmin module cache.
- Verifying that the feature is indeed marked as enabled in the domain's configuration file in
/etc/webmin/virtual-server/domains/.
Is there a specific registration step or a required function in virtual_feature.pl that I am missing for the sidebar injection to work correctly in recent versions of the Virtualmin Authentic Theme?
At an online event through the Perl Maven group we tried to understand this module and even to contriute to it. For more details about the contributions check out the OSDC Perl page.
This example is based on the one in the documentation of the JSON::Schema::Validate and tweaked a bit. It will be useful again if we continue dealing with this module.
examples/json_schema_validate.pl
use JSON::Schema::Validate;
use JSON ();
use open qw( :std :encoding(UTF-8) );
my $schema = {
'$schema' => 'https://json-schema.org/draft/2020-12/schema',
'$id' => 'https://example.org/s/root.json',
type => 'object',
required => [ 'name' ],
properties => {
name => { type => 'string', minLength => 5 },
next => { '$dynamicRef' => '#Node' },
},
'$dynamicAnchor' => 'Node',
additionalProperties => JSON::false,
};
my $js = JSON::Schema::Validate->new( $schema )
->compile
->content_checks
->ignore_unknown_required_vocab
->prune_unknown
->register_builtin_formats
->trace
->trace_limit(200) # 0 means unlimited
->unique_keys; # enable uniqueKeys
#my $data = {
# name => 'head',
# next => {
# name => 'tail'
# }
#};
#my $data = {
# name => 23,
# next => {
# name => 'tail'
# }
#};
#my $data = {
# name => 'head',
#};
my $data = {
name => 'head big',
};
my $ok = $js->validate($data)
or die( $js->error );
print "ok\n";






