Jamie Balfour

Welcome to my personal website.

Find out more about me, my personal projects, reviews, courses and much more here.

Jamie Balfour'sPersonal blog

ZPE 1.14.5 is another major update, and it builds on the incredible work that ZPE 1.14.3 and 1.14.4 have already delivered. ZPE 1.14.5 will deliver on many promises, too. 

The first big feature coming to ZPE is a breaking change. It is one that improves the syntax and performance for ZPE now and in the future, and it's something I've been wanting to do for some time.

When I say it's a breaking change, I mean that several predefined functions are now part of modules rather than being predefined functions. Those functions are:

  • random_number () -> Math::random_number ()
  • calculate_range () -> Math::range ()
  • calculate_mean () -> Math::mean ()
  • calculate_median () -> Math::median ()
  • calculate_mode () -> Math::mode ()
  • calculate_minimum () -> Math::minimum ()
  • calculate_maximum () -> Math::maximum ()
  • calculate_standard_deviation () -> Math::standard_deviation ()
  • generate_histogram () -> Math::generate_histogram ()
  • calculate_linear_interpolation () -> Math::linear_interpolation ()
  • shutdown -> System::shutdown ()
  • get_environment_variables () -> System::get_environment_variables ()
  • limit_real () -> Math::limit_number ()
  • is_headless () -> System::is_headless ()
  • is_command_line () -> System::is_command_line ()
  • aes_encrypt () -> Cryptography::aes_encrypt ()
  • aes_decrypt () -> Cryptography::aes_decrypt ()
  • file_encrypt () -> Cryptography::file_encrypt ()
  • file_decrypt () -> Cryptography::file_decrypt ()

Two functions (so far) have been transformed into module constants.

  • get_os_name () -> System::OS_NAME
  • get_max_memory () -> System::MAX_MEMORY

I will update this post as I continue to work on ZPE 1.14.5.

March 2026 has been a hugely important month for ZPE, with changes that go far beyond small fixes or minor additions. The overall direction is clear: ZPE is continuing to evolve from a scripting engine into a much broader and more capable platform, with major improvements to performance, web functionality, tooling, deployment, and the YASS language itself.

One of the biggest themes throughout the month has been performance. A great deal of work has gone into improving execution speed, especially in the runtime, the ZEN Web Parser, and ZPEC. The parser has seen repeated optimisation work, and the runtime itself received considerable performance improvements later in the month. ZPEC, the ZPE Performance Enhanced Cache, also saw major gains. It is now enabled by default, can be listed and purged more easily, and is robust enough that cached files can now be run through ZPEKit as well. Altogether, these changes make repeated execution and web-driven workloads significantly faster and more practical.

In addition to the performance improvements noted earlier, ZPE performance got an additional improvement that made it around 2 times faster than it was even after that improvement at the end of the month. This improvement speeds up both development as well as the runtime.

Another of the most significant developments has been the rapid growth of ZPE’s web capabilities. The ZEN Web Parser was extended to support sessions, cookies, and GET and POST parameters, making it much more suitable for real-world web applications. A particularly important design change was the introduction of the RequestObject, which redefines the role of the ResponseObject. Incoming data now comes from a RequestObject, while outgoing data is represented separately in the ResponseObject. This is a much cleaner and more logical model for web execution.

Session handling has also advanced considerably. Sessions can now store full ZPE values rather than being restricted to strings, which is a major improvement in flexibility. That change also led to updates in how VWS stores objects in sessions, bringing things more into line with the capabilities of the ZPE runtime. Session persistence bugs were fixed, expiry times were added, and responsibility for session handling was shifted away from VWS and into ZPE-PM. This is one of the clearest signs that the web architecture is maturing quickly.

A major new addition this month is ZPE-PM, the ZPE Process Manager. This is one of the standout features of the entire changelog. ZPE-PM allows scripts to be run over a socket, streams output directly, caches .yas files, and now handles sessions as well. It also accepts parameters through JSON requests and has effectively replaced the old JSON communication mode, which has now been removed. This is a major architectural step because it gives ZPE a much stronger service-based execution model and opens the door to cleaner integration with web servers and other tools.

The relationship between ZPE-PM and the VelocityWebServerModule also developed further. Both now handle sessions, and when ZPE is used with Apache, session information is passed to ZPE-PM through the JSON request. VWS also now passes the request over to ZPE itself for handling, so VWS no longer manages sessions directly. This centralisation makes the overall design more coherent and should make the platform easier to maintain and extend.

