---
name: panel-app-creator
description: Create or update the Panel App UI part of a NextClaw lightweight app. Use after nextclaw-app-creator selects Panel-only or Panel + Service, or when the user explicitly asks for a right-side Panel App UI, folder-based static panel, Service Actions UI, Agent-powered Panel App, React/Vite/Tailwind Panel App, or asks what a Panel App can do and which injected APIs/capabilities it can use.
description_zh: 创建或修改 NextClaw 轻量应用中的 Panel App UI 部分。适用于 nextclaw-app-creator 判断为 Panel-only 或 Panel + Service 后，或用户明确要求右侧面板 UI、目录式静态面板、Service Actions UI、Agent 驱动的 Panel App、React/Vite/Tailwind Panel App，或询问 Panel App 能做什么、能使用哪些注入 API/能力。
---

# NextClaw Panel App Creator

当用户需要实现右侧面板 UI 时使用这个专项 skill。若用户表达的是“做一个 NextClaw 小应用”而不是明确只做 UI，先读取 `nextclaw-app-creator` 判断是否还需要 Service App。

如果 Panel App 要调用 `window.nextclaw.serviceActions.*`、`window.nextclaw.agent.*` 或 `window.nextclaw.client`，必须先读取 `references/panel-app-bridge-api.md`，并按该 reference 的运行时合同写代码。

本 skill 只拥有 Panel App UI、`panel-app.json`、bridge 调用和窄侧栏体验。它不拥有 `service-app.json`、`actions.*.risk`、MCP server、Service App command 或依赖安装规则。只要需要创建或修改 Service App 文件，必须立即读取 `service-app-creator`，不能凭 Panel App 文档猜后端 manifest 字段。

## 前端工程形态判断

先主动判断是否需要工程化 `React + Vite + TypeScript + Tailwind CSS + pnpm`，不要只在用户点名技术栈时才读取专项 skill。工程化推荐栈是一整套，缺一不可；如果不使用这整套，必须是轻量目录式静态面板、用户明确指定其它技术栈，或有清楚的环境约束理由。

- 适合工程化方案：AI 应用、对话/Agent Run、需要 App Client 类型、多个视图/组件、列表筛选排序、图表、复杂表单、异步加载状态、错误/空状态较多，或后续会持续维护的 Panel App。遇到这些信号，先读取 `panel-app-react-vite-creator`，并使用完整 `React + Vite + TypeScript + Tailwind CSS + pnpm` 栈。
- 适合轻量目录式：极小工具、一次性页面、纯展示/简单表单、少量内存状态、无明显组件拆分和构建收益的应用。不要为了“像工程”而引入 npm 工程。
- 用户明确要求 Vite、React、Tailwind、现代前端技术栈、工程化源码、可构建 Panel App，或希望用 pnpm 开发再交付静态产物时，必须读取 `panel-app-react-vite-creator`。

本 skill 仍负责最终 `panel-app.json`、bridge、Client SDK、Service Actions、窄侧栏体验和 `nextclaw app check` 验收规则；`panel-app-react-vite-creator` 只负责源码工程、Vite/Tailwind 配置、构建和静态 `.panel` 产物交付。

## 能力发现

当用户询问 Panel App 能做什么、能否接入 AI、能否读取会话/历史/Agent Run、能否上传资产或订阅事件时，必须说明 `window.nextclaw.client` 这类 App Client 能力，但不要把 Service Actions 迁移成 App Client 主路径。Service Actions 当前推荐继续使用旧 bridge，因为旧 bridge 拥有 Panel App 所需的授权确认和自动 retry 体验。

默认说明这些能力边界：

- Panel UI：不需要宿主授权的静态界面、本地状态、表单、列表、图表。
- `window.nextclaw.client`：声明 `"client": true` 并整体授权后同步可用，是 App Client projection，适合 sessions、agents、agentRuns、assets、events 等标准客户端能力。`client.serviceActions.*` 当前存在，但不要作为 Panel App Service Actions 推荐路径。
- Service App：本地文件、外部 API、本地命令等后端动作；Panel App 当前推荐通过旧 bridge `window.nextclaw.serviceActions.*` 调用，以保留授权确认、grant 和自动 retry。

`window.nextclaw.serviceActions.*` 是当前 Panel App 调用 Service Actions 的推荐入口，不要因为 App Client 里存在 `client.serviceActions.*` 就默认替代。`window.nextclaw.agent.*` 暂时保留为旧 Agent bridge；只有实际不想开启整体 client 授权、维护旧应用，或需要旧 Agent bridge 独有便利能力时才提它。

