Agent skill

Sap Extension Creator

by heshengtao in heshengtao/super-agent-party

Create Super Agent Party (SAP) extensions. An agent skill from heshengtao/super-agent-party.

AGPL-3.0Auto-check passedFrontend & Design

Install Sap Extension Creator

skills CLI
$ npx skills add heshengtao/super-agent-party --skill sap-extension-creator -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install heshengtao/super-agent-party sap-extension-creator --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/heshengtao/super-agent-party.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/sap-extension-creator .claude/skills/sap-extension-creator && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
sap-extension-creator
GitHub stars
2.7k
Token cost
~6k tokens
SKILL.md length
1,583 words
Files
8 (incl. references, assets)
Skills in repo
1
Repo updated
First seen
Licence
AGPL-3.0

At a glance

Create Super Agent Party (SAP) extensions. An agent skill from heshengtao/super-agent-party.

  • Works in 6 steps: Gather Requirements → Scaffold the Extension → Write package.json → …
  • Requests like create a new SAP extension
  • SKILL.md covers Overview, Quick Decision Tree, Core Files Every Extension Needs and Workflow, plus 7 more sections
  • Runs JavaScript scripts from its folder; calls npm and node; reaches github.com and gitee.com

What it does

Sap Extension Creator is an agent skill from heshengtao/super-agent-party. Create Super Agent Party (SAP) extensions. This skill should be used when users want to create, build, or scaffold a new extension for Super Agent Party - including static HTML extensions (pure frontend) and Node.js backend extensions. Triggers on requests like "create a new SAP extension", "build an extension for Super Agent Party", "scaffold a plugin", "make a chat UI extension", or when working with sap extension projects.

Its SKILL.md is about 6k tokens, which your agent loads only when the skill is triggered. The skill folder holds 11 other files, including reference files and assets (for example `assets/node-template/index.js`, `assets/node-template/package.json` and `assets/static-template/package.json`).

It sits in Frontend & Design. It works with Node.js, npm, Model Context Protocol and ComfyUI. The repository describes itself as: ⭐ All-in-one AI companion! Super Agent Party = Self hosted neuro sama + openclaw! ⭐ 全能AI伴侣!超级智能体派对 = 自托管neuro sama + openclaw! The licence is AGPL-3.0.

When your agent uses it

  • Requests like create a new SAP extension
  • Build an extension for Super Agent Party
  • Scaffold a plugin
  • Make a chat UI extension

Example prompts

  • “create a new SAP extension”
  • “build an extension for Super Agent Party”
  • “scaffold a plugin”
  • “/sap-extension-creator”

Requirements

  • Node.js

Workflow steps

6 steps, taken from the step headings in SKILL.md.

  1. Gather Requirements
  2. Scaffold the Extension
  3. Write package.json
  4. Write index.html
  5. Write index.js (Node.js only)
  6. Implement Tool Registration (optional, works in both modes)

What it can do on your machine

Read from SKILL.md and the folder at commit bfd9309. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships script files (JavaScript), which the agent can run.

    Shell commands in SKILL.md call:

    • npm
    • node

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • github.com
    • gitee.com
    • cdnjs.cloudflare.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Sap Extension Creator loads about 6k tokens when it runs, and up to ~8.6k if it reads all its reference files. Until then it costs about 113 tokens; SKILL.md has 1,583 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~113
When it runs · the whole SKILL.md, loaded when a task matches
~6k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~8.6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from heshengtao/super-agent-party at commit bfd9309, republished under its AGPL-3.0 licence (© heshengtao). 1,583 words, ~6,038 tokens.

