NAME

Langertha::Knarr - Universal LLM hub — proxy, server, and translator across OpenAI/Anthropic/Ollama/A2A/ACP/AG-UI

VERSION

version 1.001

SYNOPSIS

The fastest way to use Knarr is the Docker image:

docker run -e ANTHROPIC_API_KEY -p 8080:8080 raudssus/langertha-knarr
ANTHROPIC_BASE_URL=http://localhost:8080 claude

The Perl API behind it:

use IO::Async::Loop;
use Langertha::Knarr;
use Langertha::Knarr::Config;
use Langertha::Knarr::Router;
use Langertha::Knarr::Handler::Router;

my $loop   = IO::Async::Loop->new;
my $config = Langertha::Knarr::Config->new(file => 'knarr.yaml');
my $router = Langertha::Knarr::Router->new(config => $config);

my $knarr = Langertha::Knarr->new(
    handler => Langertha::Knarr::Handler::Router->new(router => $router),
    loop    => $loop,
    listen  => $config->listen,
);
$knarr->run;   # blocks; OpenWebUI etc. can now connect

DESCRIPTION

Langertha::Knarr is a universal LLM hub that exposes any backend — a Langertha::Raider, a raw Langertha::Engine, a remote A2A or ACP agent, or any custom Langertha::Knarr::Handler — over the standard LLM HTTP wire protocols spoken by OpenWebUI, the OpenAI / Anthropic / Ollama SDKs, and the agent ecosystems around A2A, ACP, and AG-UI.

By default a single running Knarr answers OpenAI /v1/chat/completions, Anthropic /v1/messages, Ollama /api/chat, A2A's /.well-known/agent.json plus JSON-RPC /, ACP's /runs, and AG-UI's /awp simultaneously on every listening port. The same handler implementation drives all of them.

Knarr 1.000 is built on IO::Async and Net::Async::HTTP::Server with native Future::AsyncAwait integration into Langertha engines, so streaming works end-to-end token-by-token without any thread or event-loop bridges.

ARCHITECTURE

Three pluggable layers:

Protocols

Wire formats live in Langertha::Knarr::Protocol::*. Each consumes Langertha::Knarr::Protocol and is loaded by default. See Langertha::Knarr::Protocol::OpenAI, Langertha::Knarr::Protocol::Anthropic, Langertha::Knarr::Protocol::Ollama, Langertha::Knarr::Protocol::A2A, Langertha::Knarr::Protocol::ACP, Langertha::Knarr::Protocol::AGUI.

Handlers

Backend logic — what answers the request. Knarr ships with Langertha::Knarr::Handler::Router (the default, model→engine via Langertha::Knarr::Router), Langertha::Knarr::Handler::Engine (single engine), Langertha::Knarr::Handler::Raider (per-session agent), Langertha::Knarr::Handler::Passthrough (raw HTTP forward), Langertha::Knarr::Handler::A2AClient / Langertha::Knarr::Handler::ACPClient (consume remote agents), and Langertha::Knarr::Handler::Code (coderef-backed for tests). Implement Langertha::Knarr::Handler to write your own. Decorators (Langertha::Knarr::Handler::Tracing, Langertha::Knarr::Handler::RequestLog) wrap any inner handler and add behavior on top — they themselves consume the Handler role and compose freely.

Transport

Default is Net::Async::HTTP::Server with chunked SSE / NDJSON streaming on one or more listen sockets. For Plack deployments, Langertha::Knarr::PSGI wraps the same Knarr instance into a PSGI app (buffered — see its docs for the streaming caveat).

handler

Required. An object consuming Langertha::Knarr::Handler.

listen

ArrayRef of host:port strings or { host => ..., port => ... } hashes. Defaults to a single entry composed from "host" and "port".

host

Default 127.0.0.1. Used when "listen" is not given.

port

Default 8088. Used when "listen" is not given.

loop

Optional IO::Async::Loop instance. Defaults to a fresh one.

protocols

ArrayRef of protocol class basenames to load. Defaults to all six shipped protocols.

auth_token

Optional shared secret. When set, every incoming request must present it as Authorization: Bearer or x-api-key. Discovery routes (/.well-known/agent.json) stay anonymous.

start

$knarr->start;

Binds all listen sockets and registers the dispatcher. Returns $self. Does not enter the event loop.

run

$knarr->run;   # blocks

Calls "start" if needed, then enters the "loop" and blocks.

session

my $session = $knarr->session($id);

Returns the Langertha::Knarr::Session for the given id, creating one on demand. Used internally by the dispatcher.

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/langertha-knarr/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.