PSR-7 Bridge

Request and Response are Monad-native classes, not PSR-7 implementations. Full PSR-7 immutability semantics conflict with the ergonomic accessor API ($request->input('email'), $request->json('customer.name')) — adopting PSR-7 directly would mean giving up that API. Instead, both classes expose bridge methods that convert to and from a real PSR-7 value, so anything in your stack that expects PSR-7 — a third-party middleware, an HTTP client integration — still works.

Request to and from PSR-7

use Monad\Clarity\Services\Request;

$request = Request::capture();
$psrRequest = $request->toPsr7(); // Psr\Http\Message\ServerRequestInterface

// And back:
$request = Request::fromPsr7($psrRequest);

The round trip preserves method, path, query parameters, cookies, uploaded files, and the raw body — a request built from fromArrays(), converted with toPsr7(), and converted back with fromPsr7() ends up with the same path and query values it started with.

Response to PSR-7

use Monad\Clarity\Services\Response;

$response = Response::json(['ok' => true]);
$psrResponse = $response->toPsr7(); // Psr\Http\Message\ResponseInterface

$psrResponse->getStatusCode();              // 200
$psrResponse->getHeaderLine('Content-Type'); // application/json
(string) $psrResponse->getBody();            // {"ok":true}

There's no Response::fromPsr7() — responses are constructed going one direction only, since your application code is always the one producing them.

What's actually PSR

Logger implements PSR-3, Cache implements PSR-16, and HttpClient implements PSR-18 directly — each is a small, stable interface with no ergonomic conflict with Monad's own API style, so there was no reason to bridge those.

Next steps