## 输出位置

- Panel App 必须写入 NextClaw workspace 的 `panels/` 目录。
- 默认 workspace 是 `~/.nextclaw/workspace`；如果当前任务能读取 NextClaw 配置，则以 `agents.defaults.workspace` 为准。
- 目录式应用的目录名必须使用 kebab-case，并以 `.panel` 结尾，例如 `todo-board.panel/`。

## 文件形态

- 新建或重写 Panel App 时只使用目录式 Panel App。
- 目录式 Panel App 必须包含 `panel-app.json` 和入口 HTML；不要求服务器部署，不创建 npm 项目，不运行构建工具。
- 需要后端能力时，可配套 `service-app-creator` 创建 Service App，但必须先执行 Service App 可用性检查（见下方"Service App 可用性"节）。
- Panel App 运行在 sandbox iframe 中，不能依赖 `localStorage`、`sessionStorage`、cookie 或 IndexedDB。轻量状态默认只放内存；需要保存时提供导出/导入 JSON，或配套 Service App / App Client 能力。
- `panel-app.json` 是标题、描述、图标、入口、Agent capabilities 和 Service actions 的唯一 manifest 事实源；不要把 NextClaw manifest 字段写到 HTML meta。

## Sandbox 运行环境约束

Panel App 不是普通同源网页。宿主为了隔离应用，iframe sandbox 不包含 `allow-same-origin`，文档 origin 是 opaque / `null`。写代码时必须默认遵守：

- 不访问 `window.localStorage`、`window.sessionStorage`、`document.cookie`、IndexedDB，也不要使用会在初始化时自动触碰这些 API 的持久化库或状态插件。
- 不假设当前页面和宿主同源；不要读取父窗口 DOM、cookie、token 或宿主内部全局变量。
- 不直接持久化 bridge token、runtime token、session token 或授权状态。
- 同源 `/api/...` 请求只能用于宿主允许的 Panel App 运行时链路；优先使用 `window.nextclaw.client`、`window.nextclaw.serviceActions.*` 或 `window.nextclaw.agent.*`。
- 临时 UI 状态用普通 JS/React state；需要跨重新打开保存时，优先设计为 Service App action、App Client 标准能力，或显式导出/导入 JSON。

如果用户报告 `Failed to read the 'localStorage' property from 'Window': The document is sandboxed and lacks the 'allow-same-origin' flag`，根因通常是 Panel App 或其依赖在 sandbox 环境中访问了 Web Storage。修复方向是删除该持久化访问，而不是给 iframe 增加 `allow-same-origin`。

如果用户报告具体运行时报错，例如 `Illegal invocation`、sandbox storage、opaque origin、CORS 或 App Client 注入异常，先读取 `references/panel-app-runtime-troubleshooting.md`，按错误签名定位，不要把所有低频排障细节写进主流程。

### 目录式静态应用

适合需要后续扩展、持续维护、资源拆分或更清晰代码组织的静态应用：

```text
panels/markdown-manager.panel/
  panel-app.json
  index.html
  app.js
  styles.css
  assets/icon.svg
```

`panel-app.json` 示例：

```json
{
  "title": "Markdown 管理器",
  "description": "浏览、编辑和整理本地 Markdown 文件",
  "icon": "assets/icon.svg",
  "entry": "index.html",
  "capabilities": ["agent:generateObject"],
  "actions": ["workspace-files.list", "workspace-files.read"]
}
```

目录式规则：

- `id` 可以省略，系统会使用目录名作为身份；如果显式填写 `id`，必须等于目录名去掉 `.panel` 后的值，例如 `markdown-manager.panel` 对应 `markdown-manager`。
- `entry` 必须是目录内的 HTML 文件，通常是 `index.html`。
- 只有确实需要完整 NextClaw Client SDK 时才写 `"client": true`；不需要 client 的 Panel App 不要声明。
- `icon` 可以是 emoji、data URL、http/https/绝对路径，也可以是目录内相对资源路径，例如 `assets/icon.svg`。
- 相对 CSS、JS、图片路径可以直接写 `styles.css`、`app.js`、`assets/icon.svg`；NextClaw 会通过资源接口托管它们。
- 不要在目录式 Panel App 里创建 `package.json`、`node_modules`、Vite 配置或后台 dev server，除非用户明确要求后续升级为更重的形态。
- 创建或修改 Panel App 后不需要重启 NextClaw 宿主、server 或桌面应用；目录内容会在 workspace 中被重新读取。需要看到最新效果时，刷新“面板应用”列表、重新打开该 Panel App，或使用面板右上角刷新/重新加载内容。

