Token导航 LogoToken导航

Agent Skill · 效率

glance(glance 效率)

glance 用于补充效率相关能力,适合在 OpenClaw 中需要让 Agent 承接效率相关任务时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

glance 是效率类 Agent Skill,可用宿主为 OpenClaw,通过ClawHub获取,权限为接触敏感数据;许可证为 MIT-0,第三方扫描有提醒项,按安装量在效率类的 21,003 个 Skill 里排第 1,300。

总安装 48,922周安装 2,059GitHub Stars 公开资料未说明下载 17,131核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT-0
版本
1.0.0

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:glance(glance 效率)
来源仓库:https://github.com/acfranzen/glance
安装命令:
openclaw skills install glance
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 OpenClaw 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

ClawHubOpenClaw
openclaw skills install glance

这个 Skill 是做什么的

效率类 Skill 把重复的整理、汇总、转换工作交给助手完成,减少手工复制粘贴。

创建、更新和管理 Glance 仪表板小部件。当用户想要执行以下操作时使用:向仪表板添加内容、创建小部件、直观地跟踪数据、显示指标/统计数据、显示 API 数据或监控使用情况。

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 OpenClaw;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 openclaw skills install glance;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

glance 怎么安装?

在终端执行 openclaw skills install glance。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

glance 支持哪些 AI 工具?

公开资料标注支持 OpenClaw。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

glance 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

glance 是免费的吗?

来源标注的许可证是 MIT-0。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

glance 用的人多吗?

公开数据是累计安装 48,922 次,近一周安装 2,059 次,下载 17,131 次。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

glance 安全吗?

第三方扫描有提醒项,说明存在需要人工确认的行为。安装前请打开源码看清它读了什么、联网到哪里。

值得选的地方和要先想清楚的地方

值得选的地方

  • 专注 OpenClaw 一种宿主,触发方式和使用习惯不用来回切换。
  • 许可证明确为 MIT-0,商用和分发边界好判断。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 OpenClaw,想直接扩展它能力的人。
  • 需要处理效率类任务、又不想每次都手写提示词的人。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要厂商级技术支持和 SLA 的生产系统。

效率类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
github

GitHub 代码协作 · OpenClaw

7,632,918545需要联网MIT-0通过
nano-pdf

Nano PDF 文档 · OpenClaw

4,249,476231需要联网MIT-0通过
auto-updater

自动更新程序 · OpenClaw

2,964,063386操作浏览器MIT-0通过
video-frames

视频帧 · OpenClaw

2,621,304112需要联网MIT-0通过
gemini

Gemini 助手 · OpenClaw

2,547,39648需要联网MIT-0有提醒
glance

glance 效率 · 本页

48,922—接触敏感数据MIT-0有提醒

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

name
glance
description
Create, update, and manage Glance dashboard widgets. Use when user wants to: add something to their dashboard, create a widget, track data visually, show metrics/stats, display API data, or monitor usage.
metadata
openclaw
emoji
🖥️
homepage
https://github.com/acfranzen/glance
requires
env
["GLANCE_URL"]
bins
["curl"]
primaryEnv
GLANCE_URL

Glance

AI-extensible personal dashboard. Create custom widgets with natural language — the AI handles data collection.

Features

  • Custom Widgets — Create widgets via AI with auto-generated JSX
  • Agent Refresh — AI collects data on schedule and pushes to cache
  • Dashboard Export/Import — Share widget configurations
  • Credential Management — Secure API key storage
  • Real-time Updates — Webhook-triggered instant refreshes

Quick Start

# Navigate to skill directory (if installed via ClawHub)
cd "$(clawhub list | grep glance | awk '{print $2}')"

# Or clone directly
git clone https://github.com/acfranzen/glance ~/.glance
cd ~/.glance

# Install dependencies
npm install

# Configure environment
cp .env.example .env.local
# Edit .env.local with your settings

# Start development server
npm run dev

# Or build and start production
npm run build && npm start

Dashboard runs at http://localhost:3333

Configuration

Edit .env.local:

# Server
PORT=3333
AUTH_TOKEN=your-secret-token        # Optional: Bearer token auth

# OpenClaw Integration (for instant widget refresh)
OPENCLAW_GATEWAY_URL=https://localhost:18789
OPENCLAW_TOKEN=your-gateway-token

# Database
DATABASE_PATH=./data/glance.db      # SQLite database location

Service Installation (macOS)

