[GH-ISSUE #4837] [Bug] Custom Skill enabled globally but missing in @agent bubble and Workspace settings (macOS Desktop brew) #3047

Closed
opened 2026-02-22 18:32:24 -05:00 by yindo · 3 comments
Owner

Originally created by @Fywzero on GitHub (Jan 8, 2026).
Original GitHub issue: https://github.com/Mintplex-Labs/anything-llm/issues/4837

How are you running AnythingLLM?

Local development

What happened?

Description: I am unable to use a custom agent skill even though it is correctly placed in the storage folder and toggled ON in the global settings.

Environment:

OS: macOS (Mac Studio)

Installation Method: Homebrew (brew install --cask anythingllm)

Version: Latest Desktop Version

Storage Location: Default (~/Library/Application Support/anythingllm-desktop/storage)

Steps to Reproduce:

Created a custom skill folder sd-painter in storage/plugins/agent-skills/.

Added plugin.json (v1.0.0 schema) and handler.js following the Official Developer Guide.

In Global Settings -> Agent Skills, the "Sd painter" skill appears and is toggled ON.

Navigate to a Workspace (e.g., "default") -> Settings -> Agent Configuration.

Click "Configure Agent Skills".

Expected Behavior: The UI should show a list of skills (including the custom one) with checkboxes to enable them for the specific workspace.

Actual Behavior:

Clicking "Configure Agent Skills" in Workspace settings redirects me back to the Global Agent Skills page instead of showing the selection list.

Typing @agent in the chat does not show the custom skill icon/tag, even though other core skills like native-python work perfectly.

Cleaned .DS_Store and restarted the app multiple times, but the issue persists.

Code Used (plugin.json):

JSON

{
"schema": "skill-1.0.0",
"id": "sd-painter",
"version": "1.0.0",
"name": "SD Painter",
"hubId": "sd-painter",
"description": "Stable Diffusion integration",
"active": true,
"setup_args": {
"SD_URL": {"type": "string", "required": true, "input": {"type": "text", "default": "http://127.0.0.1:7860"}}
},
"call_args": {
"prompt": {"type": "string", "description": "prompt"}
}
}

Are there known steps to reproduce?

No response

Originally created by @Fywzero on GitHub (Jan 8, 2026). Original GitHub issue: https://github.com/Mintplex-Labs/anything-llm/issues/4837 ### How are you running AnythingLLM? Local development ### What happened? Description: I am unable to use a custom agent skill even though it is correctly placed in the storage folder and toggled ON in the global settings. Environment: OS: macOS (Mac Studio) Installation Method: Homebrew (brew install --cask anythingllm) Version: Latest Desktop Version Storage Location: Default (~/Library/Application Support/anythingllm-desktop/storage) Steps to Reproduce: Created a custom skill folder sd-painter in storage/plugins/agent-skills/. Added plugin.json (v1.0.0 schema) and handler.js following the Official Developer Guide. In Global Settings -> Agent Skills, the "Sd painter" skill appears and is toggled ON. Navigate to a Workspace (e.g., "default") -> Settings -> Agent Configuration. Click "Configure Agent Skills". Expected Behavior: The UI should show a list of skills (including the custom one) with checkboxes to enable them for the specific workspace. Actual Behavior: Clicking "Configure Agent Skills" in Workspace settings redirects me back to the Global Agent Skills page instead of showing the selection list. Typing @agent in the chat does not show the custom skill icon/tag, even though other core skills like native-python work perfectly. Cleaned .DS_Store and restarted the app multiple times, but the issue persists. Code Used (plugin.json): JSON { "schema": "skill-1.0.0", "id": "sd-painter", "version": "1.0.0", "name": "SD Painter", "hubId": "sd-painter", "description": "Stable Diffusion integration", "active": true, "setup_args": { "SD_URL": {"type": "string", "required": true, "input": {"type": "text", "default": "http://127.0.0.1:7860"}} }, "call_args": { "prompt": {"type": "string", "description": "prompt"} } } ### Are there known steps to reproduce? _No response_
yindo added the possible bugneeds info / can't replicateinvestigating labels 2026-02-22 18:32:24 -05:00
yindo closed this issue 2026-02-22 18:32:24 -05:00
Author
Owner

@timothycarambat commented on GitHub (Jan 8, 2026):

Is there any way you can post the plugin.json and the handler.js file that runs the skill? The bug would seemingly be indicate something going wrong with loading or execution.

If a custom skill fails to validate or load, we don't abort the agent call entirely and just log it as invalid and move on.
Since the plugin shows in the UI for skills that at least means the plugin json is being found, but something is going wrong during the bootstrap process for making it truly available to the agent flow.

That being said, I'm sure it can be a simple fix. If you can make that handler available, we can see what exactly is going wrong.

@timothycarambat commented on GitHub (Jan 8, 2026): Is there any way you can post the `plugin.json` and the `handler.js` file that runs the skill? The bug would seemingly be indicate something going wrong with loading or execution. If a custom skill fails to validate or load, we don't abort the agent call entirely [and just log it as invalid and move on.](https://github.com/Mintplex-Labs/anything-llm/blob/4841-aws-bedrock-api-key/server/utils/agents/index.js#L498-L503) Since the plugin shows in the UI for skills that at least means the plugin json is being found, but something is going wrong during the bootstrap process for making it truly available to the agent flow. That being said, I'm sure it can be a simple fix. If you can make that handler available, we can see what exactly is going wrong.
Author
Owner

@Fywzero commented on GitHub (Jan 9, 2026):

Hi @timothycarambat,

Thank you for the quick response! I'm glad to hear that the plugin.json is at least being recognized.

To help you diagnose why the bootstrap process is failing, here are the exact contents of my plugin.json and handler.js. I have ensured that the files are saved in UTF-8 encoding and the folder name matches the hubId.

  1. File Structure: ~/Library/Application Support/anythingllm-desktop/storage/plugins/agent-skills/local-sd/

plugin.json

handler.js

  1. plugin.json:

JSON

{
"schema": "skill-1.0.0",
"id": "sd-painter-final",
"version": "1.0.0",
"name": "Local Stable Diffusion",
"hubId": "sd-painter-final",
"description": "Generate images using local Stable Diffusion API",
"active": true,
"setup_args": {
"SD_URL": {
"label": "Stable Diffusion URL",
"type": "string",
"required": true,
"input": {
"type": "text",
"default": "http://127.0.0.1:7860"
}
}
},
"call_args": {
"prompt": {
"type": "string",
"description": "The prompt for image generation"
}
}
}
3. handler.js:

JavaScript

/**

  • 严格对齐 AnythingLLM 官方 handler-js 规范
    */
    async function handler(args) {
    // 1. 按照规范从 this.runtimeArgs 获取通过 UI 配置的 SD_URL
    const sdUrl = (this.runtimeArgs || {}).SD_URL;

// 2. 获取 LLM 传入的 prompt
const prompt = args?.prompt;

if (!prompt) {
return "Error: Prompt is required but was not provided.";
}

try {
// 3. 安全检查并调用 introspect (反馈给前端气泡)
if (typeof this.introspect === "function") {
this.introspect(Generating image with prompt: ${prompt});
}

// 4. 发起 fetch 请求
const response = await fetch(sdUrl ? `${sdUrl}/sdapi/v1/txt2img` : "/sdapi/v1/txt2img", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    prompt,
    steps: 20,
    width: 512,
    height: 512,
    sampler_name: "Euler a"
  })
});

