Tramai Logo
Tramai

Native Image

TramAI uses JDK dynamic proxies for @AiService interfaces. GraalVM native-image builds need proxy metadata for every service interface instantiated at runtime.


What This Covers

  • Generating GraalVM proxy-config.json for your @AiService interfaces
  • Registering the right interfaces
  • Spring Boot considerations
  • Native image boundaries and smoke path

When You Need This

You need native image metadata when:

  • building a GraalVM native binary of your TramAI application
  • using @AiService interfaces that TramAI instantiates at runtime via dynamic proxies
  • deploying to serverless or container environments where fast startup matters

Minimum Setup: Metadata Generator

TramAI ships a small metadata generator: NativeImageProxyConfig.

import dev.tramai.core.nativeimage.NativeImageProxyConfig
import java.nio.file.Path

fun main() {
    NativeImageProxyConfig.write(
        outputPath = Path.of(
            "src/main/resources/META-INF/native-image/com.example/app/proxy-config.json",
        ),
        InvoiceAnalyzer::class,
        IncidentSummarizer::class,
    )
}

Run this generator before producing the native binary.

The generated JSON:

[
  { "interfaces": [ "com.example.InvoiceAnalyzer" ] },
  { "interfaces": [ "com.example.IncidentSummarizer" ] }
]

What to Register

Register every @AiService interface that TramAI will instantiate in the native binary:

  • application service interfaces used through Tramai.create(...)
  • Spring-discovered @AiService interfaces if you use tramai-spring

The rule: if TramAI creates a dynamic proxy for the interface at runtime, include it in proxy-config.json.


Spring Boot Considerations

If you use tramai-spring, register the same @AiService interfaces that Spring will ask TramAI to instantiate.

The metadata generator is the same — there is no Spring-specific path:

NativeImageProxyConfig.write(
    outputPath = Path.of(
        "src/main/resources/META-INF/native-image/com.example.app/proxy-config.json",
    ),
    InvoiceAnalyzer::class,
)

Full Workflow

  1. identify every @AiService interface that will be instantiated at runtime
  2. run NativeImageProxyConfig.write(...) to generate proxy-config.json
  3. place it under META-INF/native-image/<group>/<artifact>/proxy-config.json
  4. build your native image with that metadata on the classpath

Smoke Path

A reasonable smoke path:

  1. generate proxy metadata
  2. run normal JVM tests
  3. build one minimal native sample or smoke binary that instantiates at least one @AiService
  4. verify startup and basic operation

Limitations

  • TramAI keeps runtime proxying in v1 — applications generate proxy metadata for their own interfaces
  • This metadata covers TramAI's use of JDK dynamic proxies only
  • Your app may still need additional reflection hints for:
    • HTTP client native-image needs
    • framework-specific reflection hints
    • provider-library native-image constraints
  • TramAI does not yet ship KSP-generated implementations or automatic full native-image AOT integration

Next Steps