# Create launchd plist
cat > ~/Library/LaunchAgents/com.glance.dashboard.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.glance.dashboard</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/bin/npm</string>
        <string>run</string>
        <string>dev</string>
    </array>
    <key>WorkingDirectory</key>
    <string>~/.glance</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>~/.glance/logs/stdout.log</string>
    <key>StandardErrorPath</key>
    <string>~/.glance/logs/stderr.log</string>
</dict>
</plist>
EOF

# Load service
mkdir -p ~/.glance/logs
launchctl load ~/Library/LaunchAgents/com.glance.dashboard.plist

# Service commands
launchctl start com.glance.dashboard
launchctl stop com.glance.dashboard
launchctl unload ~/Library/LaunchAgents/com.glance.dashboard.plist

Environment Variables

VariableDescriptionDefault
PORTServer port3333
AUTH_TOKENBearer token for API auth—
DATABASE_PATHSQLite database path./data/glance.db
OPENCLAW_GATEWAY_URLOpenClaw gateway for webhooks—
OPENCLAW_TOKENOpenClaw auth token—

Requirements

  • Node.js 20+
  • npm or pnpm
  • SQLite (bundled)

Widget Skill

Create and manage dashboard widgets. Most widgets use agent_refresh — you collect the data.

Quick Start

# Check Glance is running (list widgets)
curl -s -H "Origin: $GLANCE_URL" "$GLANCE_URL/api/widgets" | jq '.custom_widgets[].slug'

# Auth note: Local requests with Origin header bypass Bearer token auth
# For external access, use: -H "Authorization: Bearer $GLANCE_TOKEN"

# Refresh a widget (look up instructions, collect data, POST to cache)
sqlite3 $GLANCE_DATA/glance.db "SELECT json_extract(fetch, '$.instructions') FROM custom_widgets WHERE slug = 'my-widget'"
# Follow the instructions, then:
curl -X POST "$GLANCE_URL/api/widgets/my-widget/cache" \
  -H "Content-Type: application/json" \
  -H "Origin: $GLANCE_URL" \
  -d '{"data": {"value": 42, "fetchedAt": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}}'

# Verify in browser
browser action:open targetUrl:"$GLANCE_URL"

AI Structured Output Generation (REQUIRED)

When generating widget definitions, use the JSON Schema at docs/schemas/widget-schema.json with your AI model's structured output mode:

  • Anthropic: Use tool_use with the schema
  • OpenAI: Use response_format: { type: "json_schema", schema }

The schema enforces all required fields at generation time — malformed widgets cannot be produced.

Required Fields Checklist

Every widget MUST have these fields (the schema enforces them):

FieldTypeNotes
namestringNon-empty, human-readable
slugstringLowercase kebab-case (my-widget)
source_codestringValid JSX with Widget function
default_size{ w: 1-12, h: 1-20 }Grid units
min_size{ w: 1-12, h: 1-20 }Cannot resize smaller
fetch.typeenum"server_code" \"webhook" \"agent_refresh"
fetch.instructionsstringREQUIRED if type is agent_refresh
fetch.schedulestringREQUIRED if type is agent_refresh (cron)
data_schema.type"object"Always object
data_schema.propertiesobjectDefine each field
data_schema.requiredarrayMUST include "fetchedAt"
credentialsarrayUse [] if none needed

Example: Minimal Valid Widget

{
  "name": "My Widget",
  "slug": "my-widget",
  "source_code": "function Widget({ serverData }) { return <div>{serverData?.value}</div>; }",
  "default_size": { "w": 2, "h": 2 },
  "min_size": { "w": 1, "h": 1 },
  "fetch": {
    "type": "agent_refresh",
    "schedule": "*/15 * * * *",
    "instructions": "## Data Collection\
Collect the data...\
\
## Cache Update\
POST to /api/widgets/my-widget/cache"
  },
  "data_schema": {
    "type": "object",
    "properties": {
      "value": { "type": "number" },
      "fetchedAt": { "type": "string", "format": "date-time" }
    },
    "required": ["value", "fetchedAt"]
  },
  "credentials": []
}

⚠️ Widget Creation Checklist (MANDATORY)

Every widget must complete ALL steps before being considered done:

□ Step 1: Create widget definition (POST /api/widgets)
    - source_code with Widget function
    - data_schema (REQUIRED for validation)
    - fetch config (type + instructions for agent_refresh)
    
