When building WebUI plugin/extension systems, treat the backend as the source of truth for (1) resolving extension contents and (2) providing a stable context schema to JS extensions.

Apply these rules:

Example (contract-driven usage):

// Client: paste extension HTML resolved by backend
async function applyExtensionPoint(node, id) {
  const htmlParts = await get_webui_extensions(id); // backend contract
  node.innerHTML = htmlParts.join("\n");
}

// JS extension: rely on unified context schema
export default async function injectBranchButtons(context) {
  const msgs = context?.messages;
  if (!Array.isArray(msgs) || msgs.length === 0) return;

  for (const m of msgs) {
    // contract requires log number (no)
    if (typeof m.no !== "number") throw new Error("Missing context.messages[].no");
    // ...use m.no to wire actions
  }
}

Outcome: frontend extension code becomes deterministic (no “sometimes field is present” surprises), and plugin authors can build against a predictable backend-defined contract.