Workbench Widget Management
This skill handles widget lifecycle management (scaffolding, querying, compile verification). Coding details (SDK API, component authoring, security sandbox) live in the generate-dynamic-widget skill — when you need to write code, first LoadSkill(skillName: "generate-dynamic-widget").
Tool Inventory
| Tool |
Responsibility |
Read-only |
WidgetInit |
Generate the widget scaffold directory (~/.openloaf/dynamic-widgets/<id>/) |
No |
WidgetList |
List all created widgets |
Yes |
WidgetGet |
Read details of a single widget |
Yes |
WidgetCheck |
Compile widget (TypeScript) + trigger live preview refresh |
Yes |
GenerateWidget |
Widget code generation (see generate-dynamic-widget skill) |
No |
Read |
Widget code reading (always-available tool) |
Yes |
Edit |
Widget code editing (always-available tool) |
No |
Loading: Read / Edit are always available; WidgetInit / WidgetList / WidgetGet / WidgetCheck / GenerateWidget must be activated via ToolSearch(names: "WidgetInit,WidgetList,WidgetGet,WidgetCheck,GenerateWidget") before calling, to load their schemas.
Decision Tree
User wants a Widget
├── Does one already exist?
│ ├── Yes → WidgetList → WidgetGet → Read → understand the current state
│ │ └── Needs code changes → ToolSearch(names: "generate-dynamic-widget")
│ │ └── Edit → WidgetCheck
│ └── No → Create a new Widget (see flow below)
└── Just querying / browsing?
└── WidgetList / WidgetGet is enough
Modify vs Rebuild Decision
When the user wants to change an existing Widget:
- Modify existing (Edit): user says "add an X feature", "change the color", "show one more field" → incremental edit on existing code
- Recreate (WidgetInit): fundamental change, e.g. from "weather component" to "stock ticker", or a completely different overall architecture / layout → create a new Widget to replace it
Creating a New Widget (must follow this order)
WidgetInit — generate the scaffold directory
- Why init first? Because it creates the correct directory structure (
~/.openloaf/dynamic-widgets/<id>/), package.json, and type stub files. Skipping this and writing files directly will cause the compiler to fail to find type definitions.
ToolSearch(names: "generate-dynamic-widget") — load the coding conventions
Write — write widget.tsx (the frontend component)
Write — write functions.ts (server-side functions, if needed)
WidgetCheck — compile + trigger live preview
- Why must check run last? Because it runs the TypeScript compile and notifies the frontend to refresh the preview. Without calling check, the user still sees the old content.
Modifying an Existing Widget
WidgetList → WidgetGet → Read — locate and read the source
Edit — precise search-and-replace modification
WidgetCheck — verify via compile
Recovering from WidgetCheck Compile Failures
When WidgetCheck returns compile errors:
- Read the error — focus on the TypeScript error line number and description
- Common errors and fixes:
Cannot find module 'xxx' → widget.tsx may only import react, react/jsx-runtime, @openloaf/widget-sdk; remove the forbidden import
Type 'xxx' is not assignable → check SDK type definitions and confirm props/state types match
JSX element type does not have any construct → check that the component export is correct (must be export default)
- Fix with
Edit → run WidgetCheck again, repeat until compile passes
Widget Capability Boundaries
Good fits:
- Data display (charts, stat cards, lists)
- Simple interactions (buttons, toggles, input fields)
- Scheduled polling of APIs for data (via functions.ts server-side functions)
- Static or low-frequency content (weather, calendar, todo, clock, pomodoro)
Poor fits:
- Complex multi-page flows (use a standalone page instead)
- Heavy computation (server-side functions have a 10-second timeout)
- Real-time WebSocket long connections (not supported by the sandbox)
- Operations needing local filesystem access (isolated by the security sandbox)
Key Constraints
- Widget code directory:
~/.openloaf/dynamic-widgets/<widget-id>/
widget.tsx may only import: react, react/jsx-runtime, @openloaf/widget-sdk
functions.ts executes on the Server side with a 10-second timeout
- Sensitive information (API keys, etc.) is injected via
.env under the widget directory — never hardcode
1---2name: workbench-ops-skill-23description: Triggered when the user wants to add, modify, view, or delete widgets (desktop components / mini apps / dashboard cards) on the OpenLoaf workbench / desktop. Typical phrasings: "add a weather widget", "build a pomodoro component", "change the color of this widget". **Not for**: one-off chart rendering inside a chat message (→visualization-ops-skill), AI image generation (→cloud-media-skill), casually mentioning "clock / countdown" in conversation (→answer directly).4---56# Workbench Widget Management78This skill handles widget lifecycle management (scaffolding, querying, compile verification). Coding details (SDK API, component authoring, security sandbox) live in the `generate-dynamic-widget` skill — when you need to write code, first `LoadSkill(skillName: "generate-dynamic-widget")`.910## Tool Inventory1112| Tool | Responsibility | Read-only |13|------|----------------|-----------|14| `WidgetInit` | Generate the widget scaffold directory (`~/.openloaf/dynamic-widgets/<id>/`) | No |15| `WidgetList` | List all created widgets | Yes |16| `WidgetGet` | Read details of a single widget | Yes |17| `WidgetCheck` | Compile widget (TypeScript) + trigger live preview refresh | Yes |18| `GenerateWidget` | Widget code generation (see `generate-dynamic-widget` skill) | No |19| `Read` | Widget code reading (always-available tool) | Yes |20| `Edit` | Widget code editing (always-available tool) | No |2122> **Loading**: `Read` / `Edit` are always available; `WidgetInit` / `WidgetList` / `WidgetGet` / `WidgetCheck` / `GenerateWidget` must be activated via `ToolSearch(names: "WidgetInit,WidgetList,WidgetGet,WidgetCheck,GenerateWidget")` before calling, to load their schemas.2324## Decision Tree2526```27User wants a Widget28├── Does one already exist?29│ ├── Yes → WidgetList → WidgetGet → Read → understand the current state30│ │ └── Needs code changes → ToolSearch(names: "generate-dynamic-widget")31│ │ └── Edit → WidgetCheck32│ └── No → Create a new Widget (see flow below)33└── Just querying / browsing?34 └── WidgetList / WidgetGet is enough35```3637## Modify vs Rebuild Decision3839When the user wants to change an existing Widget:4041- **Modify existing** (Edit): user says "add an X feature", "change the color", "show one more field" → incremental edit on existing code42- **Recreate** (WidgetInit): fundamental change, e.g. from "weather component" to "stock ticker", or a completely different overall architecture / layout → create a new Widget to replace it4344## Creating a New Widget (must follow this order)45461. **`WidgetInit`** — generate the scaffold directory47 - Why init first? Because it creates the correct directory structure (`~/.openloaf/dynamic-widgets/<id>/`), package.json, and type stub files. Skipping this and writing files directly will cause the compiler to fail to find type definitions.482. **`ToolSearch(names: "generate-dynamic-widget")`** — load the coding conventions493. **`Write`** — write widget.tsx (the frontend component)504. **`Write`** — write functions.ts (server-side functions, if needed)515. **`WidgetCheck`** — compile + trigger live preview52 - Why must check run last? Because it runs the TypeScript compile and notifies the frontend to refresh the preview. Without calling check, the user still sees the old content.5354## Modifying an Existing Widget55561. `WidgetList` → `WidgetGet` → `Read` — locate and read the source572. `Edit` — precise search-and-replace modification583. `WidgetCheck` — verify via compile5960## Recovering from WidgetCheck Compile Failures6162When `WidgetCheck` returns compile errors:63641. **Read the error** — focus on the TypeScript error line number and description652. **Common errors and fixes**:66 - `Cannot find module 'xxx'` → widget.tsx may only import `react`, `react/jsx-runtime`, `@openloaf/widget-sdk`; remove the forbidden import67 - `Type 'xxx' is not assignable` → check SDK type definitions and confirm props/state types match68 - `JSX element type does not have any construct` → check that the component export is correct (must be `export default`)693. **Fix with `Edit`** → run `WidgetCheck` again, repeat until compile passes7071## Widget Capability Boundaries7273**Good fits**:74- Data display (charts, stat cards, lists)75- Simple interactions (buttons, toggles, input fields)76- Scheduled polling of APIs for data (via functions.ts server-side functions)77- Static or low-frequency content (weather, calendar, todo, clock, pomodoro)7879**Poor fits**:80- Complex multi-page flows (use a standalone page instead)81- Heavy computation (server-side functions have a 10-second timeout)82- Real-time WebSocket long connections (not supported by the sandbox)83- Operations needing local filesystem access (isolated by the security sandbox)8485## Key Constraints8687- Widget code directory: `~/.openloaf/dynamic-widgets/<widget-id>/`88- `widget.tsx` may only import: `react`, `react/jsx-runtime`, `@openloaf/widget-sdk`89- `functions.ts` executes on the Server side with a 10-second timeout90- Sensitive information (API keys, etc.) is injected via `.env` under the widget directory — never hardcode