□ Step 2: Add to dashboard (POST /api/widgets/instances)
    - custom_widget_id matches definition
    - title and config set
    
□ Step 3: Populate cache (for agent_refresh widgets)
    - Data matches data_schema exactly
    - Includes fetchedAt timestamp
    
□ Step 4: Set up cron job (for agent_refresh widgets)
    - Simple message: "⚡ WIDGET REFRESH: {slug}"
    - Appropriate schedule (*/15 or */30 typically)
    
□ Step 5: BROWSER VERIFICATION (MANDATORY)
    - Open http://localhost:3333
    - Widget is visible on dashboard
    - Shows actual data (not loading spinner)
    - Data values match what was cached
    - No errors or broken layouts
    
⛔ DO NOT report widget as complete until Step 5 passes!

Quick Reference

Widget Package Structure

Widget Package
├── meta (name, slug, description, author, version)
├── widget (source_code, default_size, min_size)
├── fetch (server_code | webhook | agent_refresh)
├── dataSchema? (JSON Schema for cached data - validates on POST)
├── cache (ttl, staleness, fallback)
├── credentials[] (API keys, local software requirements)
├── config_schema? (user options)
└── error? (retry, fallback, timeout)

Fetch Type Decision Tree

Is data available via API that the widget can call?
├── YES → Use server_code
└── NO → Does an external service push data?
    ├── YES → Use webhook
    └── NO → Use agent_refresh (YOU collect it)
ScenarioFetch TypeWho Collects Data?
Public/authenticated APIserver_codeWidget calls API at render
External service pushes datawebhookExternal service POSTs to cache
Local CLI toolsagent_refreshYOU (the agent) via PTY/exec
Interactive terminalsagent_refreshYOU (the agent) via PTY
Computed/aggregated dataagent_refreshYOU (the agent) on a schedule

⚠️ agent_refresh means YOU are the data source. You set up a cron to remind yourself, then YOU collect the data using your tools (exec, PTY, browser, etc.) and POST it to the cache.

API Endpoints

Widget Definitions

MethodEndpointDescription
POST/api/widgetsCreate widget definition
GET/api/widgetsList all definitions
GET/api/widgets/:slugGet single definition
PATCH/api/widgets/:slugUpdate definition
DELETE/api/widgets/:slugDelete definition

Widget Instances (Dashboard)

MethodEndpointDescription
POST/api/widgets/instancesAdd widget to dashboard
GET/api/widgets/instancesList dashboard widgets
PATCH/api/widgets/instances/:idUpdate instance (config, position)
DELETE/api/widgets/instances/:idRemove from dashboard

Credentials

MethodEndpointDescription
GET/api/credentialsList credentials + status
POST/api/credentialsStore credential
DELETE/api/credentials/:idDelete credential

Creating a Widget

Full Widget Package Structure

{
  "name": "GitHub PRs",
  "slug": "github-prs",
  "description": "Shows open pull requests",
  
  "source_code": "function Widget({ serverData }) { ... }",
  "default_size": { "w": 2, "h": 2 },
  "min_size": { "w": 1, "h": 1 },
  "refresh_interval": 300,
  
  "credentials": [
    {
      "id": "github",
      "type": "api_key",
      "name": "GitHub Personal Access Token",
      "description": "Token with repo scope",
      "obtain_url": "https://github.com/settings/tokens"
    }
  ],
  
  "fetch": {
    "type": "agent_refresh",
    "schedule": "*/5 * * * *",
    "instructions": "Fetch open PRs from GitHub API and POST to cache endpoint",
    "expected_freshness_seconds": 300,
    "max_staleness_seconds": 900
  },
  
  "cache": {
    "ttl_seconds": 300,
    "max_staleness_seconds": 900,
    "storage": "sqlite",
    "on_error": "use_stale"
  },
  
  "setup": {
    "description": "Configure GitHub token",
    "agent_skill": "Store GitHub PAT via /api/credentials",
    "verification": {
      "type": "cache_populated",
      "target": "github-prs"
    },
    "idempotent": true
  }
}

Fetch Types

TypeWhen to UseData Flow
server_codeWidget can call API directlyWidget → server_code → API
agent_refreshAgent must fetch/compute dataAgent → POST /cache → Widget reads
webhookExternal service pushes dataExternal → POST /cache → Widget reads

Most widgets should use agent_refresh — the agent fetches data on a schedule and pushes to the cache endpoint.

