xrt 2.0 · 310,620-line in-house runtime · MIT

One executable,
the entire C server world

XServer packs its own TLS, concurrency engine and TCC compiler into a single exe — your application is a plain C source directory, compiled to native machine code at runtime, with zero-downtime hot reload after every edit. No interpreter, no FFI, no external dependencies.

0µs
Request latency10 routes · single connection
0
APIs callable from scriptsfull xrt exports
0
External dependenciesno OpenSSL / no DLLs
0MB
Single-file sizecompiler & SDK included
XServer — deploy
Application source is compiled to native code by the embedded TCC — the output shown here is the real log
features

Built to run for years —
a native C server foundation

Protocols, cryptography, concurrency, debugging — all self-written and built in. Not linked in: packed into the same file.

Single-File Delivery

One xs.exe plus a C source directory is a complete deployment. The TCC compiler, the full SDK headers and system libraries are embedded in an LZMA-compressed VFS — zero install on the target machine.

C as Script

The devfile is compiled in-process into native machine code by the embedded TCC and calls 3057 host APIs directly through the symbol table — zero interpreter, zero FFI overhead.

Zero-Downtime Hot Reload

Edit C source and it takes effect instantly: every candidate is compiled first, swapped in only on success — on failure the old generation keeps serving; retired generations are reclaimed safely by the GC thread once references hit zero.

In-House TLS 1.2 / 1.3

No OpenSSL dependency: X25519 / P-256 / P-384, AES-GCM, ChaCha20-Poly1305, session resumption, X.509 chain validation and CRL — on both the server and the client side.

Multi-Protocol Drivers

http / https, ws / wss, tcp / tcps and udp share one lifecycle; vhosts, SNI certificate selection, the static layer and connection takeover are built in.

High-Concurrency Engine

IOCP / epoll / kqueue / io_uring / select — five event-loop backends, plus a work-stealing thread pool, coroutines, channels and futures.

Built-In Memory Debugging

Canaries / UAF isolation / fault injection / ring event log / TEXT and JSON leak reports — enable it on the production process, no separate build needed.

Tailorable Extensions

Eleven optional libraries (sqlite / the mail family / LLMs / Markdown / certificates… 700 symbols in all) compile in on demand, or all at once with a single switch; a new extension needs just one json entry plus an import table — zero host code changes.

Desktop App Form

The webview extension + a class: "app" node = local HTTP + a WebView2 window; combined with xs pack single-file delivery the artifact is a double-click desktop exe. Falls back to headless automatically.

Automatic Certificate Renewal

A built-in ACME daemon: DNS-01 renewal 30 days before expiry + hot swap (connections survive); a directories[] CA fallback chain — if Let's Encrypt is down it switches to litessl, and back once it recovers.

Trust model: scripts are trusted native code (no sandbox), intended for operator-controlled deployments — full power is exposed, and you define the boundary.

hot reload

Change one line of C, the world switches seamlessly

Hot reload is a desired-state coordinator: immutable snapshot → full pre-compilation → atomic publish → two generations in parallel → reclaim at zero references.
A failed compile is rejected outright — rollback is a semantic guarantee, not a remedy.

XServer — live reload
  1. Immutable snapshot Config and script source are frozen into a revision fingerprint; every server within one reload sees the same input.
  2. Full pre-compilation An entire server's candidate scripts must all compile before side effects are allowed — any single failure rejects the whole batch.
  3. Atomic publish Listener slots switch without blinking: unchanged endpoints hand off in place, and new connections enter the new generation instantly.
  4. Two generations in parallel Old connections keep being served by the old code to completion; ServiceSwap → xsSwapTake hands over live state.
  5. Reclaim at zero references Once leases hit zero, the GC thread destructs script, driver and config in order — soak tests show zero leaks, zero crashes.
latest-wins intent merge pending ≤ 64 hot certificate replacement timers die with their generation 4 protocols × TLS covered
code

No magic, just C

The examples below are real code from the repository. XServer wraps no object model — you operate native xrt structures directly; the compiler and the type system are your framework.