## 启动器元信息

每个 Panel App 默认都要在 `panel-app.json` 写清启动器元信息，让用户在 Panel Apps 列表中能快速识别它：

```json
{
  "title": "番茄便签",
  "description": "番茄钟、任务清单和专注记录",
  "icon": "🍅",
  "entry": "index.html"
}
```

图标规则：

- 最简单优先在 `panel-app.json.icon` 放一个语义明确的 emoji 或 1-2 个短字符。
- 如果用户要求正式图片图标，再使用目录内相对资源路径，例如 `assets/icon.svg`。
- 不要省略图标；没有用户指定时，按应用主题选择一个克制、可识别的 emoji。
- 可以在 `panel-app.json.icon` 中使用相对资源路径。

## 窄侧栏优先布局

Panel App 默认打开在 NextClaw 右侧栏里，初始宽度通常较窄；用户可以把右侧栏拉宽，但不能假设一开始就是桌面宽屏。

- 默认按 `320px-480px` 窄面板优先设计，再逐步增强到宽屏。
- 主流程、核心按钮、表单和列表在窄宽度下必须完整可用，不横向溢出。
- 使用单列布局作为基础；宽屏时再用 CSS media query 升级为双列、网格或并排详情。
- 工具栏和筛选项在窄屏下允许换行、折叠或变成分段按钮，不要做依赖大宽度的顶部横排。
- 卡片、表格、图表要适配窄容器：长文本换行，表格优先改成列表/详情卡，图表使用 `width: 100%` 和稳定高度。
- 不使用固定桌面宽度容器，例如 `width: 960px`；容器应使用 `max-width: 100%`、`min-width: 0`、`box-sizing: border-box`。
- 验收时至少想象两种宽度：窄侧栏和用户拉宽后的面板。窄侧栏可用性优先于宽屏装饰性。

## Panel Card 体验合同

只有当你已经判断这个 Panel App 适合以内联卡片展示时，才使用本节；不要把普通右侧面板、编辑器、管理页、大表格或多页工作流硬做成卡片。

适合 Panel Card 的形态：

- 天气卡片、汇率卡、计时器、计算器、checklist、picker、短表单、小 preview、小 dashboard。
- 用户希望“直接试一下”“快速看一下”“在当前对话里操作”，且核心交互能在有限高度内完成。

不适合 Panel Card 的形态：

- 长文档阅读、富文本/代码/Markdown 编辑器、文件浏览器、设置页、复杂管理台、大表格、多页持续工作区。

如果决定做 Panel Card，必须按 card-first 设计：

- 首屏 `220px-420px` 高度内必须看见核心价值，不要让用户先滚动才知道卡片能做什么。
- 横向优先：默认让信息沿宽度展开，宽度大于高度；常见结构是左侧主结果/核心状态，右侧短列表、次要指标或一个主操作。容器太窄时再折成单列。
- 禁止横向滚动、固定桌面宽度、大片空白和过高 hero。
- 设计上不要依赖 document 级内部滚动；允许 dropdown、select、短列表等控件级局部滚动。内容超出时改成摘要 + 展开，而不是把整张卡片设计成滚动页面。宿主可能用 iframe 滚动兜底旧内容，但不要把它当成默认体验。
- 只保留一个主操作，最多 2-3 个辅助操作；复杂配置、详情和历史记录交给展开后的 side panel。
- 必须有 loading、empty、error 状态；错误要可读，不要只在 console 里报错。
- 视觉要像精美卡片：清晰层级、克制色彩、足够留白、稳定高度、数字/状态突出、按钮和输入控件可点击。
- inline 宿主会在 URL 上追加 `nextclawDisplayMode=card` 和 `nextclawPlacement=inline`；检测到这些参数时，优先渲染 card-first 布局，不要继续使用完整页面布局。
- 完成后用 `show_content(type="panel_app", placement="inline")` 展示；如果实现过程中发现卡片空间不足，改用 `placement="side_panel"`，不要勉强塞进 inline。

## Service Actions

本节只说明 Panel App 如何声明和调用已存在或由 `service-app-creator` 设计出的 Service Action；不要在这里发明 Service App action 的 `risk`、`inputSchema`、command 或 server 实现。当前 Panel App 调用 Service Actions 推荐使用 `window.nextclaw.serviceActions.*`；`client.serviceActions.*` 暂时不作为推荐路径，因为它缺少旧 bridge 的授权确认和自动 retry 体验。