Step 1: Create Widget Definition

POST /api/widgets
Content-Type: application/json

{
  "name": "GitHub PRs",
  "slug": "github-prs",
  "description": "Shows open pull requests",
  "source_code": "function Widget({ serverData }) { ... }",
  "default_size": { "w": 2, "h": 2 },
  "credentials": [...],
  "fetch": { "type": "agent_refresh", "schedule": "*/5 * * * *", ... },
  "data_schema": {
    "type": "object",
    "properties": {
      "prs": { "type": "array", "description": "List of PR objects" },
      "fetchedAt": { "type": "string", "format": "date-time" }
    },
    "required": ["prs", "fetchedAt"]
  },
  "cache": { "ttl_seconds": 300, ... }
}

data_schema (REQUIRED) defines the data contract between the fetcher and the widget. Cache POSTs are validated against it — malformed data returns 400.

⚠️ Always include data_schema when creating widgets. This ensures: 1. Data validation on cache POSTs (400 on schema mismatch) 2. Clear documentation of expected data structure 3. AI agents know the exact format to produce

Step 2: Add to Dashboard

POST /api/widgets/instances
Content-Type: application/json

{
  "type": "custom",
  "title": "GitHub PRs",
  "custom_widget_id": "cw_abc123",
  "config": { "owner": "acfranzen", "repo": "libra" }
}

Step 3: Populate Cache (for agent_refresh)

POST /api/widgets/github-prs/cache
Content-Type: application/json

{
  "data": {
    "prs": [...],
    "fetchedAt": "2026-02-03T14:00:00Z"
  }
}

⚠️ If the widget has a dataSchema, the cache endpoint validates your data against it. Bad data returns 400 with details. Always check the widget's schema before POSTing:

GET /api/widgets/github-prs
# Response includes dataSchema showing required fields and types

Step 4: Browser Verification (REQUIRED)

⚠️ MANDATORY: Every widget creation and refresh MUST end with browser verification.

Never consider a widget "done" until you've visually confirmed it renders correctly on the dashboard.

// REQUIRED: Open dashboard and verify widget renders
browser({ 
  action: 'open', 
  targetUrl: 'http://localhost:3333',
  profile: 'openclaw'
});

// Take a snapshot and check the widget
browser({ action: 'snapshot' });

// Look for:
// 1. Widget is visible on the dashboard
// 2. Shows actual data, NOT "Waiting for data..." or loading spinner
// 3. Data values match what was pushed to cache
// 4. No error messages displayed
// 5. Layout looks correct (not broken/overlapping)

Verification checklist (must ALL be true):

  • [ ] Widget visible on dashboard grid
  • [ ] Title displays correctly
  • [ ] Data renders (not stuck on loading)
  • [ ] Values match cached data
  • [ ] No error states or broken layouts
  • [ ] "Updated X ago" footer shows recent timestamp

Common issues and fixes:

SymptomCauseFix
"Waiting for data..."Cache emptyPOST data to /api/widgets/{slug}/cache
Widget not visibleNot added to dashboardPOST /api/widgets/instances
Wrong/old dataSlug mismatchCheck slug matches between definition and cache POST
Broken layoutBad JSX in source_codeCheck widget code for syntax errors
"No data" after POSTSchema validation failedCheck data matches data_schema

If verification fails, fix the issue before reporting success.

Widget Code Template (agent_refresh)

For agent_refresh widgets, use serverData prop (NOT useData hook):

function Widget({ serverData }) {
  const data = serverData;
  const loading = !serverData;
  const error = serverData?.error;
  
  if (loading) return <Loading message="Waiting for data..." />;
  if (error) return <ErrorDisplay message={error} />;
  
  // NOTE: Do NOT wrap in <Card> - the framework wrapper (CustomWidgetWrapper) 
  // already provides the outer card with title, refresh button, and footer.
  // Just render your content directly.
  return (
    <div className="space-y-3">
      <List items={data.prs?.map(pr => ({
        title: pr.title,
        subtitle: `#${pr.number} by ${pr.author}`,
        badge: pr.state
      })) || []} />
    </div>
  );
}

Important: The widget wrapper (CustomWidgetWrapper) provides:

  • Outer <Card> container with header (widget title)
  • Refresh button and "Updated X ago" footer
  • Loading/error states

Your widget code should just render the content — no Card, no CardHeader, no footer.

