Prompt registry
Every LLM system prompt the SDK ships (webagent narrator, planner, InlineAgent, markdown-edit, translator, STT cleanup, Dwell classifier) is registered on a process-wide registry under stable IDs. Hosts override per-locale, append site-wide reminders, or list what's registered — one API for the whole prompt surface.
Why
Before v0.2.2, prompts lived inline in each subsystem module. A host that wanted "Japanese planner prompt" or "the InlineAgent should never touch tone" had to fork the module. The registry is the "one place" for all of it.
Access
Every DotDotDuck instance exposes dddk.prompts. It's the same singleton as the module-level promptRegistry export — either works, whichever fits your import style.
import { autoInstall, promptRegistry, PROMPT_IDS } from '@perhapxin/dddk';
const dddk = autoInstall();
// Idiomatic path — via the instance
dddk.prompts.list();
// Also available as the shared singleton
promptRegistry.list();
Registered IDs
Every ID in the shipped PROMPT_IDS enum has a default. Full list:
| ID constant | String value | Owner subsystem |
|---|---|---|
INLINE_EDIT |
'inline-edit.system' |
InlineAgent — replaces a text fragment inside a longer body |
MARKDOWN_EDIT |
'markdown-edit.system' |
Markdown-doc edit tool (used by Plan runner) |
VOICE_CLEANUP |
'voice-cleanup.system' |
Voice STT cleanup — turns raw transcript into polished prose |
TRANSLATE |
'translate.system' |
Immersive-translate — inline machine translation of visible copy |
DWELL_CLASSIFY |
'dwell-classify.system' |
Dwell classifier — labels the long-pressed element + suggests actions |
PLANNER |
'planner.system' |
Planner — writes the CoT / task plan for the WebAgent |
WEBAGENT_NARRATOR |
'webagent-narrator.system' |
WebAgent narrator — the everything-prompt for the agentic loop |
WEBAGENT_COT |
'webagent-cot.system' |
WebAgent CoT variant — thinking-mode narrator |
TASK |
'task.system' |
Task runner — free-form task execution prompt |
Enumerate at runtime with dddk.prompts.list().
Override a single locale
dddk.prompts.override('inline-edit.system', 'ja', () => `
あなたはインライン編集アシスタントです。ユーザーが長いテキストの中の断片を選択し、指示を出しました…
`);
Fallback order when the SDK resolves a prompt: override(id, currentLocale) → override(id, 'en') → the SDK-registered default. So you can localise Japanese while leaving English and every other locale on the shipped default.
For prompts that consume runtime context (planner, webagent narrator, Dwell classifier), the override function receives the full context object:
dddk.prompts.override('webagent-narrator.system', 'ja', (ctx, locale) => {
// ctx is the AssemblePromptInput — brand, persona, sitemap, session, etc.
return japaneseNarratorRenderer(ctx);
});
Append site-wide reminders
append() stitches extra content on the end of the resolved prompt. It runs for every locale — useful for one-line rules that shouldn't require re-writing the whole prompt:
dddk.prompts.append('webagent-narrator.system', () => `
- Never mention pricing.
- Always cite sources.
- Refuse anything not related to Acme products.
`);
Multiple append() calls stack in registration order. Reset with dddk.prompts.reset(id) (drops overrides + appenders, keeps the SDK default).
Full API
class PromptRegistry {
registerDefault<Ctx>(id: string, render: (ctx: Ctx, locale: string) => string): void;
override<Ctx>(id: string, locale: string, render: (ctx: Ctx, locale: string) => string): void;
append<Ctx>(id: string, extra: (ctx: Ctx, locale: string) => string): void;
render<Ctx>(id: string, ctx?: Ctx, locale?: string): string;
reset(id: string): void;
has(id: string): boolean;
list(): string[];
}
registerDefault— normally you don't call this; subsystems do it at module init. Hosts wanting to ship an entirely new prompt id (e.g. a domain-specific tool) can use it.override(id, locale, render)— most common host operation. Later calls with the same(id, locale)win.append(id, extra)— join extra content to whatever renderer wins. Stacks.render(id, ctx?, locale?)— resolve to a final string.localedefaults to'en'.reset(id)— drop overrides + appenders for this id. SDK default stays.has(id)— is anything registered for this id (default or override)?list()— every registered id, sorted alphabetically.
Common patterns
Multi-locale rollout
const NARRATOR_JA = (ctx: AssemblePromptInput) => `...`;
const NARRATOR_ES = (ctx: AssemblePromptInput) => `...`;
const NARRATOR_FR = (ctx: AssemblePromptInput) => `...`;
dddk.prompts.override('webagent-narrator.system', 'ja', NARRATOR_JA);
dddk.prompts.override('webagent-narrator.system', 'es', NARRATOR_ES);
dddk.prompts.override('webagent-narrator.system', 'fr', NARRATOR_FR);
// EN + zh-TW stay on SDK defaults.
Compliance layer without touching the base prompt
const compliance = () => `
Compliance requirements:
- Never disclose user PII.
- Refuse requests to draft legal or medical opinions.
- If asked about pricing, respond: "Please contact sales@acme.com."
`;
// Apply the compliance rules to every LLM-facing prompt the SDK ships.
for (const id of dddk.prompts.list()) {
dddk.prompts.append(id, compliance);
}
Live locale switch
The registry is read at message-assembly time, not at subsystem construction. Change the site language and the next agent turn / next InlineAgent action / next translation uses the new locale's prompt automatically — no re-mount, no reload.
document.querySelector('#lang-picker')?.addEventListener('change', (e) => {
const locale = (e.target as HTMLSelectElement).value;
dddk.setLocale(locale);
// Next agent turn uses the ja / es / fr / zh-TW variant of every registered prompt.
});
Non-goals
The registry does not:
- Parse or execute the prompt. Runtime message plumbing (system role, temperature, tool schemas) still lives in the subsystem callsites.
- Cache resolved strings. Each
render(id, ctx, locale)call runs the renderer fresh — cheap enough to re-run per turn. - Store credentials or LLM provider config. That's
DotDotDuckConfig.llm/config.llm.provider.
Related
- auto-install.md — the one-line install that registers defaults for you.
- migrating.md — how to adopt the registry from v0.2.1.
- agent/ — where the WebAgent narrator + planner prompts live at the callsite.