Using kiss-server with AI coding agents

This guide teaches AI coding agents how to generate small, correct, and performant applications with kiss-server.

Purpose Of This Guide

AI agents tend to overbuild HTTP services: adding frameworks, JSON libraries, global abstractions, unnecessary maps, and hidden blocking work. KissServer is intentionally small. Generate code that matches that shape.

Use this guide when creating an app with kiss-server or when changing kiss-server itself.

When To Use kiss-server

Use kiss-server for:

When Not To Use kiss-server

Do not choose kiss-server when the app requires:

For TLS, HTTP/2, HTTP/3, compression policy, and edge caching, put Cloudflare, Nginx, Caddy, or another reverse proxy in front.

Core Mental Model

KissServer server = KissServer.create();

server.fastGet("/health", FastResponses.text("OK"));
server.get("/users/{id}", ctx -> ctx.text(ctx.pathParam("id")));
server.post("/echo", ctx -> ctx.text(ctx.bodyAsString()));

server.start(8080).await();

There are two route paths:

The Two Route Paths

Fast Path

Fast path routes use fastGet(path, responseBytes):

server.fastGet("/health", FastResponses.text("OK"));
server.fastGet("/version", FastResponses.json("{\"version\":\"1.0.0\"}"));

Use fast path only when:

Good candidates: /health, /ready, /version, /ping, /robots.txt.

Normal Path

Normal routes use get, post, put, delete, patch, head, options, or route:

server.get("/users/{id}", ctx -> {
    String id = ctx.pathParam("id");
    return ctx.text("User " + id);
});

Use normal routes for:

Performance-First Route Selection

Endpoint shape Use Reason
Fixed static GET fastGet + FastResponses avoids normal route object allocation
Dynamic GET normal get needs Context and path/query input
POST body normal post needs request body handling
Static JSON fastGet + FastResponses.json prebuilds response bytes
Dynamic JSON normal route + Response.body response depends on request or domain data
Blocking work normal route + suitable executor selector should not be blocked

Best Performance Patterns

Good Examples

Fast health endpoint:

server.fastGet("/health", FastResponses.text("OK"));

Normal dynamic endpoint:

server.get("/users/{id}", ctx -> {
    String id = ctx.pathParam("id");
    return ctx.text("User " + id);
});

Normal POST endpoint:

server.post("/echo", ctx -> ctx.text(ctx.bodyAsString()));

JSON response without adding a JSON dependency:

server.get("/status", ctx -> {
    String json = "{\"status\":\"ok\"}";
    return Response.body(HttpStatus.OK, ContentType.JSON, json, StandardCharsets.UTF_8);
});

Header access:

server.get("/agent", ctx -> {
    String agent = ctx.request().header("User-Agent");
    return ctx.text(agent == null ? "" : agent);
});

Domain-specific body limit inside a route:

server.post("/commands", ctx -> {
    byte[] body = ctx.request().body();
    if (body.length > 64 * 1024) {
        return ctx.text(HttpStatus.PAYLOAD_TOO_LARGE, "Payload too large");
    }
    return ctx.text("Accepted");
});

Bad Examples

Do not use fast path for dynamic logic:

// Bad: fast path is not for request-dependent business logic.
server.fastGet("/users/123", FastResponses.text(loadUserFromDatabase("123")));

Do not hide blocking work on direct mode:

// Bad: DIRECT handlers run on the selector thread.
ServerConfig config = ServerConfig.builder()
        .handlerExecutionMode(HandlerExecutionMode.DIRECT)
        .build();

Do not add a framework just to build a small kiss-server app:

<!-- Bad for a simple kiss-server app unless the application explicitly needs it. -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Bad Patterns

Java 17 Baseline

Generated code should default to Java 17:

JDK 21 Virtual Threads Optional Usage

JDK 21 applications may pass a virtual-thread executor:

ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

ServerConfig config = ServerConfig.builder()
        .port(8080)
        .executor(executor)
        .build();

This belongs in application code only. Do not add direct JDK 21 API calls to kiss-server main source.

Android Compatibility Notes

KissServer is Android-compatible by design, not validated as universally Android-supported yet.

AI agents should:

Do not claim Android device support until instrumented Android validation exists.

Error Handling Patterns

Custom error handler API is not implemented yet. Current behavior maps safe server errors to HTTP responses such as 400, 404, 405, 413, 431, and 500.

For app-level validation, return explicit responses:

server.get("/users/{id}", ctx -> {
    String id = ctx.pathParam("id");
    if (id == null || id.isBlank()) {
        return ctx.text(HttpStatus.BAD_REQUEST, "Missing id");
    }
    return ctx.text("User " + id);
});

Handler exceptions map to a safe 500 Internal Server Error response and should not expose stack traces to clients.

JSON Handling Without Dependency

KissServer does not require a JSON library. For static JSON:

server.fastGet("/version", FastResponses.json("{\"version\":\"1.0.0\"}"));

For dynamic JSON, build or serialize the domain value in the application:

server.get("/users/{id}", ctx -> {
    String id = escapeJson(ctx.pathParam("id"));
    String json = "{\"id\":\"" + id + "\"}";
    return Response.body(HttpStatus.OK, ContentType.JSON, json, StandardCharsets.UTF_8);
});

Only add a JSON dependency when the application explicitly needs one.

src/main/java/com/example/app/Main.java
src/main/java/com/example/app/Routes.java
src/main/java/com/example/app/UserService.java
src/test/java/com/example/app/RoutesTest.java
pom.xml

Keep route handlers small. Move domain logic into small classes when it improves clarity.

Use a reverse proxy for TLS and modern edge features:

client
  -> Cloudflare/Nginx/Caddy using TLS + HTTP/2 or HTTP/3
      -> kiss-server using HTTP/1.1 locally

Configure an explicit executor for production apps. Choose a fixed or cached pool for Java 17 based on workload, or a virtual-thread executor from JDK 21 application code for blocking-heavy apps after testing.

AI Checklist Before Generating Code

AI Checklist Before Changing kiss-server Itself

Common Mistakes To Avoid

Prompt Snippet For Generating A kiss-server App

Create a Java 17 Maven app using kiss-server. Keep the app zero-framework and use no dependencies except kiss-server unless I explicitly request one. Use fastGet with FastResponses for fixed /health and /version endpoints. Use normal get/post routes for dynamic and business endpoints. Configure an explicit ExecutorService. Include curl commands, focused tests, and a short benchmark command using wrk. Do not use JDK 21 APIs unless the snippet is clearly marked optional.

Prompt Snippet For Optimizing A kiss-server App

Inspect this kiss-server app for performance. Identify fixed static GET endpoints that can safely use fastGet. Keep dynamic and POST routes on the normal path. Look for unnecessary allocation, body string conversion, synchronized hot state, blocking direct-mode handlers, and synchronous per-request logging. Benchmark before and after with wrk, include p99 latency, store raw results, and do not claim universal production performance.

Prompt Snippet For Adding A New Route

Add a route to this kiss-server app. Inspect the current routing style first. Use fastGet only if the route is an exact fixed GET response. Use a normal route for dynamic params, query-dependent logic, request bodies, or business logic. Keep Java 17 compatibility, add focused tests, update docs or curl examples, and avoid adding frameworks or JSON dependencies unless required.