Panel App 调用 Service App 前，必须在 `panel-app.json` 的 `actions` 数组声明允许使用的 action：

```json
{
  "title": "Markdown 管理器",
  "entry": "index.html",
  "actions": ["workspace-files.list", "workspace-files.read"]
}
```

action id 必须来自对应 `service-app.json.actions`：`<service-app-id>.<tool-name>`。`service-app-id` 不包含点号，tool name 可以包含点号。
不要发明 `permissions.allowlist`、`serviceActions` 等额外字段；当前标准字段就是 `actions`。

运行时通过宿主注入的 SDK 调用：

```js
// Service App 调用必须在 try/catch 中，错误要给出明确用户反馈
try {
  if (window.nextclaw?.serviceActions?.invoke) {
    // invoke() 返回 action 的业务结果 payload，不需要读取 response.result
    const note = await window.nextclaw.serviceActions.invoke("workspace-notes.readNote", {
      path: "notes/today.md"
    });
    renderNote(note.content ?? "");
  } else {
    showError("当前环境不支持 Service Actions");
  }
} catch (e) {
  console.error("Service Action 调用失败:", e);
  showError("Service Action 调用失败，请检查授权和服务状态。");
}
```

`list()` 返回 action 数组，`invoke()` 已由宿主 SDK 解包，返回值就是 Service App tool 的业务 payload。不要写 `response.actions`、`response.result`、`response.files` 这种不确定访问：

```js
const actions = await window.nextclaw.serviceActions.list();
renderActions(actions);
```

如果 action 返回 `{ files: [...] }`，应写：

```js
const payload = await window.nextclaw.serviceActions.invoke("workspace-files.list", {});
const files = payload.files ?? [];
```

错误提示要区分原因：bridge 不存在才说 Service Actions 不可用；调用抛错才说 Service Action 调用失败；返回结构不符合预期要说返回格式未识别，不要统一误报为 Service App 不可用。

不要在 Panel App 里伪造 caller、保存 token 或直接请求 Service Gateway；首次调用授权由宿主处理。
不要为了发现 action 在 Panel App 启动时自行触发后端探测；Service Actions 列表由宿主读取静态 manifest，运行时 discovery 由服务应用面板中的显式操作完成。

## Client SDK

Panel App 如果需要完整 NextClaw Client SDK，在 `panel-app.json` 中声明：

```json
{
  "title": "示例应用",
  "entry": "index.html",
  "client": true
}
```

授权后，宿主会同步注入 `window.nextclaw.client`。它是面向 Panel App 的 `NextClawAppClient` projection，不是完整底层 `NextClawClient`；不要自己 import、不要自己初始化 token，也不要假设有 host/admin namespace。

App Client 不只是“发送请求的 transport”。对 AI/聊天类 Panel App 来说，NextClaw 已经是会话、消息、Agent Run、实时事件和资产的持久化 owner：

- 用稳定 `peerId` 让 NextClaw 创建或复用会话，不要保存 `sessionIdByAgent` 这类浏览器侧映射。
- 用 `client.sessions.list()` / `client.sessions.get()` / `client.sessions.listMessages()` 恢复历史，不要把聊天记录镜像到浏览器 storage。
- 用 `client.agentRuns.send()` 触发运行；用返回的 `sessionId` 只作为当前内存态和事件过滤条件。
- 用 `client.events.subscribe()` 追踪运行中的流式事件；页面重新打开后再从 `sessions/listMessages` 恢复最终事实。
- Panel App 自己只维护渲染所需的临时 UI state，例如当前输入框内容、当前选中的 agent id、正在流式累积的片段；这些状态默认放内存，不跨重新打开持久化。

```js
const client = window.nextclaw?.client;
if (!client) {
  showError("当前面板应用尚未获得 NextClaw Client SDK 授权。");
  return;
}

const sessions = await client.sessions.list();
```

不要把 Client SDK API schema 硬编码进本 skill 或 Panel App 模板。需要类型和接口时，应从用户机器上已安装的 NPM 包解析：