if (!response.ok) {
  throw new Error(`SD API Response Error: ${response.statusText}`);
}

const data = await response.json();

if (data && data.images && data.images.length > 0) {
  // 5. 按照规范返回描述性字符串
  return `Success: Generated image for "${prompt}". Please check your Stable Diffusion outputs folder.`;
}

return "API called successfully, but no image data was returned.";

} catch (error) {
// 6. 按照规范记录错误并返回字符串
if (typeof this.logger === "function") {
this.logger(Skill Error: ${error.message});
}
return Skill execution failed: ${error.message};
}
}

// 必须使用 CommonJS 导出格式
module.exports = { handler };
I have also attached the original files below for your review. Please let me know if there are any specific logs I should check to provide more detail on the bootstrap failure.

Best regards, fywzero

plugin.json

handler.js

@Fywzero commented on GitHub (Jan 9, 2026): Hi @timothycarambat, Thank you for the quick response! I'm glad to hear that the plugin.json is at least being recognized. To help you diagnose why the bootstrap process is failing, here are the exact contents of my plugin.json and handler.js. I have ensured that the files are saved in UTF-8 encoding and the folder name matches the hubId. 1. File Structure: ~/Library/Application Support/anythingllm-desktop/storage/plugins/agent-skills/local-sd/ plugin.json handler.js 2. plugin.json: JSON { "schema": "skill-1.0.0", "id": "sd-painter-final", "version": "1.0.0", "name": "Local Stable Diffusion", "hubId": "sd-painter-final", "description": "Generate images using local Stable Diffusion API", "active": true, "setup_args": { "SD_URL": { "label": "Stable Diffusion URL", "type": "string", "required": true, "input": { "type": "text", "default": "http://127.0.0.1:7860" } } }, "call_args": { "prompt": { "type": "string", "description": "The prompt for image generation" } } } 3. handler.js: JavaScript /** * 严格对齐 AnythingLLM 官方 handler-js 规范 */ async function handler(args) { // 1. 按照规范从 this.runtimeArgs 获取通过 UI 配置的 SD_URL const sdUrl = (this.runtimeArgs || {}).SD_URL; // 2. 获取 LLM 传入的 prompt const prompt = args?.prompt; if (!prompt) { return "Error: Prompt is required but was not provided."; } try { // 3. 安全检查并调用 introspect (反馈给前端气泡) if (typeof this.introspect === "function") { this.introspect(`Generating image with prompt: ${prompt}`); } // 4. 发起 fetch 请求 const response = await fetch(sdUrl ? `${sdUrl}/sdapi/v1/txt2img` : "/sdapi/v1/txt2img", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ prompt, steps: 20, width: 512, height: 512, sampler_name: "Euler a" }) }); if (!response.ok) { throw new Error(`SD API Response Error: ${response.statusText}`); } const data = await response.json(); if (data && data.images && data.images.length > 0) { // 5. 按照规范返回描述性字符串 return `Success: Generated image for "${prompt}". Please check your Stable Diffusion outputs folder.`; } return "API called successfully, but no image data was returned."; } catch (error) { // 6. 按照规范记录错误并返回字符串 if (typeof this.logger === "function") { this.logger(`Skill Error: ${error.message}`); } return `Skill execution failed: ${error.message}`; } } // 必须使用 CommonJS 导出格式 module.exports = { handler }; I have also attached the original files below for your review. Please let me know if there are any specific logs I should check to provide more detail on the bootstrap failure. Best regards, fywzero [plugin.json](https://github.com/user-attachments/files/24522716/plugin.json) [handler.js](https://github.com/user-attachments/files/24522717/handler.js)
Author
Owner

