1. Problem
Prompts today live per-project. An organization with multiple projects has to configure the same prompt N times, copy-pasting with minor per-project tweaks (e.g. different brand voice notes, product-specific terminology). When the base prompt needs to change, every project must be updated individually. Users tell us this is annoying.
Baseline today: each project has its own prompt list. Prompts reference built-in fragments (translationMemory, glossary, etc.) but have no way to parameterize project-specific text — users bake it directly into the template.
2. Appetite
1 week, one developer. Tight but achievable — the data model change is small, migration is a straight copy, and the UI largely reuses existing prompt-management components (moved from project settings to organization settings).
3. Solution
Data model changes
Prompt.organization_id added; project_id removed after migration
- New entity
CustomFragment (org-scoped): name, defaultValue, organization_id
- New entity
ProjectFragmentOverride: project_id, custom_fragment_id, value
- Prompts reference custom fragments by name in the Handlebars template (same syntax as built-in fragments)
Custom fragments only have effect when referenced by an org-level prompt. Unreferenced fragments are harmless but do nothing — we don't enforce a hard constraint, the UI can surface "unused" as a hint.
Migration (one-off Liquibase changeset)
- For each existing project prompt: copy to its organization with name
"<original name> (from project <project name>)"
- The existing
set-default-prompt/{promptId} pointer per project keeps working — the promptId is unchanged, now pointing at an org-level record
Backend
- Move prompt CRUD from
/v2/projects/{projectId}/prompts to /v2/organizations/{organizationId}/prompts
- Add
/v2/organizations/{organizationId}/custom-fragments CRUD
- Add
/v2/projects/{projectId}/fragment-overrides to set override values (org defines the fragments; project only sets values)
- Default-prompt endpoint validates
prompt.organization == project.organization
- Prompt rendering resolves custom fragments as: project override value → org default value
- Scopes:
prompts.edit (org-level) — create/edit/delete org prompts and custom fragments
prompt-fragment-overrides.edit (project-level) — set project-level fragment override values
Frontend
- Move AiPrompt components from project settings to organization settings (pattern: mirror the existing
OrganizationLLMProviders layout)
- Add "Custom fragments" section in organization settings — list, edit name + default value
- Add "Prompt fragments" section in project settings — list org-level fragments with their default values and an input to override per project
- MT settings "default prompt" dropdown now lists org prompts
4. Rabbit holes
- Activity log scope: Prompt edits are tracked via
@ActivityLoggedEntity today. Org-level entities need to log against the organization, not a project. Use the same pattern as LlmProvider.
- Permission model:
- Org-level prompts and custom fragments — organization Maintainer (and above) can edit (
prompts.edit scope).
- Project-level fragment overrides — project Manager (and above) can edit (
prompt-fragment-overrides.edit scope).
- Template rendering: Custom fragment variables must not collide with built-in fragment names. Validation: reject custom fragment names matching any built-in name on save.
- Empty override value vs. "use default": An empty project override is treated as "use default", not "use empty string". UI shows placeholder = default value so it's obvious.
5. No-gos
- No dedup of migrated prompts — if 5 projects had identical prompts, the org gets 5 copies. Users clean up manually. (Most customers don't have custom prompts, so volume is low.)
- No automatic fragment extraction from existing prompt text. Refactoring old prompts into fragment-based ones is a user-driven activity.
- Projects cannot define new custom fragments — only override values of fragments defined at the organization level. Keeps the mental model simple.
- No per-fragment permissions — any project user with the
prompt-fragment-overrides.edit scope can override any fragment value.
- No cross-org prompt sharing — prompts are strictly within one organization.
6. Success criteria
- All existing project prompts migrated without user-visible breakage (MT continues to work with previously-set default prompts)
- Organizations with multiple projects can maintain a single prompt template with per-project fragment values
- Time-to-configure-new-project (for orgs with existing prompt setup) drops from "recreate the prompt" to "set a few fragment values"
1. Problem
Prompts today live per-project. An organization with multiple projects has to configure the same prompt N times, copy-pasting with minor per-project tweaks (e.g. different brand voice notes, product-specific terminology). When the base prompt needs to change, every project must be updated individually. Users tell us this is annoying.
Baseline today: each project has its own prompt list. Prompts reference built-in fragments (translationMemory, glossary, etc.) but have no way to parameterize project-specific text — users bake it directly into the template.
2. Appetite
1 week, one developer. Tight but achievable — the data model change is small, migration is a straight copy, and the UI largely reuses existing prompt-management components (moved from project settings to organization settings).
3. Solution
Data model changes
Prompt.organization_idadded;project_idremoved after migrationCustomFragment(org-scoped):name,defaultValue,organization_idProjectFragmentOverride:project_id,custom_fragment_id,valueCustom fragments only have effect when referenced by an org-level prompt. Unreferenced fragments are harmless but do nothing — we don't enforce a hard constraint, the UI can surface "unused" as a hint.
Migration (one-off Liquibase changeset)
"<original name> (from project <project name>)"set-default-prompt/{promptId}pointer per project keeps working — the promptId is unchanged, now pointing at an org-level recordBackend
/v2/projects/{projectId}/promptsto/v2/organizations/{organizationId}/prompts/v2/organizations/{organizationId}/custom-fragmentsCRUD/v2/projects/{projectId}/fragment-overridesto set override values (org defines the fragments; project only sets values)prompt.organization == project.organizationprompts.edit(org-level) — create/edit/delete org prompts and custom fragmentsprompt-fragment-overrides.edit(project-level) — set project-level fragment override valuesFrontend
OrganizationLLMProviderslayout)4. Rabbit holes
@ActivityLoggedEntitytoday. Org-level entities need to log against the organization, not a project. Use the same pattern asLlmProvider.prompts.editscope).prompt-fragment-overrides.editscope).5. No-gos
prompt-fragment-overrides.editscope can override any fragment value.6. Success criteria