Built-in Session Template Overrides — Design
Goal
Allow users to customize a limited set of settings on the built-in AI Session Templates without cloning them, while still receiving upstream improvements (system prompts, tools, capabilities) on upgrade.
Scope
Editable on built-in templates: model, engine, environment.
All other fields (systemPrompt, mcpServers, allowedTools, workingDirectory, initScript,
initScriptType, welcomeMessage, initialMessage, name, description, templateId,
capabilities) remain locked. Cloning remains the escape hatch for deeper customization.
Data Model
- New Flyway migration
V2__session_template_overrides.sqlcreating tablesession_template_override: id(PK, sequence-backed, consistent with existing Panache entities)template_idVARCHAR, unique, not null — the built-in template IDmodelVARCHAR, nullableengineVARCHAR, nullableenvironmentTEXT, nullable — JSON string, same format asSessionTemplateEntity.environment- New entity
SessionTemplateOverrideEntityincore/.../entities/. - Semantics: a null field means "use the built-in default". The
environmentoverride replaces the default map (no merging). - When all three fields are null/empty after a save, the row is deleted.
- Rows whose
template_idno longer matches a built-in (e.g. a built-in removed in a later release) are ignored at read time.
Service Layer (SessionTemplateService)
getTemplate(id)andlistTemplates()return built-ins with overrides merged in. Consumers such asAssistantSessionManager.createSessionrequire no changes.- The returned
SessionTemplaterecord gainsoverriddenFields(Set<String>, values frommodel,engine,environment; empty for user templates and un-overridden built-ins). - New methods:
getOverrides(String templateId)— returns current overrides (fields may be null).setOverrides(String templateId, SessionTemplateOverrides overrides)— upserts; returns merged template.clearOverrides(String templateId)— deletes the row if present.- Errors: unknown ID → not-found exception; non-built-in ID →
IllegalArgumentException(mapped to 400).
REST API (contract-first, common/api/src/main/resources/openapi.json)
New path /assistant/templates/{templateId}/overrides (tag Assistant):
| Op | operationId | Request | Response | Errors |
|---|---|---|---|---|
| GET | getSessionTemplateOverrides |
— | 200 SessionTemplateOverrides |
404 unknown, 400 not built-in |
| PUT | updateSessionTemplateOverrides |
SessionTemplateOverrides |
200 SessionTemplate (merged) |
404, 400 |
| DELETE | deleteSessionTemplateOverrides |
— | 204 | 404, 400 |
New schema SessionTemplateOverrides:
model: string, nullableengine: string, nullableenvironment: object (string → string), nullable; values may use${secret:NAME}
SessionTemplate schema gains read-only overriddenFields: string[].
The existing PUT/DELETE /assistant/templates/{templateId} continue returning 403 for built-ins.
Implementation in AssistantResourceImpl using generated beans from io.apitomy.axiom.api.beans.
Import / Export
Overrides are not included in configuration packs. They are treated as deployment-local settings.
ImportExportService and ConfigurationPacksPage are unchanged.
UI
ui/src/config/api.ts: addSessionTemplateOverridestype,overriddenFieldsonSessionTemplate, andgetSessionTemplateOverrides/updateSessionTemplateOverrides/deleteSessionTemplateOverridesfunctions.SessionTemplateDetailPage.tsx:- For built-ins,
model,engineand the Environment tab are editable; all other fields stay read-only. - Save on a built-in calls
PUT .../overrideswith only the three fields. - Overridden fields show a "Modified" label.
- "Reset to defaults" button (shown only when
overriddenFieldsis non-empty) callsDELETEafter confirmation, then reloads. SessionTemplatesPage.tsx: built-ins with non-emptyoverriddenFieldsshow a "Customized" label next to "Built-in".
Testing (JUnit 5)
- Service: merge logic (each field individually, all fields, none), empty save deletes row,
clearOverrides, rejection of non-built-in IDs, orphaned override rows ignored. - REST: GET/PUT/DELETE happy paths, 404 unknown ID, 400 user template,
overriddenFieldspopulated inGET /assistant/templatesandGET /assistant/templates/{id}. - Session creation: a session created from an overridden built-in uses the overridden model and engine.