/* route.h — URI × method slot-based registration (real source excerpt) */
static void RouteHTTP_Init(void)
{
	G_StaticRouteTableHTTP = xrtMapCreate(sizeof(RouteInfoHTTP));

	/* Static routes: exact URIs */
	AddStaticRouteHTTP("/api/v1/items", XHTTP_METHOD_GET,  Handle_API_List);
	AddStaticRouteHTTP("/api/v1/items", XHTTP_METHOD_POST, Handle_API_Add);

	/* Dynamic routes: {id} segment capture, method masks combine freely */
	AddDynamicRouteHTTP("/api/v1/items/{id}",
		XHTTP_METHOD_GET,                    Handle_API_Item);
	AddDynamicRouteHTTP("/api/v1/items/{id}",
		XHTTP_METHOD_PUT | XHTTP_METHOD_PATCH, Handle_API_Item_Update);
	AddDynamicRouteHTTP("/api/v1/items/{id}",
		XHTTP_METHOD_DELETE,                 Handle_API_Item_Delete);

	/* After registration, compile once into immutable patterns —
	   matching cost is independent of the route count */
	(void)RouteHTTP_Compile();
}
/* route_http/basic.h — building JSON with xvalue (real source excerpt) */
static void Handle_JSON(XS_HttpReq* pReq,
	const RouteParamHTTP* arrParam, uint32 iParamCount)
{
	const XS_HostInfo* pHost = pReq->host;
	xvalue* pObject = xrtValueObject();

	(void)arrParam; (void)iParamCount;
	xrtValueObjectSetNew(pObject, XRT_STR_LITERAL("server"),
		xrtValueString(XRT_STR_LITERAL("xs3 demo")));
	xrtValueObjectSetNew(pObject, XRT_STR_LITERAL("ok"),
		xrtValueBool(true));
	xrtValueObjectSetNew(pObject, XRT_STR_LITERAL("host"),
		xrtValueString(xrtStrView((pHost->Name ? pHost->Name : "?"))));

	(void)ReplyJSON(pReq, 200, pObject);
	xrtValueRelease(pObject);
}
/* ws / wss contract callbacks: XServer does handshake and framing,
   you write only business logic */
static void WsOpen(XS_HostInfo* pHost, xwsstream* pWs)
{
	xrtWsStreamText(pWs, xrtStrView("connected"));
}

static void WsText(XS_HostInfo* pHost, xwsstream* pWs, xstrview tText)
{
	/* Masking, fragment reassembly, control frames and message
	   limits are all handled by the xrt layer */
	(void)xrtWsStreamText(pWs, tText);          /* echo */
}

static void WsBinary(XS_HostInfo* pHost, xwsstream* pWs, xbytesview tData)
{
	xvalue* pMsg = xrtValueObject();
	xrtValueObjectSetNew(pMsg, XRT_STR_LITERAL("size"),
		xrtValueInt64((int64)tData.Size));
	(void)xrtWsStreamBinary(pWs, tData);
	xrtValueRelease(pMsg);
}
/* Hot-reload state handover: the old generation exports a snapshot,
   the new one takes it and carries on (contract API) */
static bool ServiceSwap(XS_HostInfo* pHost, xvalue** ppShared)
{
	xvalue* pState = xrtValueObject();

	xrtValueObjectSetNew(pState, XRT_STR_LITERAL("counter"),
		xrtValueInt64(G_iCounter));
	*ppShared = pState;               /* non-destructive: the old
	                                      generation can still serve */
	return true;
}

static void ServiceInit(XS_HostInfo* pHost)
{
	xvalue* pState = xsSwapTake(pHost);   /* valid only inside the
	                                      new generation's Init */

	if ( pState != NULL ) {
		G_iCounter = xrtValueInt64(
			xrtValueObjectGet(pState, "counter"));
		xrtValueRelease(pState);
	}
}

/* Trigger a reload: desired-state coordination; the returned
   stable ID can query the final state */