Download SKILL.mdSave it as .claude/skills/sap-extension-creator/SKILL.md (or your agent's skills folder). This skill also uses 7 other files; get the full folder from GitHub.
name
sap-extension-creator
description
Create Super Agent Party (SAP) extensions. This skill should be used when users want to create, build, or scaffold a new extension for Super Agent Party - including static HTML extensions (pure frontend) and Node.js backend extensions. Triggers on requests like "create a new SAP extension", "build an extension for Super Agent Party", "scaffold a plugin", "make a chat UI extension", or when working with sap extension projects.

SAP Extension Creator

Overview

Create Super Agent Party extensions—self-contained packages that extend the platform with custom chat UI and tools. Two modes are supported:

  • Static extension: Pure HTML/CSS/JS frontend, served directly by SAP from the extension folder
  • Node.js extension: Full-stack with Express backend, auto-managed by SAP (npm install + node index.js <port>)

Both modes support MCP tool registration (the register_node_extension_mcp protocol message works for ANY extension via WebSocket, despite the "node" in its name).

Quick Decision Tree

User wants to create an extension?
├─ Only needs UI (chat, display, simple interactions)? → Static Extension
└─ Needs backend logic (API calls, DB, file processing)? → Node.js Extension

Core Files Every Extension Needs

FileRequiredPurpose
package.json✅Metadata, dependencies, window config
index.html✅Main UI (full HTML page, single-file app)
index.jsNode onlyNode.js entry point
node_modules/Node onlyAuto-installed by SAP via npm install

Workflow

Step 1: Gather Requirements

Ask the user:

  1. Extension name? (hyphen-case, e.g., my-weather-widget)
  2. Description? (one sentence)
  3. Static or Node.js? (Node.js only if backend logic/server-side code is needed)
  4. For Node.js: what npm dependencies?
  5. Should it register custom tools for the AI? (works in both static and Node.js modes via WebSocket MCP)
  6. GitHub repository URL? (optional, for updates)
  7. Transparent window? (frameless, always-on-top — for mini widgets like music controllers)
  8. Default window size? (width/height in pixels)
Step 2: Scaffold the Extension

Use the templates in assets/ as starting points:

  • Static: Copy assets/static-template/
  • Node.js: Copy assets/node-template/

Create the extension directory under the workspace (user will later install it into SAP's extensions/ folder).

Step 3: Write package.json

See references/package-json-spec.md for the complete field reference. Minimum:

json
{
  "name": "my-extension",
  "version": "1.0.0",
  "description": "What it does",
  "author": "your-name",
  "repository": "https://github.com/user/repo",
  "backupRepository": "https://gitee.com/user/repo",
  "category": "Tools"
}

For Node.js extensions, also include:

json
{
  "main": "index.js",
  "nodePort": 0,
  "dependencies": { "express": "^5.1.0" }
}

For transparent/frameless widgets (e.g., mini music controllers, floating panels):

json
{
  "transparent": true,
  "width": 280,
  "height": 80
}

When transparent: true, SAP creates a frameless, transparent, always-on-top window (see main.js open-extension-window handler). Use this for compact overlay widgets.

Step 4: Write index.html

The HTML page is rendered inside an Electron BrowserWindow (either directly or via an iframe). Key patterns:

  • Self-contained: The extension is a single HTML file with all CSS/JS inlined or loaded from CDN. For Node.js extensions, static assets are served from the extension directory.
  • Font Awesome: Use CDN to ensure reliable loading in both static and Node.js modes:
    html
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    Avoid relative paths like ../../fontawesome/ — these may work for static extensions but break for Node.js extensions (different serving paths).
  • Dark/Light mode: Always support both (see "Theme & i18n" section below).
  • i18n (Chinese/English): Always support bilingual UI (see "Theme & i18n" section below).
  • WebSocket connection: Connect to ws://host/ws for messaging and MCP.
  • Extension ID: Parse window.location.pathname for /extensions/{ext_id}/.
  • Message rendering: Listen for messages_update and broadcast_messages events.
  • Send user input: Send set_user_input then trigger_send_message.
Step 5: Write index.js (Node.js only)

See references/node-entry-spec.md for the full protocol. The entry point:

  1. Receives a port number via process.argv[2]
  2. Starts an Express server on that port at 127.0.0.1
  3. Serves static files from its own directory
  4. Exposes a /health endpoint for readiness checks
  5. SAP reverse-proxies requests to the extension
Step 6: Implement Tool Registration (optional, works in both modes)

Extensions can register tools that the AI agent can call — via WebSocket in the frontend (both static and Node.js). The MCP lifecycle has three mandatory stages:

STARTUP  → ws.onopen         → registerMcpTools()
RUNTIME  → ws.onmessage      → handleMcpCall() when AI calls a tool
SHUTDOWN → window.beforeunload → unregisterMcpTools()

① Register on startup — always in ws.onopen, using a dedicated function:

js
function registerMcpTools() {
  getExtId();
  ws.send(JSON.stringify({
    type: 'register_node_extension_mcp',
    data: {
      ext_id: MY_EXT_ID,
      tools: [{
        name: `${MY_EXT_ID}_my_tool`,
        description: 'What this tool does (use the user\'s language)',
        parameters: {
          type: 'object',
          properties: {
            param1: { type: 'string', description: '...' }
          },
          required: ['param1']
        }
      }]
    }
  }));
}

② Handle tool calls — the AI agent calls your tool:

js
async function handleMcpCall(data) {
  const { ext_id, tool_name, tool_params, call_id } = data;
  if (ext_id !== MY_EXT_ID && !tool_name.includes(MY_EXT_ID)) return;
  // ... execute logic, then:
  ws.send(JSON.stringify({
    type: 'mcp_tool_result',
    data: { call_id, result: 'output' }
  }));
}

③ Unregister on shutdown — MUST send unregister_node_extension_mcp before the window closes:

js
function unregisterMcpTools() {
  if (ws && ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({ type: 'unregister_node_extension_mcp', data: { ext_id: MY_EXT_ID } }));
  }
}
window.addEventListener('beforeunload', () => { unregisterMcpTools(); });

Key rule: Registration and unregistration MUST be in separate named functions (registerMcpTools / unregisterMcpTools), NOT inline code. This makes the lifecycle explicit and easy for AI to understand.

If an extension has no MCP tools, all three functions can be deleted.

See sap-lx-music/index.html for a complete real-world MCP implementation example (static extension with 12+ registered tools).


Theme & i18n (Dark/Light Mode + Bilingual)

Every extension should support dark/light mode and Chinese/English bilingual UI. Do NOT hardcode a single theme color scheme — use CSS variables so each extension can have its own identity.

CSS Variable Pattern

Define light theme in :root and override in body.dark:

css
:root {
  --bg: #ffffff;
  --bg-secondary: #f5f5f5;
  --text: #333333;
  --text-sub: #888888;
  --accent: #ec4141;        /* extension's own brand color */
  --accent-hover: #d73a3a;
  --border: rgba(0,0,0,0.08);
  --transition: 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", sans-serif;
}

body.dark {
  --bg: #2b2b2b;
  --bg-secondary: #222222;
  --text: #e0e0e0;
  --text-sub: #888888;
  --border: rgba(255,255,255,0.06);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
  height: 100%; font-family: var(--font);
  background: var(--bg); color: var(--text);
  transition: background var(--transition);
}
Dark Mode Toggle
js
function initTheme() {
  const saved = localStorage.getItem('myext_dark');
  if (saved === 'dark' || (!saved && matchMedia('(prefers-color-scheme:dark)').matches)) {
    document.body.classList.add('dark');
  }
}

function toggleDarkMode() {
  const isDark = document.body.classList.toggle('dark');
  localStorage.setItem('myext_dark', isDark ? 'dark' : 'light');
}
i18n Pattern
js
const i18n = {
  zh: {
    welcome: '欢迎使用我的扩展',
    send: '发送',
    // ... all UI strings
  },
  en: {
    welcome: 'Welcome to My Extension',
    send: 'Send',
    // ...
  }
};

let lang = localStorage.getItem('myext_lang') || 'zh';
function t(k) { return i18n[lang]?.[k] || i18n.zh[k] || k; }

function toggleLanguage() {
  lang = lang === 'zh' ? 'en' : 'zh';
  localStorage.setItem('myext_lang', lang);
  updateAllTexts();  // re-render all i18n-dependent UI
}

When registering MCP tools, set description and parameters in the current user's language for better AI interaction.


Responsive Design

Every extension should work well across different window sizes. Critical patterns:

Viewport Meta (REQUIRED)
html
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
CSS Media Queries

Use breakpoints to adapt layout at small sizes:

css
@media (max-width: 900px) {
  /* stack layouts vertically, reduce padding */
}

@media (max-width: 600px) {
  /* hide secondary elements, compact controls */
}

Key responsive practices:

  • Use vw units for widths as fallback (e.g., width: 65vw; max-width: 360px)
  • Use flex layouts with flex-wrap that naturally adapt
  • Hide non-essential elements on small screens (display: none)
  • Reduce font sizes and padding at breakpoints

iframe Compatibility

Extensions may be rendered inside an iframe (depending on SAP's configuration). Ensure:

  • Extension ID detection: Use window.location.pathname (works in both direct and iframe contexts):
    js
    function getExtId() {
      try {
        const match = window.location.pathname.match(/\/extensions\/([^\/]+)/);
        return match ? match[1] : 'unknown';
      } catch(e) { return 'unknown'; }
    }
  • WebSocket connection: Use location.host (not hardcoded):
    js
    const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
    ws = new WebSocket(`${proto}//${location.host}/ws`);
  • Window close: window.close() works in both direct and iframe contexts
  • Avoid window.top / window.parent assumptions — your extension may be the top-level window
  • Font Awesome via CDN ensures icons load regardless of serving path

Transparent Window / Compact Mode

When transparent: true is set in package.json, SAP creates a frameless transparent window. The extension must implement compact mode to work correctly.

How SAP Creates Transparent Windows

From main.js, when extension.transparent is true:

js
{
  frame: false,
  transparent: true,
  alwaysOnTop: true,
  skipTaskbar: false,
  hasShadow: false,
  backgroundColor: 'rgba(0, 0, 0, 0)',
}
Compact Mode CSS (REQUIRED for transparent extensions)
css
/* Transparent backgrounds */
body.compact { background: transparent !important; }
html.compact { background: transparent !important; }

/* Drag regions — make structural elements draggable for frameless windows */
body.compact header,
body.compact footer,
body.compact #inputBar {
  -webkit-app-region: drag;
}

/* Interactive elements MUST opt-out of drag */
body.compact button,
body.compact input,
body.compact textarea,
body.compact select,
body.compact a,
body.compact .compact-close-btn {
  -webkit-app-region: no-drag;
}

/* Compact close button (red circle, top-right) */
.compact-close-btn { display: none; }
body.compact .compact-close-btn {
  display: flex;
  position: absolute;
  top: 5px; right: 5px;
  width: 20px; height: 20px;
  background: rgb(255, 57, 57);
  border: none; border-radius: 50%;
  color: #fff;
  align-items: center; justify-content: center;
  font-size: 10px; cursor: pointer;
  transition: 0.2s;
  z-index: 100;
  -webkit-app-region: no-drag;
}
body.compact .compact-close-btn:hover { background: #ec4141; }
Compact Mode Detection (REQUIRED)
js
function checkCompactMode() {
  if (window.innerHeight < 200) {
    document.documentElement.classList.add('compact');
    document.body.classList.add('compact');
  } else {
    document.documentElement.classList.remove('compact');
    document.body.classList.remove('compact');
  }
}

function closeWindow() { window.close(); }

checkCompactMode();
window.addEventListener('resize', checkCompactMode);
Placing the Close Button

The close button HTML must be placed at the body level (not nested inside containers), typically right after <body>:

html
<body>
  <button class="compact-close-btn" onclick="closeWindow()" title="关闭窗口">
    <i class="fa-solid fa-xmark"></i>
  </button>
  <!-- rest of content -->
</body>

For transparent mini-widgets, you can also place the close button inside a content container and make it visible on hover — see sap-lx-music for this pattern.


Using iframes for Custom URL Schemes

If your extension needs to invoke custom protocol URLs (e.g., lxmusic://, myapp://), use a hidden iframe technique:

js
function invokeScheme(url) {
  let iframe = document.getElementById('scheme-invoker');
  if (!iframe) {
    iframe = document.createElement('iframe');
    iframe.id = 'scheme-invoker';
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
  }
  iframe.src = url;
}

This avoids window.open() popup blockers and works reliably inside Electron.


Show full SKILL.md (674 more words)Show less

WebSocket Protocol Reference

Message TypeDirectionPurpose
get_messages→ SAPRequest current message history
messages_update← SAPMessage list updated
broadcast_messages← SAPBroadcast message update
set_user_input→ SAPUpdate user input text
trigger_send_message→ SAPSend current input as user message
trigger_clear_message→ SAPClear all messages
register_node_extension_mcp→ SAPRegister MCP tools (works for static AND Node.js)
unregister_node_extension_mcp→ SAPUnregister on page close
mcp_registered← SAPConfirmation of registration
call_mcp_tool← SAPAI agent calls a registered tool
mcp_tool_result→ SAPReturn tool execution result
trigger_close_extension→ SAPRequest extension window close

Simple Chat HTTP API (/simple_chat)

SAP exposes a stateless HTTP endpoint POST /simple_chat that extensions can call for one-off AI tasks — translation, summarization, quick Q&A, code generation — without going through the WebSocket chat flow and without adding messages to the conversation history.

This is ideal when your extension needs a quick, single-turn AI call: translate text, summarize content, extract keywords, classify input, etc.

When to Use /simple_chat vs WebSocket
Feature/simple_chat HTTP APIWebSocket (trigger_send_message)
Conversation history❌ Stateless — no history✅ Full chat history
Messages shown in UI❌ Not added to chat✅ Rendered in message list
Use caseOne-off: translate, summarize, classifyMulti-turn chat, agent tasks
Response formatOpenAI-compatible JSON / NDJSON streammessages_update / broadcast_messages events
SpeedUses SAP's fast client configUses current active model provider
Endpoint
POST /simple_chat
Content-Type: application/json

The endpoint is on the same origin as the extension, so use a relative URL:

js
const res = await fetch('/simple_chat', { ... });
Request Format
json
{
  "messages": [
    { "role": "system", "content": "You are a professional translator." },
    { "role": "user", "content": "Translate 'Hello world' to Chinese." }
  ],
  "stream": false,
  "temperature": 0.7
}
FieldTypeRequiredDescription
messagesarray✅Array of {role, content} objects (system/user/assistant)
streamboolean❌ (default false)true for streaming, false for one-shot JSON response
temperaturenumber❌ (default from settings)0–2, lower = more deterministic
Non-Streaming Response (stream: false)

Returns a standard OpenAI-compatible ChatCompletion JSON object:

json
{
  "id": "chatcmpl-xxx",
  "object": "chat.completion",
  "created": 1234567890,
  "model": "gpt-4o",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "你好世界"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 20,
    "completion_tokens": 5,
    "total_tokens": 25
  }
}

Access the result: data.choices[0].message.content

Streaming Response (stream: true)

Returns NDJSON (one JSON object per line), matching OpenAI's streaming format. Each line contains a delta chunk:

{"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
{"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"你好"},"finish_reason":null}]}
{"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"世界"},"finish_reason":null}]}
{"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

Note: The stream does NOT send a [DONE] marker. Detect completion by checking choices[0].finish_reason.

JavaScript Usage Examples
Non-Streaming (Simple One-Shot Call)
js
/**
 * Call SAP's /simple_chat for a one-off AI task.
 * @param {Array} messages - [{role, content}, ...]
 * @param {number} [temperature=0.7]
 * @returns {Promise<object>} OpenAI-compatible ChatCompletion
 */
async function simpleChat(messages, temperature = 0.7) {
  const res = await fetch('/simple_chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ messages, stream: false, temperature })
  });
  if (!res.ok) {
    const err = await res.json();
    throw new Error(err.error?.message || `HTTP ${res.status}`);
  }
  return await res.json();
}

// ---------- Practical Examples ----------

// Translation
async function translate(text, targetLang = 'Chinese') {
  const res = await simpleChat([
    { role: 'system', content: `You are a translator. Translate to ${targetLang}. Reply ONLY with the translation, no explanations.` },
    { role: 'user', content: text }
  ]);
  return res.choices[0].message.content;
}

// Summarization
async function summarize(text, maxWords = 50) {
  const res = await simpleChat([
    { role: 'system', content: `Summarize in ≤${maxWords} words. Reply ONLY with the summary.` },
    { role: 'user', content: text }
  ]);
  return res.choices[0].message.content;
}

// Quick classification
async function classify(text, labels) {
  const res = await simpleChat([
    { role: 'system', content: `Classify into one of: ${labels.join(', ')}. Reply ONLY with the label.` },
    { role: 'user', content: text }
  ]);
  return res.choices[0].message.content.trim();
}
Streaming (Real-Time Display)
js
/**
 * Call /simple_chat with streaming. Yields delta content strings.
 * @param {Array} messages
 * @param {number} [temperature=0.7]
 * @returns {AsyncGenerator<string>} Yields delta content chunks
 */
async function* simpleChatStream(messages, temperature = 0.7) {
  const res = await fetch('/simple_chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ messages, stream: true, temperature })
  });
  if (!res.ok) {
    const err = await res.json();
    throw new Error(err.error?.message || `HTTP ${res.status}`);
  }

  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  let buf = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buf += decoder.decode(value, { stream: true });
    const lines = buf.split('\n');
    buf = lines.pop();  // keep incomplete line in buffer
    for (const line of lines) {
      if (!line.trim()) continue;
      try {
        const chunk = JSON.parse(line);
        const content = chunk.choices?.[0]?.delta?.content;
        if (content) yield content;
        if (chunk.choices?.[0]?.finish_reason === 'stop') return;
      } catch(e) { /* ignore parse errors for partial lines */ }
    }
  }
}

// Usage: render streaming response into an element
const el = document.getElementById('output');
el.textContent = '';
for await (const chunk of simpleChatStream([
  { role: 'user', content: 'Write a haiku about coding.' }
])) {
  el.textContent += chunk;
}
Error Handling

On error, the endpoint returns a JSON object with an error field:

json
{
  "error": {
    "message": "No model providers configured",
    "type": "server_error",
    "code": 500
  }
}

Always check res.ok and parse the error body.

Important Notes for /simple_chat
  • Stateless: Each call is independent. No conversation context is preserved between calls.
  • No UI impact: Results are NOT displayed in the main chat window. Your extension owns the rendering.
  • Uses fast client: The endpoint uses SAP's "fast" model provider configuration. This may be a different model than the main chat.
  • Same origin only: Extensions are served from the same origin, so no CORS issues. Use a relative URL (/simple_chat).
  • Not a replacement for MCP tools: If you need the AI agent to call your extension, register MCP tools via WebSocket. /simple_chat is for your extension to call the AI, not the other way around.

Important Notes

  • Extension ID format: {owner}_{repo} (e.g., heshengtao_sap-example)
  • nodePort: 0 means auto-assign a free port (3100-13999 range)
  • Always register beforeunload handler to send unregister_node_extension_mcp
  • MCP works in both static and Node.js extensions — the register_node_extension_mcp message type name is historical; it works over WebSocket from any extension. Always follow the three-stage lifecycle: registerMcpTools() on WS open, handleMcpCall() on tool call, unregisterMcpTools() on beforeunload
  • Font Awesome: Always use CDN (cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css). Relative paths like ../../fontawesome/ do NOT work for Node.js extensions (they're served from Express, not from SAP's static directory)
  • Theme colors: Each extension defines its own identity via CSS variables on :root and body.dark. Do NOT force SAP's theme colors
  • Always implement dark/light mode and Chinese/English i18n as basic functionality
  • Transparent windows: Always implement compact mode. Without -webkit-app-region: drag, frameless windows cannot be moved. Without -webkit-app-region: no-drag on interactive elements, buttons become unclickable
  • Close button: For transparent/frameless windows, the extension MUST provide its own close button since there's no native title bar

Reference Implementations

Study these real extensions for patterns:

  • sap-lx-music — Static extension with MCP, transparent compact mode, dark/light theme, i18n, custom scheme invocation
  • sap-example (heshengtao_sap-example) — Basic static chat UI extension
  • sap-example-with-node (heshengtao_sap-example-with-node) — Node.js extension with Express backend

Resources

assets/
  • assets/static-template/ — Complete starter template for static extensions
  • assets/node-template/ — Complete starter template for Node.js extensions
references/
  • references/package-json-spec.md — Complete package.json field reference
  • references/node-entry-spec.md — Node.js entry point and lifecycle specification

© heshengtao, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 7 other files (references, assets) in skills/sap-extension-creator of heshengtao/super-agent-party.

  • SKILL.md
  • assets/node-template/index.html
  • assets/node-template/index.js
  • assets/node-template/package.json
  • assets/static-template/index.html
  • assets/static-template/package.json
  • references/node-entry-spec.md
  • references/package-json-spec.md

Open the folder on GitHubat commit bfd9309

Compare with similar skills

Sap Extension Creator next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Sap Extension Creator compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Sap Extension Creator this skillheshengtao/super-agent-party2.7k—~6kAutomated safety check: PassAGPL-3.0
Managing MCP IndexComfy-Org/workflow_templates1.3k—~1.9kAutomated safety check: NotesMIT
Create Docsvictorgarciaesgi/nuxt-typed-router4132 repos~2.8kAutomated safety check: PassMIT
Frontend Build Timing Auditopenops-cloud/openops1.1k—~2.3kAutomated safety check: PassCustom licence
Better Iconsdtsola/xiaoyaosearch1k2 repos~895Automated safety check: PassCustom licence
Orchardcore Asset ManagerOrchardCMS/OrchardCore8.2k—~1.5kAutomated safety check: PassBSD-3-Clause

Similar skills

  • Managing MCP Index

    Comfy-Org/workflow_templates

    Builds and maintains templates/index.mcp.json for Comfy Cloud MCP tools.

    1.3k GitHub stars~1.9k tokensUpdated today
    Frontend & DesignAuto-check: notes
  • Create Docs

    victorgarciaesgi/nuxt-typed-router

    Create complete documentation sites for projects. An agent skill from victorgarciaesgi/nuxt-typed-router.

    413 GitHub starsUsed in 2 repos~2.8k tokens
    Frontend & DesignAuto-check passed
  • Frontend Build Timing Audit

    openops-cloud/openops

    Detects and diagnoses chunk-evaluation timing bugs in the Vite/rolldown production build of react-ui (works-in-dev / broken-in-build i18n regressions, missing UI labels, module-scope t()…

    1.1k GitHub stars~2.3k tokensUpdated yesterday
    Frontend & DesignAuto-check passed
  • Better Icons

    dtsola/xiaoyaosearch

    Searches more than 200 Iconify icon libraries and fetches icons as SVG from a command line tool or an MCP server.

    1k GitHub starsUsed in 2 repos~895 tokens
    Frontend & DesignAuto-check passed
  • Orchardcore Asset Manager

    OrchardCMS/OrchardCore

    Builds, watches, and manages frontend assets in OrchardCore.

    8.2k GitHub stars~1.5k tokensUpdated yesterday
    Frontend & DesignAuto-check passed
  • Extract Design System

    arvindrk/extract-design-system

    Extract design primitives from a public website and generate starter token files for your project.

    237 GitHub starsUsed in 1 repo~514 tokens
    Frontend & DesignAuto-check passed

Questions about Sap Extension Creator

What does Sap Extension Creator do?

Create Super Agent Party (SAP) extensions. An agent skill from heshengtao/super-agent-party. Sap Extension Creator is an agent skill from heshengtao/super-agent-party. Create Super Agent Party (SAP) extensions.

When should I use Sap Extension Creator?

Sap Extension Creator fits situations like: requests like create a new SAP extension; build an extension for Super Agent Party; scaffold a plugin; make a chat UI extension.

How do I install Sap Extension Creator in Claude Code?

Run `npx skills add heshengtao/super-agent-party --skill sap-extension-creator -a claude-code`. Or copy the skill folder (skills/sap-extension-creator in heshengtao/super-agent-party) into .claude/skills/sap-extension-creator in your project. Claude Code loads it when a task matches its description.

How do I install Sap Extension Creator in Codex?

Run `npx skills add heshengtao/super-agent-party --skill sap-extension-creator -a codex`. Or copy the skill folder (skills/sap-extension-creator in heshengtao/super-agent-party) into .agents/skills/sap-extension-creator in your project. Codex loads it when a task matches its description.

Can I use Sap Extension Creator in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add heshengtao/super-agent-party --skill sap-extension-creator -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/sap-extension-creator, .gemini/skills/sap-extension-creator, .github/skills/sap-extension-creator and .opencode/skills/sap-extension-creator in your project.

What does Sap Extension Creator need to run?

Going by SKILL.md and its folder, Sap Extension Creator needs JavaScript for the scripts in its folder and the command-line tools its instructions call (npm and node). Our summary lists: Node.js.

Does Sap Extension Creator access the network?

SKILL.md names 3 domains. In commands or code: github.com, gitee.com and cdnjs.cloudflare.com; the agent is likely to contact these when it follows the instructions. This is read from the text; nothing was executed.

Is Sap Extension Creator safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Sap Extension Creator use?

Sap Extension Creator is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Sap Extension Creator use?

About 6k tokens (SKILL.md is roughly 24k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 2.6k tokens, read only when the agent opens those files.

What are the alternatives to Sap Extension Creator?

Skills that share tags, products or a category with Sap Extension Creator: Managing MCP Index (Comfy-Org/workflow_templates, 1.3k stars), Create Docs (victorgarciaesgi/nuxt-typed-router, 413 stars), Frontend Build Timing Audit (openops-cloud/openops, 1.1k stars) and Better Icons (dtsola/xiaoyaosearch, 1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Sap Extension Creator?

heshengtao (a GitHub user) maintains it in heshengtao/super-agent-party, which has 2,728 GitHub stars. The repository was last updated on October 10, 2026.

Source: heshengtao/super-agent-party on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.