fix(custom-widgets): remove tools from copied prompt

This commit is contained in:
Thomas Camlong committed 2026-07-20 19:01:24 +02:00
1 parent 48f73d919d
commit 1e56ed5884
7 files changed
+36 -59

No files matched your search

+7 -17
View File
@@ -1,6 +1,6 @@
---
name: homarr-custom-widget
description: Author, validate, preview, and install safe Homarr Custom JSX v2 widgets from API documentation. Use when creating or fixing Homarr custom widgets, including multi-source dashboards, queries, actions, options, temporary inputs, and Mantine JSX.
description: Author safe Homarr Custom JSX v2 widgets from API documentation. Use when creating or fixing Homarr custom widgets, including multi-source dashboards, queries, actions, options, temporary inputs, and Mantine JSX.
license: Apache-2.0
metadata:
version: "2.0.0"
@@ -10,22 +10,12 @@ metadata:
Create one widget at a time. Repeat the workflow when the user asks for several widgets; do not invent packs or shared connections.
## Standalone workflow
## Authoring workflow
When Homarr MCP tools and `homarr://` resources are unavailable, continue offline using this skill and the supplied authoring prompt. Do not search repeatedly for missing tools, stop, or ask whether to proceed. Produce the requested credential-free manifest and JSX directly, without claiming they were validated, previewed, or installed. The user will paste them into Homarr and return any diagnostics for correction.
## Connected workflow
Use this workflow only when the Homarr MCP tools and resources are actually available:
1. Get `homarr-custom-widget-author`, then read `homarr://custom-widgets/schema` and `homarr://custom-widgets/components`.
2. Read the API documentation supplied by the user. Ask for missing base URLs and credentials only when needed.
3. Build one `homarr-custom-widget-v2` document. Keep credentials outside the document.
4. Call `customWidget_validate`, fix every error, and treat advisory Mantine prop warnings as review items.
5. Call `customWidget_previewCreate`, then test load/manual queries with `customWidget_previewQuery` and actions with `customWidget_previewAction`.
6. If credentials are missing, call `customWidget_secretRequestUser`. Use `customWidget_secretSet` only when the user already supplied a credential and the tool is authorized.
7. Inspect the preview URL and `customWidget_previewJournal`. Patch JSX with `customWidget_templatePatch` or update the draft and repeat.
8. Call `customWidget_create` only after validation and preview pass. Continue with the next widget independently.
1. Read the API documentation supplied by the user. Ask for a missing base URL only when it cannot be inferred safely.
2. Build one credential-free `homarr-custom-widget-v2` manifest and one safe JSX template.
3. Return the complete manifest and JSX in the exact fenced-block format requested by the authoring prompt.
4. When the user supplies Homarr diagnostics, correct every reported issue while preserving unrelated fields.
## Output rules
@@ -37,4 +27,4 @@ Use this workflow only when the Homarr MCP tools and resources are actually avai
- Include responsive loading, empty, error, and success states.
- Keep actions explicit, permission-scoped, confirmed when destructive, and followed by targeted invalidation.
When connected through MCP, use the live schema, component, example, and skill resources. If live resources are unavailable, follow this document and the authoring prompt; do not assume access to repository-relative files.
Follow this document and the supplied authoring prompt as the complete authoring reference. Do not assume access to repository-relative files.
@@ -12,6 +12,8 @@ Install the Agent Skill directly from the verified Homarr repository:
npx skills add https://github.com/homarr-labs/homarr --skill homarr-custom-widget
```
The portable skill is a tool-agnostic authoring reference. Connected workflow and tool instructions come from Homarr's native MCP prompt instead, so the same complete skill can also be embedded safely in the UI's offline copy/paste prompt.
The source lives at [`.agents/skills/homarr-custom-widget`](https://github.com/homarr-labs/homarr/tree/dev/.agents/skills/homarr-custom-widget). There is no ZIP archive. After the skill exists on the repository's default branch, run the command once to register installation activity, verify the skills.sh page, and request official maker attribution for `homarr-labs` through skills.sh. Repository code cannot grant that attribution itself.
## MCP discovery
@@ -20,7 +20,7 @@ The **Schema** action beside Undo, Redo, and Format expands the generated JSON S
## ChatGPT copy/paste
Enter a short request and optional API documentation URL, then select **Copy AI prompt**. Its dropdown also offers a self-contained version with the Custom Widget skill embedded for models that cannot discover skills or MCP resources. The copied text starts with your request and repeats it as the final instruction so it cannot be lost behind the authoring reference. The embedded version explicitly uses a standalone workflow: the model must author immediately without searching for Homarr MCP tools or claiming that it validated the result. Paste either prompt into ChatGPT or another model. The model must return exactly:
Enter a short request and optional API documentation URL, then select **Copy AI prompt**. Its dropdown also offers a self-contained version with the complete Custom Widget authoring skill embedded. Both copied prompts are strictly offline authoring references: they contain no MCP resource names, tool calls, or connected-workflow instructions. Paste either prompt into ChatGPT or another model. The model must return exactly:
1. A fenced `json` block with one complete widget and `template: "__HOMARR_TEMPLATE__"`.
2. A fenced `jsx` block with the readable template.
+6 -13
View File
@@ -6,7 +6,7 @@ const AUTHORING_PROMPT = `You create Homarr Custom JSX v2 widgets. Return exactl
Use $schema "homarr-custom-widget-v2". A widget contains metadata, inline API sources, named requests, an options schema, defaults, and one JSX template. Never include credentials. Use one source named "default" unless the widget genuinely combines APIs.
This Homarr release uses Mantine ${CUSTOM_WIDGET_MANTINE_VERSION}. When connected, read homarr://custom-widgets/schema and homarr://custom-widgets/components instead of guessing the installed surface.
This Homarr release uses Mantine ${CUSTOM_WIDGET_MANTINE_VERSION}. Use only the Homarr runtime components and Mantine capabilities described in this prompt and its embedded skill.
Queries and actions may use GET, POST, PUT, PATCH, or DELETE. Set kind to query for reads and action for user-triggered changes. Actions never use trigger "load". Declare every path, query, or body parameter. Use {name} in paths and {"$param":"name"} in query/body templates. Every declared parameter needs an explicit value source: SubFetch, ActionButton, and ToggleSwitch supply manual request values through their params prop; every load-query parameter must have an optionsBinding entry containing {"$option":"optionName"} or a primitive literal. Never infer a binding from matching names. Use load-triggered query results through data.<requestId>.
@@ -51,24 +51,17 @@ export function buildCustomWidgetAiPrompt(
embeddedSkill?: string,
) {
const requestedWidget = redactText(request?.trim() || "Describe the widget you want to create.");
const sections = [`# User request\n\n${requestedWidget}`];
const sections = [`Please create this Homarr Custom JSX v2 widget:\n\n${requestedWidget}`];
if (documentationUrl) sections.push(`API documentation: ${redactUrl(documentationUrl)}`);
if (embeddedSkill) {
sections.push(`## Execution mode: standalone copy/paste
You do not have to connect to Homarr MCP or access any \`homarr://\` resource to complete this request. Do not search for unavailable Homarr tools, do not stop because they are unavailable, and do not ask whether to proceed. Author the best valid widget you can from the instructions embedded below. Do not claim that you validated, previewed, or installed it; the user will paste your two output blocks into Homarr for validation.`);
}
sections.push(AUTHORING_PROMPT);
if (embeddedSkill) sections.push(`## Embedded Homarr Custom Widget skill\n\n${embeddedSkill}`);
if (embeddedSkill) sections.push(`Use this complete Homarr Custom Widget authoring skill:\n\n${embeddedSkill}`);
if (rawResponse) sections.push(`Sample API response:\n\n\`\`\`json\n${redactResponse(rawResponse)}\n\`\`\``);
if (currentConfig) {
sections.push(`Current widget:\n\n\`\`\`json\n${JSON.stringify(redactValue(currentConfig), null, 2)}\n\`\`\``);
}
sections.push(`## Produce the response now
Create this widget: ${requestedWidget}
Return exactly one complete \`json\` fenced block and one complete \`jsx\` fenced block as specified above. Do not respond with a plan, a refusal, a tool-access warning, or a question.`);
sections.push(
`Create the requested widget now and return exactly one complete \`json\` fenced block followed by one complete \`jsx\` fenced block. Homarr will validate the result after it is pasted into the workbench.`,
);
const prompt = sections.join("\n\n");
return embeddedSkill ? prompt : prompt.slice(0, 8_000);
}
@@ -15,7 +15,7 @@ export const CUSTOM_WIDGET_SKILL_INSTALL_COMMAND =
export const CUSTOM_WIDGET_SKILL_MD = `---
name: homarr-custom-widget
description: Author, validate, preview, and install safe Homarr Custom JSX v2 widgets from API documentation. Use when creating or fixing Homarr custom widgets, including multi-source dashboards, queries, actions, options, temporary inputs, and Mantine JSX.
description: Author safe Homarr Custom JSX v2 widgets from API documentation. Use when creating or fixing Homarr custom widgets, including multi-source dashboards, queries, actions, options, temporary inputs, and Mantine JSX.
license: Apache-2.0
metadata:
version: "2.0.0"
@@ -25,22 +25,12 @@ metadata:
Create one widget at a time. Repeat the workflow when the user asks for several widgets; do not invent packs or shared connections.
## Standalone workflow
## Authoring workflow
When Homarr MCP tools and \`homarr://\` resources are unavailable, continue offline using this skill and the supplied authoring prompt. Do not search repeatedly for missing tools, stop, or ask whether to proceed. Produce the requested credential-free manifest and JSX directly, without claiming they were validated, previewed, or installed. The user will paste them into Homarr and return any diagnostics for correction.
## Connected workflow
Use this workflow only when the Homarr MCP tools and resources are actually available:
1. Get \`homarr-custom-widget-author\`, then read \`homarr://custom-widgets/schema\` and \`homarr://custom-widgets/components\`.
2. Read the API documentation supplied by the user. Ask for missing base URLs and credentials only when needed.
3. Build one \`homarr-custom-widget-v2\` document. Keep credentials outside the document.
4. Call \`customWidget_validate\`, fix every error, and treat advisory Mantine prop warnings as review items.
5. Call \`customWidget_previewCreate\`, then test load/manual queries with \`customWidget_previewQuery\` and actions with \`customWidget_previewAction\`.
6. If credentials are missing, call \`customWidget_secretRequestUser\`. Use \`customWidget_secretSet\` only when the user already supplied a credential and the tool is authorized.
7. Inspect the preview URL and \`customWidget_previewJournal\`. Patch JSX with \`customWidget_templatePatch\` or update the draft and repeat.
8. Call \`customWidget_create\` only after validation and preview pass. Continue with the next widget independently.
1. Read the API documentation supplied by the user. Ask for a missing base URL only when it cannot be inferred safely.
2. Build one credential-free \`homarr-custom-widget-v2\` manifest and one safe JSX template.
3. Return the complete manifest and JSX in the exact fenced-block format requested by the authoring prompt.
4. When the user supplies Homarr diagnostics, correct every reported issue while preserving unrelated fields.
## Output rules
@@ -52,7 +42,7 @@ Use this workflow only when the Homarr MCP tools and resources are actually avai
- Include responsive loading, empty, error, and success states.
- Keep actions explicit, permission-scoped, confirmed when destructive, and followed by targeted invalidation.
When connected through MCP, use the live schema, component, example, and skill resources. If live resources are unavailable, follow this document and the authoring prompt; do not assume access to repository-relative files.
Follow this document and the supplied authoring prompt as the complete authoring reference. Do not assume access to repository-relative files.
`;
export function getCustomWidgetSkill() {
@@ -15,16 +15,14 @@ describe("buildCustomWidgetAiPrompt", () => {
CUSTOM_WIDGET_SKILL_MD,
);
expect(prompt.startsWith("# User request\n\nCreate a status widget")).toBe(true);
expect(prompt).toContain("## Execution mode: standalone copy/paste");
expect(prompt).toContain("Do not search for unavailable Homarr tools");
expect(prompt).toContain("## Embedded Homarr Custom Widget skill");
expect(prompt.startsWith("Please create this Homarr Custom JSX v2 widget:\n\nCreate a status widget")).toBe(true);
expect(prompt).toContain("Use this complete Homarr Custom Widget authoring skill:");
expect(prompt).toContain("# Homarr Custom Widget");
expect(prompt).toContain("When Homarr MCP tools and `homarr://` resources are unavailable, continue offline");
expect(prompt).toContain("do not assume access to repository-relative files");
expect(prompt).toContain("## Authoring workflow");
expect(prompt).toContain("Do not assume access to repository-relative files");
expect(prompt).not.toContain("references/schema.md");
expect(prompt.endsWith("Do not respond with a plan, a refusal, a tool-access warning, or a question.")).toBe(true);
expect(prompt.match(/Create a status widget/g)).toHaveLength(2);
expect(prompt).not.toMatch(/\bMCP\b|homarr:\/\/|customWidget_|\btools?\b/iu);
expect(prompt.endsWith("Homarr will validate the result after it is pasted into the workbench.")).toBe(true);
});
test("is concise and describes the one-widget v2 contract", () => {
@@ -42,7 +40,10 @@ describe("buildCustomWidgetAiPrompt", () => {
expect(prompt).toContain('"optionsBinding"');
expect(prompt).toContain("Never infer a binding from matching names");
expect(prompt).toContain("Create a Portainer widget");
expect(prompt.startsWith("# User request\n\nCreate a Portainer widget")).toBe(true);
expect(prompt.startsWith("Please create this Homarr Custom JSX v2 widget:\n\nCreate a Portainer widget")).toBe(
true,
);
expect(prompt).not.toMatch(/\bMCP\b|homarr:\/\/|customWidget_|\btools?\b/iu);
expect(prompt.length).toBeLessThanOrEqual(8_000);
});
@@ -13,8 +13,9 @@ describe("custom widget Agent Skill", () => {
expect(CUSTOM_WIDGET_SKILL_MD).toBe(source);
expect(getCustomWidgetSkill().skillMd).toBe(source);
expect(source).not.toContain("references/schema.md");
expect(source).toContain("do not assume access to repository-relative files");
expect(source).toContain("When Homarr MCP tools and `homarr://` resources are unavailable, continue offline");
expect(source).toContain("Do not assume access to repository-relative files");
expect(source).toContain("## Authoring workflow");
expect(source).not.toMatch(/\bMCP\b|homarr:\/\/|customWidget_|\btools?\b/iu);
});
test("publishes repository-based skills.sh installation metadata", () => {