Changes for version 0.002000 - 2026-06-26

  • Distribution
    • The PAGI distribution is now the specification: PAGI.pm plus the PAGI::Spec::* documentation. The reference server and its runner (PAGI::Server::Runner) moved to the PAGI-Server distribution, and the application toolkit (middleware, apps, endpoints, request/response, test utilities) moved to the PAGI-Tools distribution. Git history preserved.
    • The PAGI::Spec::* documents are now authored directly as POD. The previous markdown-to-POD build step (and its App::sdview dependency) has been removed; the spec POD is the source.
    • Expanded the learning material: PAGI::Cookbook (worked, runnable recipes), examples/mini-framework (a complete web framework on PAGI in about fifty lines), PAGI::PSGI (a migration guide for people coming from PSGI), PAGI::Building (a guide for framework authors), and a committed README.md. All example code targets Perl 5.18.
    • The spec modules are pure documentation. For backward compatibility during the transition, PAGI pulls in PAGI-Server and PAGI-Tools as runtime dependencies, so existing `requires 'PAGI'` dependents keep getting the server and toolkit. Depend on PAGI::Server / PAGI::Tools directly; this convenience dependency will be removed in a future release.
  • Specification updates
    • pagi.connection gains response_started (MUST) and response_complete (SHOULD). response_started is true once http.response.start is emitted for the scope -- server-set, read-only, and producer-agnostic (an application response and a server-synthesized backstop both set it; the terminal callbacks carry the clean-vs-abnormal outcome). Because it lives on the shared pagi.connection object it is observable across the middleware stack, unlike a per-layer-copied scope scalar. Adds the per-request scoping note for connection (HTTP/1.1/2/3; SSE as its own scope type).
    • Documented scope shallow-clone semantics. Middleware clone the scope for downward-only isolation: top-level keys are private to each layer, while referenced values (the pagi.connection object, lifespan state) are shared, so a plain top-level scalar does not propagate -- share per-request state through a reference. PAGI::Spec states the normative minimum; the model is detailed in PAGI::Building, with shorter notes in PAGI::PSGI and PAGI::Tutorial.
    • Header byte safety is now the server's duty. On emission a server MUST reject (fail the send) any header name or value containing CR, LF, or NUL (and control characters in names) rather than forwarding or silently rewriting it (RFC 9112 S11.1, RFC 9110 S5.5). This generalizes the existing sse.send field-newline rule to all header emission and lets app-side containers such as PAGI::Headers hold values as opaque bytes.

Documentation

building frameworks and toolkits on PAGI
worked, runnable recipes for the PAGI protocol
how PAGI stays loop-agnostic, how not to block, and how a server binds to an event loop
coming to PAGI from PSGI
The base PAGI specification: application interface and core concepts
The PAGI server extension mechanism
The PAGI Lifespan protocol for startup and shutdown events
The PAGI server runner contract for swappable servers
The PAGI TLS extension for reporting connection security in scope
PAGI message formats for HTTP, WebSocket, and SSE
Learn the PAGI protocol for async Perl web applications

Modules

Perl Asynchronous Gateway Interface

Examples