- 优先在运行环境中解析 `@nextclaw/client-sdk` 包位置，例如 `require.resolve("@nextclaw/client-sdk")` 或查看包的 `package.json.exports`。
- 类型入口通常在包的 `dist/index.d.ts` 或 package exports 的 `types` 指向处；构建产物里可以找到 `NextClawAppClient` 以及它引用到的 request/response type。
- **Monorepo 回退路径**：`@nextclaw/client-sdk` 是 `nextclaw-ui` 的依赖，不是顶层根依赖。如果 `require.resolve` 在默认工作区找不到，先检查相关 workspace 包的 `node_modules`（如 `packages/nextclaw-ui/node_modules/@nextclaw/client-sdk/dist/`），直接读 `dist/` 下的 `.d.ts` 类型声明。不要跳到源码树里搜索——编译包的类型声明比源码更准确且更易定位。
- 如果所有工作区的 `node_modules` 都找不到该包或声明文件，再明确提示当前 NextClaw 安装缺少 Client SDK 产物，不要凭记忆猜接口。

## Service App 可用性

构建 Panel App 时必须区分“环境不支持”“未授权”“服务调用失败”“返回格式不符合预期”，不要把所有问题都报成 Service App 不可用：

1. **先检查，后调用**：在调用任何 service action 前，检查 `window.nextclaw?.serviceActions?.invoke` 是否存在。
2. **声明一致**：调用前确认 `panel-app.json.actions` 包含实际 action id。
3. **try/catch 包裹**：所有 service action 调用必须在 try/catch 中，catch 里展示明确错误。
4. **返回值校验**：`invoke()` 返回业务 payload；如果 payload 结构不符合 UI 预期，提示“返回格式未识别”，不要误报为连接失败。
5. **本地降级有边界**：只有用户目标允许页面内临时状态时才做纯前端降级；读写文件、执行命令、外部 API、稳定持久化这类目标不能静默降级为假成功。
6. **运行时失败快速决策**：如果 Service App 已部署但返回错误，最多调试 2 次（检查 manifest、检查 server 日志），仍失败就明确告知用户当前阻塞点，不要反复空转。
7. **多文件写入后做交叉一致性检查**：CSS/JS/HTML 分开写时容易出现类名、ID、事件名不一致。全部文件写完后、交付前，快速检查：(a) JS 中的 `querySelector`/`className` 是否在 CSS 中有对应规则；(b) HTML 中的 `id`/`class` 是否在 JS 中被引用；(c) CSS 选择器是否覆盖了 JS 动态生成的 DOM 结构。不要依赖浏览器调试工具发现这些问题——它们在写入阶段就能通过代码审读发现。
8. **Panel App 不工作时先自审代码，再用外部工具**：用户报告"没看到"/"没反应"时，第一反应应该是读自己写的代码（manifest、JS API 调用格式、bridge 声明），而不是立即用 Chrome DevTools 等外部调试工具。先按清单自查：(a) `panel-app.json` 是否声明了需要的 `client`/`capabilities`/`actions`；(b) JS 中的 bridge/SDK 调用格式是否正确；(c) `waitForClient`/初始化逻辑是否有静默失败。用户给出方向性提示时（如"你是不是 api 格式没搞对"、"有没有声明 client: true"），优先验证用户指出的方向，不要继续自己的推理链。

## 交付前自检

新建或修改 Panel App 后，必须运行：

```bash
nextclaw app check ~/.nextclaw/workspace/panels/<app-id>.panel
```

`nextclaw app check` 失败时必须先修复，再交付给用户。它会检查目录式 `panel-app.json`、入口 HTML、资源路径、Agent capabilities、Service action allowlist 以及常见 bridge 调用漏声明问题。

如果这个 Panel App 配套修改了 Service App，还必须对对应服务目录运行 `nextclaw app check`、`nextclaw app dev`，并用 `nextclaw app call <service-app-dir> <action-name> --input '{}'` 抽测关键 action。Panel App 自检不替代后端真实 runtime 验收。

交付说明不要要求用户 restart；除非已经验证是宿主进程异常、版本切换或进程崩溃，否则重启不是 Panel App 生效步骤。

## Agent API

Panel App 可以通过宿主注入的 `window.nextclaw.agent` 调用 NextClaw Agent。需要 Agent 能力时，必须先在 `panel-app.json.capabilities` 声明 capability：

```json
{
  "capabilities": ["agent:send", "agent:generateObject"]
}
```

只声明实际会用到的能力：

- 只触发会话 run：声明 `agent:send`。
- 需要结构化对象返回：声明 `agent:generateObject`。
- capability 名称必须精确使用冒号形式。不要写 `agent.send`、`agent.generateObject` 或泛化的 `agent`。

### generateObject