XS_ReloadId iId = xsReloadHostSubmit(pHost);
Scripts call 2957 xrt APIs directly: networking · TLS · HTTP · WS · coroutines · threads · files · JSON · templates · SQLite · XTP2 … API reference →
benchmark

On par with Go, flat at ten thousand routes

Measured by routebench: single-connection keep-alive sequential requests, 3 rounds × 10,000 per configuration, five server stacks on the same machine.

0µs
Latency @ 10 routes
0µs
Latency @ 10,000 routes
+0%
Latency growth at 10k routesFastAPI grows +935%
0–0×
faster than PHP / FastAPI at 10k routes

10 routes µs / request (lower is better)

XServer C/TCC
42.0
Go 1.22
42.2
PHP 8.3
391.6
FastAPI
379.0

10,000 routes µs / request (lower is better)

Go 1.22
45.7
XServer C/TCC
59.1
PHP 8.3
2318.2
FastAPI
3920.1

Batch pattern compilation plus matching that is independent of the route count keeps latency growth at only +41% under 10k routes; among the comparison stacks FastAPI degrades +935% and PHP +492%.

architecture

Three layers, one process, direct calls

No IPC, no serialization boundary — scripts call the host by address through the symbol table; a function call is just a function call.

Your code · compiled by TCC · the hot-reload unit
main.croute.hmodules/ route_http/page/template/wwwroot/
The application is a source directory — 14 contract symbols (ServiceInit / RequestProc / WsText …) are the entire contract
XServer host · ~9,400 lines
Config assemblyProtocol drivers http·ws·tcp·udpTopology & generations Reload coordinatorScript enginevhost · SNI
xs.json desired-state coordination · flicker-free listener handoff · generation reference-counted GC
xrt runtime · 310,620 lines · 91 modules · 3,030 APIs
TLS 1.2/1.3 + X.509HTTP/1.1WebSocket Five-backend event loopCoroutines · thread pool · channels Containers · JSON · templates · regex · patternMemory debugging
Zero TODO left in self-written code · two-level module trimming (XRT_MODULE_* / XRT_FEATURE_*)
TCC 0.9.28rc embedded LZMA VFS · 350 resources Windows / Linux 10 optional libraries · one-switch all · xs --version
deploy

Build once, copy and run

The artifact is replaced atomically only after a successful link — a failed build always leaves the last working xs.exe intact.

myapp/ the whole deployment ≈ one exe + source
xs.exe            5.2 MB   the only binary
xs.json           services · ports · TLS · vhosts
main.c            application entry (ServiceInit)
route.h           route registration manifest
modules/           reusable modules (http/db/template…)
route_http/        request handlers
page/              controlled pages (outside wwwroot)
template/          xrtTemplate templates
db/                SQLite data files
wwwroot/           static asset root
01

Build

One command builds a tailored variant on both platforms (Windows / Linux):

build.bat build.bat all
02

Copy

Copy xs.exe and the source directory to the target machine — no runtime install, no DLLs, no header dependencies; the compiler is already inside the exe.

03

Run & evolve

Start with xs xs.json; afterwards edit any C source and call xsReloadHostSubmit() to hot reload — no dropped connections, no downtime.

./xs xs.jsonFull guide →
single-file deploy

One exe, the whole site inside

Pack xs.json, wwwroot, C sources and TLS certificates into one LZMA archive appended to the xs binary — a zero-argument start reads the config and serves files straight from the pack. Same-named files on disk always win: drop one next to the exe to hot-fix, delete it to restore the packed version.

Single-file deploy in three steps
# 1. pack (the site dir must contain xs.json; per-entry LZMA)
xs.exe pack site/ -o app.exe
# 2. deploy: copying this one file is the whole deployment
app.exe
# 3. hot-fix: drop a same-named file next to the exe to override the pack
echo ... > app.exe/wwwroot/index.html

The pack is everything

  • config + static + sources + certificates all packed — the demo site 1.7 MB → 542 KB
  • disk priority: external files always win; drop a renewed certificate next to the exe, no repacking
  • built-in tooling: --list entries / --extract / --strip back to the pristine binary
  • zero startup cost: probing reads the last 24 bytes of itself; the immutable index is thread-safe, content decompresses lazily on first access and stays cached
  • --no-vfs: ignore the app pack at once, debug in directory mode
