Developer Guide
Runtime APIs
The ctx.runtime object is the extension's app-scoped toolbox for prompt instructions, artifacts, variables, memories, chat context, persona data, media resolution, and extension-owned UI.
Instruction and artifact APIs
These APIs are the bridge between extension logic and the current request. They let the extension add artifacts or prompt instructions without bypassing the host runtime.
Artifact API
emitImage(input)Add an image artifact to the app-owned gallery or inline fallback.
Artifact API
The authoring guide explicitly recommends this when the extension wants to emit an image after a tool or hook runs.
Common inputs include a generated URL or blob, an optional prompt, and source metadata such as the extension key, tool name, and display mode.
It resolves to the created artifact record instead of only fire-and-forget behavior.
Prompt API
emitPromptInstruction(instruction)Queue a full prompt-contribution object for the current round.
Prompt API
Use this when you already know the exact contribution shape you want to append, including placement and priority.
Prompt helper
appendAssistantInstruction(text, placement?, priority?)Convenience wrapper for adding plain-text prompt guidance, defaulting to system_post.
Prompt helper
This is the lighter-weight version of emitPromptInstruction(). Use it when the extension just needs to append a short instruction string.
State and context APIs
These APIs let the extension read and write runtime data that belongs to the active persona, active chat, or extension-owned persistent state.
Extension-owned state
variables.get / set / delete / listPersist JSON runtime state in user or persona scope without abusing settings.
Extension-owned state
The authoring guide recommends variables for counters, flags, disposition, and other structured scene state that should survive across turns.
Reads are non-throwing: missing keys return found: false. Writes support both scope: 'user' and scope: 'persona', plus visibility values such as private and shared.
Persona memory API
memories.create / search / deleteRead and write memories scoped to the active persona in the current chat.
Persona memory API
Use create to store a new memory, search to query relevant memories by text, and delete to remove one.
The markdown examples use this for turn-level reflection after the assistant reply is complete.
Session history API
chat.list(options)Read chronological messages from the current session with position and speaker filters.
Session history API
The authoring guide documents position values of first or last, plus speaker filters such as user, persona, both, or all.
Transcript injection
chat.sendMessage(input)Post a user, assistant, or system message into the active chat — the same path built-ins like findom and auto-advance use.
Transcript injection
Available to every extension tier. Pass { role, content }; resolves with { ok, messageId }. Returns an error result when no chat session is active.
// Inside a tool executor or lifecycle hook
await ctx.runtime.chat.sendMessage({
role: 'system',
content: 'Webhook fired — escalating heart rate alert.',
});Programmatic advance
chat.runTurn(options?)Trigger an LLM turn from extension code — the auto-advance pattern, now exposed to all extensions.
Programmatic advance
Calls into the same chat-turn runner the app uses for user messages. Omit userMessage to silently advance (no new user-visible message is added). Defaults kind to 'extension'.
onAfterAssistantMessage or async UI events (timers, webhook callbacks, settings buttons).// From onAfterAssistantMessage to silently advance the conversation
await ctx.runtime.chat.runTurn();
// Or from a UI event with a user-visible prompt
await ctx.runtime.chat.runTurn({
kind: 'extension',
userMessage: 'Schedule fired: please continue the previous instruction.',
});Active persona API
persona.get()Return the normalized persona record for the active chat.
Active persona API
Use this when extension logic needs persona metadata without duplicating that data into extension variables or settings.
Media and UI APIs
These APIs help extensions bridge from host-managed assets and modals into the custom UI or tool flows they own.
My Media bridge
media.get(mediaId) and media.getUrl(mediaId)Resolve media ids from My Media into metadata or a signed URL for direct use.
My Media bridge
The authoring guide recommends this when the user stores media ids in settings or variables and the extension needs to turn them into actual runtime assets.
media.get(...) returns metadata, while media.getUrl(...) returns a direct URL-oriented result for tags like <img> or <audio>.
const introTrack = await ctx.runtime.media.getUrl('media-id-from-settings');
if (introTrack.ok && introTrack.url) {
const audio = new Audio(introTrack.url);
await audio.play();
}Host UI bridge
ui.showModal(request)Open an app-owned modal and await the chosen action.
Host UI bridge
Use this when the extension needs a modal decision point but should still render it inside the host app's modal system instead of inventing its own overlay.
The promise resolves with the chosen action id or dismiss result, so the extension can continue its own flow after the user responds.
Transient notification
ui.toast(input)Show a non-blocking toast in the corner of the app.
Transient notification
Fire-and-forget. Pass { message, level?, durationMs?, actionLabel?, onAction? }. Levels are info, success, warning, error. Default duration is 4000 ms; pass 0 to require manual dismiss.
ctx.runtime.ui.toast({
message: 'Spotify connected',
level: 'success',
});
ctx.runtime.ui.toast({
message: 'Reconnect needed',
level: 'warning',
actionLabel: 'Open settings',
onAction: () => ctx.runtime.ui.showModal({ title: 'Spotify', body: 'Re-link your account.' }),
});