`generateObject` 适合 AI 分析、总结、分类、生成结构化 UI 状态：把当前 UI 状态交给持续 Agent 会话，并拿回可以直接写入应用状态的 JSON object。不要为了 AI 分析新建 Service App 自己调用模型，除非用户明确要求接入某个外部模型服务。

```js
if (!window.nextclaw?.agent?.generateObject) {
  throw new Error("当前环境不支持 NextClaw Agent API");
}

const result = await window.nextclaw.agent.generateObject({
  peerId: "mood-summary",
  prompt: "总结这些心情记录，并给出三个具体建议。",
  context: { entries },
  schema: {
    type: "object",
    properties: {
      summary: { type: "string" },
      suggestions: {
        type: "array",
        items: { type: "string" }
      }
    },
    required: ["summary", "suggestions"],
    additionalProperties: false
  }
});
```

关键约定：

- `peerId` 由 Panel App 自己生成并保持稳定；同一个 Panel App + 同一个 `peerId` 会复用同一个 Agent 会话。
- 不要自己生成、缓存或猜测稳定 `sessionId`；需要固定会话时只传 `peerId`，由 NextClaw 内部创建或复用 session。
- `schema` 必须描述期望返回对象；不要要求 Agent 在自然语言里输出 JSON。
- 返回值就是结构化对象本身，不是字符串，也不是 `{ result: ... }` envelope。
- 第一次调用受保护 Agent capability 时，宿主会负责弹授权，不要自己实现授权 UI。

#### Capability 声明格式

`generateObject` 和 `send` 各自需要独立声明。声明必须使用**完整格式**（`agent:generateObject`、`agent:send`），不能用笼统的 `agent`：

```json
{
  "capabilities": ["agent:generateObject", "agent:send"]
}
```

错误示例：

```json
{
  "capabilities": ["agent"]
}
```

### send

`send` 适合只触发一次 Agent 会话 run，不等待最终回复：

```js
const handle = await window.nextclaw.agent.send({
  peerId: "daily-analysis",
  content: [{ type: "text", text: "请根据当前数据生成一份后续分析。" }]
});
```

后续继续使用同一个 `peerId` 即可投送到同一会话：

```js
await window.nextclaw.agent.send({
  peerId: "daily-analysis",
  content: [{ type: "text", text: "继续上一轮，补充风险点。" }]
});
```

如果你已经明确拿到了已有会话的 `sessionId`，也可以把它作为历史 continuation 使用：

```js
await window.nextclaw.agent.send({
  sessionId: handle.sessionId,
  content: [{ type: "text", text: "继续上一轮，补充风险点。" }]
});
```

不要同时传 `peerId` 和 `sessionId`。这两个字段分别代表“由系统按稳定 peer 创建/复用会话”和“继续一个已知会话”，混用会被拒绝。

不要在 `panel-app.json.capabilities` 未声明对应 capability 时调用 `window.nextclaw.agent.*`。调用失败时展示明确错误，不要静默当作成功，也不要退回到直接请求某个本地 Agent HTTP 接口。

## 实现建议

0. **信任 write_file 结果**：`write_file` 返回成功即表示文件已写入。不要用 `exec ls -la`、`head` 或 `read_file` 去"验证"刚写入的文件——这会浪费工具调用，并可能因批量执行的时间戳不一致导致分析循环。需要验证时，只在全部写入完成后的验收阶段做一次。
0b. **manifest 只写 `panel-app.json`**：标题、描述、图标、Service actions、Agent capabilities 都写入 `panel-app.json`。不要在 HTML `<head>` 中添加 NextClaw manifest meta，也不要发明 `permissions.allowlist`、`serviceActions` 等字段。
1. 明确用户要解决的实际工作流，不把临时工具做成复杂产品。
2. 生成完整可打开的 HTML：`<!doctype html>`、`<meta charset="utf-8">`、响应式布局、可访问的按钮和输入。
3. 每次新建或重写 Panel App 时，都要先补齐 `panel-app.json` 的 `title`、`description`、`icon` 和 `entry`。
4. 本地状态优先用内存变量或框架 state；需要导入导出时，用文本框、复制、下载 JSON 等浏览器原生能力。不要使用 `localStorage`、`sessionStorage`、cookie 或 IndexedDB。
5. 视觉保持克制、清晰、信息密度适中，避免营销页式 hero 和装饰性堆叠。
6. 完成后告诉用户在 NextClaw 左下角设置菜单打开“面板应用”，再选择对应应用。