Key difference: agent_refresh widgets receive data via serverData prop, NOT by calling useData(). The agent pushes data to /api/widgets/{slug}/cache.

Server Code (Legacy Alternative)

Prefer agent_refresh over server_code. Only use server_code when the widget MUST execute code at render time (rare).

// Only for fetch.type = "server_code" widgets
const token = await getCredential('github');
const response = await fetch('https://api.github.com/repos/owner/repo/pulls', {
  headers: { 'Authorization': `Bearer ${token}` }
});
return await response.json();

Available: fetch, getCredential(provider), params, console Blocked: require, eval, fs, process, global

Agent Refresh Contract

⚠️ CRITICAL: For agent_refresh widgets, YOU (the OpenClaw agent) are the data collector.

This is NOT an external API or service. YOU must:

  1. Set up a cron job to remind yourself to collect data on a schedule
  2. Use your own tools (PTY, exec, browser, etc.) to gather the data
  3. Parse the output into structured JSON
  4. POST to the cache endpoint so the widget can display it

The Pattern

┌─────────────────────────────────────────────────────────────┐
│  Cron fires → Agent wakes up → Agent collects data →        │
│  Agent POSTs to /cache → Widget displays fresh data         │
└─────────────────────────────────────────────────────────────┘

Step-by-Step for agent_refresh Widgets

  1. Create the widget with fetch.type = "agent_refresh" and detailed fetch.instructions
  2. Set up a cron job targeting YOUR main session (message is just the slug):
   cron.add({
     name: "Widget: My Data Refresh",
     schedule: { kind: "cron", expr: "*/15 * * * *" },
     payload: { 
       kind: "systemEvent", 
       text: "⚡ WIDGET REFRESH: my-widget"  // Just the slug!
     },
     sessionTarget: "main"  // Reminds YOU, not an isolated session
   })
  1. When you receive the refresh message, look up fetch.instructions from the DB and spawn a subagent:
   // Parse slug from message
   const slug = message.replace('⚡ WIDGET REFRESH:', '').trim();
   // Query widget's fetch.instructions
   const widget = db.query('SELECT fetch FROM custom_widgets WHERE slug = ?', slug);
   // Spawn subagent with the instructions
   sessions_spawn({ task: widget.fetch.instructions, model: 'haiku' });
  1. The subagent collects the data using your tools:

- exec for shell commands - PTY for interactive CLI tools (like claude /status) - browser for web scraping - API calls via web_fetch

  1. POST the data to the cache:
   POST /api/widgets/{slug}/cache
   Content-Type: application/json
   
   {
     "data": {
       "myValue": 42,
       "fetchedAt": "2026-02-03T18:30:00.000Z"
     }
   }

Writing Excellent fetch.instructions

The fetch.instructions field is the single source of truth for how to collect widget data. Write them clearly so any subagent can follow them.

Required sections:

## Data Collection
Exact commands to run with full paths and flags.
Include PTY requirements if interactive.

## Data Transformation
Exact JSON structure expected.
Include field descriptions and examples.

## Cache Update
Full URL, required headers, body format.

## Browser Verification
Confirm the widget renders correctly.

Good example:

## Data Collection

gog gmail search "in:inbox" --json


## Data Transformation
Take first 5-8 emails, generate AI summary (3-5 words) for each:

{ "emails": [{"id": "...", "from": "...", "subject": "...", "summary": "AI summary here", "unread": true}], "fetchedAt": "ISO timestamp" }


## Cache Update
POST to: http://localhost:3333/api/widgets/recent-emails/cache
Header: Origin: http://localhost:3333
Body: { "data": <object above> }

## Browser Verification  
Open http://localhost:3333 and confirm widget shows emails with AI summaries.

Bad example (too vague):

Get emails and post to cache.

Real Example: Claude Max Usage Widget

This widget shows Claude CLI usage stats. The data comes from running claude in a PTY and navigating to /status → Usage.

The agent's job every 15 minutes:

1. Spawn PTY: exec("claude", { pty: true })
2. Send: "/status" + Enter
3. Navigate to Usage tab (Right arrow keys)
4. Parse the output: Session %, Week %, Extra %
5. POST to /api/widgets/claude-code-usage/cache
6. Kill the PTY session
7. ⚠️ VERIFY: Open browser to http://localhost:3333 and confirm widget displays new data

This is YOUR responsibility as the agent. The widget just displays whatever data is in the cache.

