Contributor Change Guides
TramAI's structure is enforced, not just documented. Every extension point has a contract test that fails the build when you drift from it, so a change is only "done" when the gates that own it pass.
Each guide below names four things:
- the exact extension point — the SPI, interface, or builder you implement;
- the files that must change — including the machine-readable registries;
- the mandatory contract tests — the TCKs and architecture guards that act as independent oracles;
- the verification commands — the gates you run before requesting review.
Every guide also ends with a trap list: what fails CI when you skip a step.
The Guides
| Change | Guide | Key contract |
|---|---|---|
| New provider adapter module | Adding a Provider | ProviderTck + ProviderTckEnrollmentArchitectureTest |
| New persistence store implementation | Adding a Store | shared store TCKs + *EnrollmentArchitectureTest |
| New workflow step (built-in or external) | Adding a Workflow Step | step tests + definition-digest golden + cancellation scanner |
| New approval state or transition | Adding an Approval State | ApprovalStoreTck + ApprovalContinuationStoreTck + lifecycle-model property tests |
| New runtime event | Adding an Event | RuntimeEventCatalogueArchitectureTest (ASM + source scan) |
| Change structured-output constraints | Changing Structured-Output Constraints | StructuredOutputContractTck + ContractEvolutionTest |
How The Guides Stay Honest
Each guide is written against the 0.6.0 source tree with verified path:line references. The contract tests it names are independent oracles: they are deliberately not derived from the implementation, so they fail loudly on drift.
If a guide's facts no longer match the code, the codebase moved. Update the guide in the same pull request that moves the contract, or the next contributor following it wastes a review round.
Authority For Module Metadata
Never hand-write module classification into documentation. The single source of truth is in the TramAI repository:
| File | What it owns |
|---|---|
config/quality/module-catalog.yml | Module path, description, maturity, apiStability, layer, publishability, rationale, and the shared entryDefaults anchors (&provider, &core, &runtime, &framework, &capability, &security, &persistence, &operations, &internal, &publishedTesting) |
config/quality/module-boundaries.yml | Allowed layer edges, forbidden edges (published → internal, published → applications-examples, published → excluded), self-edges, and cycles |
./gradlew verify060Architecture verifies the catalog against the actual Gradle projects, the published artifact set, and BOM membership. Adding a module without a catalog entry — or with a classification that does not match reality — fails that gate.
Where To Start Reading
These guides cover repository-level changes. If you are consuming TramAI rather than extending the repository, start with the extension guides instead — they cover the same surfaces from the outside:
- Custom Providers — the
ModelProviderSPI and explicit registration - Custom Interceptors — operation, DLP, and engine-event hooks
- Custom Observers — observation and telemetry surfaces
- MCP Integration — the MCP server adapter
- Testing & Observability — deterministic tests against the shipped testing module
Two deep dives give the context these guides assume:
- Module Architecture — the 0.6.0 ten-layer topology, the machine-readable authorities, and the boundary rules
- Quality Gates — how the gates named in these guides are composed, including the coverage and mutation ratchets
Non-Negotiable Rules
These apply to every guide in this section:
- Never weaken a TCK or architecture guard to make your change pass. The test is the contract.
- Never edit the analyzer baseline (
config/quality/0.6.0-baseline.json) in the same pull request as a behaviour change. - Never route a new extension around the catalog. Enrolment is architecture-enforced.
CancellationExceptionis preserved and propagated on every path. Usedev.tramai.core.coroutines.rethrowIfCancellation()incatch (e: Exception)blocks.