app node

A server and an APP

Declare a class: "app" service node in xs.json — a local HTTP service and a WebView2 desktop window in one process: a loading window at startup, the interface opens automatically once the service is ready, closing the window shuts down gracefully.

class: "app" in action
The XServer app-node desktop window: the site interface running inside a WebView2 window

One config, two forms

  • class: "app": local HTTP + desktop window in one; the interface is just a web page — templates, routing, SQLite keep working
  • automatic fallback: environments without WebView2 degrade to a headless service, same binary, zero changes
  • xsw.exe: the no-console variant ships with the release package — double-click and it is a desktop app
  • with xs pack: site, sources and certificates packed into one exe — single-file distribution for desktop apps
  • full stack available: xllm chats and xwork agent orchestration run behind the window
extensions

Need more? Compile it in

An extension = one json entry + one import symbol table + one header. Statically compiled into the host, symbols exported to scripts — even plugins compiled by nested TCC can use them.

sqlite

272 symbols · FULLMUTEX-safe for multiple workers

The complete SQLite engine compiled in statically, its header exposed through the VFS. Prepared statements, bound parameters, transactions — the demo's REST CRUD is built on it.

sqlite3_open_v2("db/main.db", &db, flags, NULL);

xtp2

32-byte header frame protocol · streaming parser

A binary application-layer protocol over ordered byte streams: REQUEST / RESPONSE / PUSH / EVENT message types, a complete limits system, verified with libFuzzer.

xtp2_feed(&st, buf, len);  /* incremental parsing, zero allocation */

xllm

68+57 symbols · 3 dialects · SSE streaming

The LLM calling core library (same source as xrt extlibs): request and multimodal construction, Chat Completions / Responses / Anthropic dialects, SSE decoding, retries and cancellation; networking and TLS come from the host xrt.

xllmRequestAddTextMessage(&req, XLLM_ROLE_USER, "hi");

qrcodegen

10 symbols · QR + PNG output

QR Code generator (Nayuki, MIT): encode and read modules in one step; a PNG output layer (1-bit grayscale, IDAT via xrt zlib) — ready for 2FA, payment codes, API endpoints and mail embedding.

png = qrcodegen_png(qr, 4, 4, &size);

xjwt

24 symbols · HS/RS/ES + JWKS

JWT (RFC 7519) signing and verification: HS256/384/512, RS trio (PKCS#8/PKCS#1), ES256 (DER, OpenSSL interop), JWKS key selection, public-key caching; one-line error reads, array-valued aud.

claims = xjwtVerify(token, pem, &check);

xoauth2

25 symbols · auth-code + PKCE + OIDC helpers

OAuth 2.0 (RFC 6749) client: five provider presets, PKCE, token refresh, one-shot state/nonce burn; transport via injectable callback (xrt TLS convenience included). Data-couples with xjwt — eight lines of glue compose an OIDC login.

tok = xoauth2CompleteLogin(&oauth, code, state);

xwork

42 symbols · Agent orchestration

The capstone of the AI stack (above xllm): tool registration & execution, workspace policy, subagent types, notification stream and compaction scheduling. Proven end-to-end by agent-demo — approval gates, trails and diff panels verified in-browser.

xworkAgentRegisterBuiltinTools(agent);

webview

app node · desktop window

WebView2 desktop window + class: "app" service node: loading splash → auto-open on ready → graceful shutdown on close. Combined with single-file packing = a double-click desktop exe; falls back to headless when unavailable.

if (xsWebviewAvailable()) openDesktop();

Your library

one entry in extensions.json

Point at the source files, VFS header and import table — the registry checks path escapes, duplicate macros and name collisions, verified by both unit tests and runtime probes.

{ "name": "mylib", "macro": "XS_USE_MYLIB" }

Put the server back into one file

xrt runtime + XServer host + your C source — start now.

Friendly Links