There were also important changes for YASS as a language. The new arrow expression syntax is one of the most exciting additions for day-to-day coding. Expressions such as x.where(n => n % 2 == 0) are now fully implemented, and the feature has also been extended to work with maps, allowing forms such as x.where(k, v => v > 40). This is a very modern addition to the language and makes working with collections far more expressive and convenient.

March also introduced compiled YASS webpages through the new .yep file format. This is another major milestone because it strengthens ZPE’s role as a web platform rather than simply a scripting environment. Alongside that, LAMEX3 was added in experimental form as an AI-improved version of LAME, showing that experimentation and forward-looking development are continuing alongside the core runtime work.

Tooling and usability have also improved noticeably. A new Interactive Actions feature was introduced, allowing interactive code sessions. New ZAC tools were added, including --tools and --zpec, and there was some useful command-line tidying too, such as moving properties help from -p to -h properties. These are the kind of improvements that make the platform easier and more pleasant to work with as it grows in complexity.

Installation and deployment have become simpler as well. The old createInstallScript approach has been removed, and ZPE now installs itself. A dedicated ZPEInstaller class was introduced to support the growing range of installer responsibilities. This is an important quality-of-life change because it reduces friction and helps the system feel more complete and self-contained.

There were also several internal architectural changes that, while less flashy, are very important. Undefined is now internally defined as a singleton, which is cleaner and more efficient. Aliases have been moved from the runtime to the compiler, meaning they are now compiled into their corresponding function calls rather than resolved dynamically at runtime. This should improve both performance and compatibility. The runtime was also updated to use its own standard output, and native methods now include checks for returned data types.

DepthGuard has also been added. DepthGuard protects and guarantees against stack overflow in recursive toString functions. This is needed for ZPE's debug features, but it's also good practice.

Parsing and reliability also received attention. The JSON parser was improved, syntax errors now report proper line numbers, and a CSV parser bug was fixed so that line breaks are handled correctly. There was also a fix for a recent bug that caused the first argument in an executable to be ignored. These may sound like smaller details, but they make a big difference to the day-to-day experience of using and debugging the platform.

ZPE's performance was improved through plugins and internal functions; it now also uses a special caching method for internal functions to further improve performance.

Several smaller additions round out the month’s work. A new directory_is_empty function was added, and list_add_element now has the append and list_append aliases. These are not as fundamental as the web and runtime changes, but they still help make the language and standard library more convenient to use.

Looking across all these updates, the biggest story is that ZPE is becoming broader, faster, and more mature. Performance has improved significantly, caching is now a central part of the system, web support has become much more capable, session handling has been redesigned for greater scalability, and ZPE-PM introduces a powerful new execution model built around sockets and structured requests. At the same time, YASS is gaining more modern language features, and the surrounding tooling is becoming easier to use and deploy.

In addition, ZPE 1.14.3 introduced built-in debugging that works very well. But ZPE 1.14.4 has improved this considerably, making it faster and much more reliable. Now, instead of relying on internal commands, ZPE uses a port system to send them.

Last but not least, ZPE 1.14.4 introduced static built-in objects. These are like the Math library in Java or Python. For example, ZPE now has a CLI class with static methods. HTMLBuilder is now static also. This means they can be accessed at startup with their name. For example CLI->overwrite($i).

In short, March 2026 has been one of the most substantial periods of development for ZPE in quite some time. The platform now feels far closer to a complete application environment, with serious web capabilities, stronger architecture, better performance, and a more modern developer experience. There is still more to come, but this month has laid down some very important foundations for where ZPE is heading next.

ZPE 1.14.4 has had the most builds of any minor version of ZPE to date, with over 2,000 builds.

Arrow expressions are another new feature coming to ZPE 1.14.4. They make light work of simple expressions:

YASS
$x = [11, 34, 55, 66, 74, 87, 93, 102]
print($x.where(n => n % 2 == 0))

And for maps:

YASS
$x = ["a" => 11, "b" => 34, "c" => 55, "d" => 66, "e" => 74, "f" => 87, g" => 93, "h" => 102]
print($x.where(key, value => value > 40))

These new expressions are designed to simplify statements that would normally require a lambda function:

YASS
$x = [11, 34, 55, 66, 74, 87, 93, 102]
print($x.where(n => function ($n) { return $n % 2 == 0}))

Underneath, arrow expressions are actually running a lambda function themselves, but the syntax is simpler and easier on the eye than a lambda function.

In addition, I have also made some other significant changes:

  • Firstly, internal aliases are no longer part of the runtime but are now part of the compiler, so that they are compiled to the appropriate internal function. This improves performance slightly, too. 
  • New features in the parser mean that line numbering in compiler syntax errors and any other compile errors now show correct line numbers.
  • And finally there's been a major fix in the CSV parser.

With a significant improvement to mod_zpe over the last few days, coupled with ZPE-PM and the new ZPE 1.14.4 performance improvements, YASS is now fully capable of running as a server-side language. And you can see what I mean if you visit the section of my website which is all powered by YASS at https://www.jamiebalfour.scot/yass. This part of my website is running the Apache module mod_zpe, and ZPE-PM is permanently running on my webserver as the backend. 

ZPE 1.14.4 will be out a week on Thursday, bringing massive improvements to ZPE. Also launching this Thursday is VWS 1.1.3, which brings major updates to VWS.

mod_zpe was first written in 2024 and has been pretty decent since. Its only letdown was one of ZPE's biggest weaknesses - it needed a fresh start every time it was required. Now with the latest update and ZPE 1.14.4's new ZPE-PM, it's finally possible to get exceptional performance from ZPE.

ZPE-PM is a daemon that runs YASS code via a socket. That means that there is no start-up cost associated with running code. This makes responses very quick - almost instant. 

ZPE is even more integrated into VWS than into Apache, offering an easy-to-manage installation. But at least now it works with Apache too.

ZPE-PM is the latest feature to make it into ZPE 1.14.4, and it's a major addition. 

ZPE-PM or ZPE Process Manager works like PHP-FPM (FastCGI Process Manager). ZPE-PM is designed to run as a daemon process, much like ZPE Lite (more on that later). 

One of the biggest limitations of traditional scripting setups is that every request starts from scratch.

  • Load runtime
  • Parse code
  • Execute
  • Tear everything down

That’s fine for small scripts, but as things grow, it becomes inefficient — and harder to scale.

So I built ZPE-PM.

ZPE-PM is a long-running process that executes ZPE scripts over a socket connection.

Instead of launching ZPE for every request, you:

  1. Start ZPE-PM once
  2. Send it execution requests over a socket
  3. Receive results (or live output)

It acts as a bridge between:

  • clients (CLI tools, web servers like VWS)
  • and the ZPE runtime

ZPE Lite is now, well, really lite. Using the zpe -l command to run the Lite mode is easy. You simply provide a file name to run through ZPE-PM (ZPE-PM must be running), and a host and port number are optional. By default, the host is localhost, and the port is 8940. 

You can also communicate with ZPE-PM with Python, C#, or any programming language that supports sockets. 

It's very fast. Processing with ZPE 1.14.4 has become considerably faster overall, so the Standard Algorithms went from 650ms to around 300ms in the latest update. But ZPE-PM makes the whole process really fast, and the newly improved ZPEC caching system comes in really handy for further performance improvements. Running a script once caches the byte codes for the next run. But not only that, ZPEC is designed for low-latency internalised communication, so requests are very lightweight, adding only around 7ms of overhead.

ZPE 1.14.4 is a big update. It mainly focuses on performance but also on integration with VWS.

First performance. This is big. Running the Standard Algorithms library in ZPE 1.14.3 took an average time of ~600ms. With ZPE 1.14.4, the mean time is now ~350ms. This is a massive improvement. ZPEX has gone from 30ms to 23ms to run the same library too. 

VWS has recently been revisited, so ZPE's support for VWS has been improved. New session variables, cookies and much more have been added to ZPE. ZPE's web performance has also been improved. As well as this, in addition to the YASS Web Pages (ywp) files you can create, you can now also compile these to YASS Executable Pages (yep) files for up to 5x faster processing. Nice.

ZPE now has a new --tools option for special tools in ZPE. ZPE --install now actually installs ZPE. ZPEC has been improved too, offering much better and faster performance than before. LAMEX3 comes to ZPE - 'improved' by ChatGPT (although performance has occasionally been lower than LAMEX2, I am working to ensure it is consistently faster than X2).

ZPE 1.14.4 will be out very soon, as I am just adding the finishing touches. 

VWS 1.1.3 is a big update with many new performance improvements and features.

VBench

Part of Velocity Web Server's growth has been adding tools to make managing a web server easier than ever. VBench, a new benchmarking tool, continues this philosophy. It works much like Apache Benchmark and is designed to be a drop-in replacement for quickly running benchmarks on any operating system, with a single command in VWS.

Much like ApacheBench, VBench sends many concurrent requests to a web server to test how well it handles them. VWS, on average, can handle 180 requests per second on a simple PHP page, whereas Apache is closer to 75 per second (though this is not an official number yet), as I'll need to do more rigorous testing later.

VBench is something I've wanted to make for a long time, and now I have. 

Web Assets

Web Assets are a special type of asset that can be cached by the web server. For example, let's say you host many websites on your web server, and all of these websites use React. Well, rather than specifically copying React to each of these websites, just use the Web Assets tool - firstly install the asset (React) and then on each of the pages requiring React, just write and VWS will provide it for you. And it's quick too. 

Web Asset Bundles

Web Asset Bundles are even more interesting and useful. These combine multiple assets into a single request before sending them to you, reducing the number of requests. Same idea, but instead of the word asset, we use bundle: . It's fast, and it's powerful. 

The most recent benchmarkings

I benchmark VWS frequently using Apache Bench. The command used is ab -n 10000 -c 40 url. I do this for both Apache and VWS and run the same file on the same server. I then get ChatGPT to look at the results from both of them and summarise. Thanks to some real performance improvements, VWS pulls ahead of Apache in all benchmarks carried out. Here's what ChatGPT had to say:

VWS performed slightly better than Apache in this test. Apache handled 2544.69 requests/sec with a mean request time of 15.719 ms, while VWS handled 2670.49 requests/sec with a mean request time of 14.979 ms. Both completed 10,000 requests at concurrency 40 with 0 failed requests.

Latency was also a bit better on VWS. The median request time was 14 ms for VWS versus 15 ms for Apache, and the 99th percentile was 24 ms for VWS versus 36 ms for Apache. That suggests VWS had slightly better tail latency in this run.

Apache showed a lower mean connect time, but VWS showed a lower mean processing time. Apache’s mean connect time was 5 ms versus 8 ms for VWS, but Apache’s mean processing time was 10 ms versus 7 ms for VWS. Overall total mean time still favoured VWS at 15 ms versus 16 ms for Apache.

Apache transferred more total bytes, 4,010,000 versus 3,020,000 for VWS, while both transferred the same HTML payload, 1,310,000 bytes. That suggests Apache was sending more header overhead, while VWS was leaner on the wire.

So the overall finding is that, for this particular internet-facing test at concurrency 40, VWS was competitive with Apache and slightly faster overall, with lower average latency, better tail latency, and no failed requests.

Next steps

I had given up on VWS until last month. But now look at it. It's nearly a fully-fledged web server.

VWS is nearly production-ready. The introduction of benchmarking tools has allowed me to test how well VWS handles multiple requests, and it does pretty well. I have no concerns about VWS being able to deliver what's needed on scale, but I want to get it right.

Additionally, ZPE has been getting a lot of attention over the last four months, with this month and last month focused on the new features in VWS. 

Velocity Web Server (VWS) has been getting more and more features for over a week now. Over the last few days, VWS has gained quite a lot:

  • POST and GET (query string) parameter values
  • Sessions and session variables
  • Cookies
  • Headers
  • RESPONSE and REQUEST parameters
  • Virtual hosts - multiple domains on one server
  • A Control Server (used to receive control signals)
  • MIME type support
  • Keep alive
  • Redirects

Additionally, ZPE's performance has improved. ZPE now supports compiled YASS Web Pages known as YASS Executable Pages (.yep). This improves page loading performance considerably. 

VWS will be released at the end of this month, alongside ZPE 1.14.4.

As the title suggests, this evening I had a major breakthrough with Velocity Web Server, introducing TLS support. This was one of the biggest barriers to the development of VWS back in 2023, but now it's back on track, and the server is getting better and better.

I am now looking into virtual hosts and adding automatic Let's Encrypt certificate issuance. 

VWS performance, particularly for static files, is exceptional and very, very fast. In addition, if you end up going with ZPE and YASS Web Pages, you'll see the huge performance gains you can get from a solid web server built on modularity.

Powered by DASH 2.0