Subagent Task Template for Refreshes

When spawning subagents for widget refreshes, always include browser verification:

sessions_spawn({
  task: `${fetchInstructions}

## REQUIRED: Browser Verification
After posting to cache, verify the widget renders correctly:
1. Open http://localhost:3333 in browser
2. Find the widget on the dashboard
3. Confirm it shows the data you just posted
4. Report any rendering issues

Do NOT report success until browser verification passes.`,
  model: 'haiku',
  label: `${slug}-refresh`
});

Cache Endpoint

POST /api/widgets/{slug}/cache
Content-Type: application/json

{
  "data": {
    "packages": 142,
    "fetchedAt": "2026-02-03T18:30:00.000Z"
  }
}

Immediate Refresh via Webhook

For agent_refresh widgets, users can trigger immediate refreshes via the UI refresh button.

When configured with OPENCLAW_GATEWAY_URL and OPENCLAW_TOKEN environment variables, clicking the refresh button will:

  1. Store a refresh request in the database (fallback for polling)
  2. Immediately POST a wake notification to OpenClaw via /api/sessions/wake
  3. The agent receives a prompt to refresh that specific widget now

This eliminates the delay of waiting for the next heartbeat poll.

Environment variables (add to .env.local):

OPENCLAW_GATEWAY_URL=http://localhost:18789
OPENCLAW_TOKEN=your-gateway-token

How it works:

  1. User clicks refresh button on widget
  2. Glance POSTs to /api/widgets/{slug}/refresh
  3. If webhook configured, Glance immediately notifies OpenClaw: ⚡ WIDGET REFRESH: Refresh the "{slug}" widget now and POST to cache
  4. Agent wakes up, collects fresh data, POSTs to cache
  5. Widget re-renders with updated data

Response includes webhook status:

{
  "status": "refresh_requested",
  "webhook_sent": true,
  "fallback_queued": true
}

If webhook fails or isn't configured, the DB fallback ensures the next heartbeat/poll will pick it up.

Rules

  • Always include fetchedAt timestamp
  • Don't overwrite on errors - let widget use stale data
  • Use main session cron so YOU handle the collection, not an isolated agent

## Credential Requirements Format

### Credential Types

| Type | Storage | Description | Use For |
|------|---------|-------------|---------|
| `api_key` | Glance DB (encrypted) | API tokens stored in Glance | GitHub PAT, OpenWeather key |
| `local_software` | Agent's machine | Software that must be installed | Homebrew, Docker |
| `agent` | Agent environment | Auth that lives on the agent | `gh` CLI auth, `gcloud` auth |
| `oauth` | Glance DB | OAuth tokens (future) | Google Calendar |

### Examples

{ "credentials": [ { "id": "github", "type": "api_key", "name": "GitHub Personal Access Token", "description": "Token with repo scope", "obtain_url": "https://github.com/settings/tokens", "obtain_instructions": "Create token with 'repo' scope" }, { "id": "homebrew", "type": "local_software", "name": "Homebrew", "check_command": "which brew", "install_url": "https://brew.sh" }, { "id": "github_cli", "type": "agent", "name": "GitHub CLI", "description": "Agent needs gh CLI authenticated to GitHub", "agent_tool": "gh", "agent_auth_check": "gh auth status", "agent_auth_instructions": "Run gh auth login on the machine running OpenClaw" } ] }


**When to use `agent` type:** Use for `agent_refresh` widgets where the agent collects data using CLI tools that have their own auth (like `gh`, `gcloud`, `aws`). These credentials aren't stored in Glance — they exist in the agent's environment.

## Common Credential Providers

| Provider | ID | Description |
|----------|-----|-------------|
| GitHub | `github` | GitHub API (PAT with repo scope) |
| Anthropic | `anthropic` | Claude API (Admin key for usage) |
| OpenAI | `openai` | GPT API (Admin key for usage) |
| OpenWeather | `openweather` | Weather data API |
| Linear | `linear` | Linear API |
| Notion | `notion` | Notion API |

## Export/Import Packages

### Export

GET /api/widgets/{slug}/export


Returns: `{ "package": "!GW1!eJxVj8EKwj..." }`

### Import

POST /api/widgets/import Content-Type: application/json

{ "package": "!GW1!eJxVj8EKwj...", "dry_run": false, "auto_add_to_dashboard": true }


