TramAI - governed AI workflows for Java and Kotlin

Extending

TramAI is designed to stay structured while remaining adaptable. This section covers the extension points you use when the default providers and behaviors are not enough and you need to integrate custom infrastructure.

In This Section

GuideFocus
Custom ProvidersImplementing the ModelProvider SPI for non-standard or internal backends
Custom InterceptorsAdding cross-cutting behavior around operation execution
Custom ObserversPlugging in custom observation and telemetry behavior
MCP IntegrationThe internal MCP server adapter and what MCP capability does not exist yet

When To Start Here

Start here when the default modules are close but not sufficient, and you need to tailor TramAI to your platform or internal tooling.

What You Can Extend Without Forking

These surfaces are supported extension points. Everything else is internal and can change without notice.

SurfaceInterfaceNotes
Providersdev.tramai.core.provider.ModelProviderRegistered explicitly through ProviderRegistry; conformance is proved by ProviderTck
Request/response rewritingdev.tramai.core.observation.OperationInterceptorChainable; pass-through defaults on both methods
DLP scanningdev.tramai.core.security.DlpInterceptorInspect and sanitize model outputs and tool results
Observationdev.tramai.core.observation.OperationObserverOne observation per provider attempt
Engine eventsdev.tramai.engine.EngineEventObserverEvent identities come from RuntimeEventCatalogue
Structured outputStructuredOutputHandlerImplement a handler when Jackson does not fit your payloads

@ExperimentalTramaiInternalApi and @ExperimentalProviderTransportApi mark code that sits outside the stable compatibility promise. Opting in is fine; depending on it is a considered risk.

Constraints Every Extension Must Respect

These are enforced in the TramAI repository by verifyStaticSafetyGuards and verifyCancellationSafety, and they apply to your code too:

  • No sensitive-payload logging — never log prompts, responses, tool arguments, tokens, or credentials.
  • No System.out / System.err in production code; use a logger.
  • Cancellation must propagate. In catch (e: Exception) blocks call rethrowIfCancellation() from dev.tramai.core.coroutines.rethrowIfCancellation before wrapping, logging, or swallowing.
  • No unbounded response-body reads; use the bounded helpers.

Contributing Back

If you are contributing to the TramAI repository rather than building on it, the contributor change guides cover the same surfaces from the inside, including the files that must change and the contract tests that gate each change:

Next Steps