@timothycarambat commented on GitHub (Jan 9, 2026):

Ah, easy fix! Thanks for providing the files. Here are the completed files:
handler.js
plugin.json

What i changed:

  1. Folder is wrong. hubId and the folder name must match otherwise you will see this error log in the backend logs
    [0] [AgentHandler] Imported plugin by hubId sd-painter not found in plugin directory. Skipping inclusion to agent cluster.

So you corrected path is ~/Library/Application Support/anythingllm-desktop/storage/plugins/agent-skills/sd-painter-final/

  1. Plugin JSON has issues.
    In your plugin.json you had required for SD_URL but also have a default. I removed required since there is a default.

The plugin was missing the entire entrypoint block - here is the plugin.json reference

  1. Handler.js was wrong
    The export is not module.exports = {handler} is it module.exports.runtime.handler so I changed the last line to this
    module.exports = { runtime: { handler } };

Here is the reference for that - https://docs.anythingllm.com/agent/custom/handler-js

@timothycarambat commented on GitHub (Jan 9, 2026): Ah, easy fix! Thanks for providing the files. Here are the completed files: [handler.js](https://github.com/user-attachments/files/24532852/handler.js) [plugin.json](https://github.com/user-attachments/files/24532853/plugin.json) What i changed: 1. Folder is wrong. `hubId` and the folder name **must match** otherwise you will see this error log in the backend logs `[0] [AgentHandler] Imported plugin by hubId sd-painter not found in plugin directory. Skipping inclusion to agent cluster.` So you corrected path is `~/Library/Application Support/anythingllm-desktop/storage/plugins/agent-skills/sd-painter-final/` 2. Plugin JSON has issues. In your plugin.json you had `required` for SD_URL but also have a default. I removed required since there is a default. The plugin was missing the entire `entrypoint` block - [here is the plugin.json reference](https://docs.anythingllm.com/agent/custom/plugin-json) 3. Handler.js was wrong The export is not `module.exports = {handler}` is it `module.exports.runtime.handler` so I changed the last line to this `module.exports = { runtime: { handler } };` Here is the reference for that - https://docs.anythingllm.com/agent/custom/handler-js
yindo changed title from [Bug] Custom Skill enabled globally but missing in @agent bubble and Workspace settings (macOS Desktop brew) to [GH-ISSUE #4837] [Bug] Custom Skill enabled globally but missing in @agent bubble and Workspace settings (macOS Desktop brew) 2026-06-05 14:50:00 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Mintplex-Labs/anything-llm#3047