The `!GW1!` prefix indicates Glance Widget v1 format (compressed base64 JSON).

### Import Response with Cron

{ "valid": true, "widget": { "id": "cw_abc", "slug": "homebrew-status" }, "cronSchedule": { "expression": "*/15 * * * *", "instructions": "Run brew list...", "slug": "homebrew-status" } }


When `cronSchedule` is returned, OpenClaw should register a cron job.

## Key UI Components

| Component | Use For |
|-----------|---------|
| `Card` | Widget container (always use `className="h-full"`) |
| `List` | Items with title/subtitle/badge |
| `Stat` | Single metric with trend indicator |
| `Progress` | Progress bars with variants |
| `Badge` | Status labels (success/warning/error) |
| `Stack` | Flexbox layout (row/column) |
| `Grid` | CSS Grid layout |
| `Loading` | Loading spinner |
| `ErrorDisplay` | Error with retry button |

See [references/components.md](references/components.md) for full props.

## Hooks

// Fetch data (BOTH args required!) const { data, loading, error, refresh } = useData('github', {}); const { data } = useData('github', { endpoint: '/pulls', params: { state: 'open' } });

// Get widget config const config = useConfig();

// Widget-local state const { state, setState } = useWidgetState('counter', 0);


**⚠️ `useData` requires both arguments.** Pass empty `{}` if no query needed.

## Error Handling

if (error?.code === 'CREDENTIAL_MISSING') { return <Card><CardContent> <Icons.Lock className="h-8 w-8" /> <p>GitHub token required</p> </CardContent></Card>; }


Error codes: `CREDENTIAL_MISSING`, `RATE_LIMITED`, `NETWORK_ERROR`, `API_ERROR`

## Best Practices

1. **Always check credentials before creating widgets**
2. **Use meaningful names:** `github-prs-libra` not `widget-1`
3. **Include fetchedAt in all data** for staleness tracking
4. **Handle errors gracefully** with retry options
5. **Confirm actions:** "Done! Widget added to dashboard."
6. **Size appropriately:** Lists 1x1, charts 2x2

## Reading Dashboard Data

To summarize dashboard for user:
  1. GET /api/widgets/instances → list instances
  2. For each: POST /api/widgets/:slug/execute
  3. Combine into natural language summary

---

## ⚠️ Rules & Gotchas

1. **Use JSON Schema for generation** — `docs/schemas/widget-schema.json` enforces all required fields
2. **Browser verify EVERYTHING** — don't report success until you see the widget render correctly
3. **agent_refresh = YOU collect data** — the widget just displays what you POST to cache
4. **fetch.instructions is the source of truth** — cron jobs just send the slug, you look up instructions
5. **Always include fetchedAt** — widgets need timestamps for "Updated X ago" display
6. **data_schema is REQUIRED** — cache POSTs validate against it, malformed data returns 400
7. **credentials is REQUIRED** — use empty array `[]` if no credentials needed
8. **Don't wrap in Card** — the framework provides the outer card, you render content only
9. **Use Haiku for refresh subagents** — mechanical data collection doesn't need Opus
10. **Mark refresh requests as processed** — `DELETE /api/widgets/{slug}/refresh` after handling
11. **Spawn subagents for refreshes** — don't block main session with PTY/long-running work

## Environment Variables

| Variable | Description | Example |
|----------|-------------|---------|
| `GLANCE_URL` | Glance server URL | `http://localhost:3333` |
| `GLANCE_DATA` | Path to SQLite database | `/tmp/glance-test/data` |
| `OPENCLAW_GATEWAY_URL` | For webhook refresh notifications | `https://localhost:18789` |
| `OPENCLAW_TOKEN` | Gateway auth token | `d551fe97...` |

## Learnings (Feb 2026)

- **Webhook refresh works** — Glance POSTs to OpenClaw gateway, agent wakes immediately
- **Simple cron messages** — just `⚡ WIDGET REFRESH: {slug}`, agent looks up instructions
- **AI summaries need AI** — for recent-emails, YOU generate the summaries, not some API
- **icalBuddy for iCloud** — `gog calendar` doesn't work for iCloud, use `/opt/homebrew/bin/icalBuddy`
- **wttr.in for weather** — free, no API key, JSON format: `wttr.in/City?format=j1`

平台分布

OpenClaw

78.32%
按下载量换算13,417

安全审计

VirusTotal

可疑

ClawScan

可疑

Static analysis

未展示

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills