一键导入
widget-create
Creates a new Foundation blackboard widget — registers it in the ontology, scaffolds the Svelte component, and wires it into WidgetManager.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Creates a new Foundation blackboard widget — registers it in the ontology, scaffolds the Svelte component, and wires it into WidgetManager.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when reviewing pending code changes (working tree + staged) before commit. Checks against FOUNDATION conventions, architecture layer rules, validates compilation, and flags violations of CLAUDE.md / development.md rules.
Creates a new FOUNDATION release — bumps version, updates CHANGELOG, SoftwareRelease.ttl, README, commits, tags, and publishes a GitHub release.
Start the FOUNDATION dev server (npm run tauri dev) under PM2 management. Use when the app is not running and Claude needs it up (MCP, QA, visual validation) or the user asks to start the server.
Restart the FOUNDATION dev server via PM2, with optional Vite/SvelteKit cache clean. Use after config changes, when the Vite SSR module runner goes zombie (transport invoke timed out), or when the user asks for a restart.
Stop the FOUNDATION dev server managed by PM2, including orphan child cleanup (FOUNDATION.exe / cargo). Use when the user asks to stop the server or Claude needs a clean shutdown.
Use when the user asks to check for available dependency updates in FOUNDATION — phrases like "verifica atualizações de dependências", "o que tem pra atualizar", "tem versão nova das libs", "deps desatualizadas". Runs the Rust deps-check binary (npm + Cargo) and presents the report. Same check that runs automatically on the first session of each day.
| name | widget-create |
| description | Creates a new Foundation blackboard widget — registers it in the ontology, scaffolds the Svelte component, and wires it into WidgetManager. |
| disable-model-invocation | false |
!grep -n "widget_type\|import.*Widget" src/lib/components/widgets/WidgetManager.svelte | head -40
You are creating a new blackboard widget for Foundation. A widget is a live panel on the visual canvas, bound to one ontology entity, that reads its data from the triple store.
Start by calling search(class_iri: "foundation:WidgetType") to see all existing widget types and avoid duplicates.
If the user hasn't specified all details, ask for:
owl:Thing for universalUse assert_individual to create a foundation:WidgetType individual:
assert_individual(operations: [{
class_iri: "foundation:WidgetType",
label: "<Widget Name>",
comment: "<one-line description — shown as tooltip in Inspector header>",
icon: "<material-symbols-name>",
properties: [
{ property_iri: "foundation:hasStatus", values: ["foundation:Status_1772755611667"] },
{ property_iri: "foundation:widgetTypeId", values: ["<type_id>"] },
{ property_iri: "foundation:widgetSupportedClass", values: ["<class_iri or owl:Thing>"] },
{ property_iri: "foundation:widgetDefaultWidth", values: ["480"] },
{ property_iri: "foundation:widgetDefaultHeight", values: ["600"] }
]
}])
Always add a widgetUsageNote explaining when and why the AI should use this widget, followed by how to display it:
{ property_iri: "foundation:widgetUsageNote", values: ["<WHY: when to use this widget — then HOW: pass the entity IRI in speak.iris>"] }
If the widget requires a dedicated entity to be created first (e.g. a foundation:MermaidDiagram individual), the HOW section must describe that creation workflow before the speak.iris step.
Confirm the IRI returned before proceeding.
Create src/lib/components/widgets/<PascalCaseName>Widget.svelte.
Use this minimal structure:
<script>
import { onMount, onDestroy } from 'svelte';
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
let { widgetId, entityId = '' } = $props();
let entityData = $state(null);
let loading = $state(true);
let error = $state(null);
async function loadData() {
if (!entityId) return;
try {
const result = await invoke('entity__get', { entityId });
entityData = JSON.parse(result);
} catch (err) {
error = err?.toString() ?? 'Failed to load';
} finally {
loading = false;
}
}
async function closeWidget() {
await invoke('widget_blackboard__remove_widget', { widgetId });
}
let unlistenEntityUpdated;
onMount(async () => {
await loadData();
unlistenEntityUpdated = await listen('entity-updated', async (event) => {
if (event.payload.entityId === entityId) await loadData();
});
});
onDestroy(() => {
unlistenEntityUpdated?.();
});
</script>
<div class="widget">
<!-- widget-header is required — WidgetManager attaches drag listeners to it -->
<div class="widget-header">
<span class="material-symbols-outlined"><!-- icon --></span>
<span class="title">{entityData?.label ?? entityId}</span>
<button class="close-btn" onclick={closeWidget}>
<span class="material-symbols-outlined">close</span>
</button>
</div>
<div class="widget-content">
{#if loading}
<div class="loading">
<span class="material-symbols-outlined spinning">progress_activity</span>
</div>
{:else if error}
<div class="error">{error}</div>
{:else}
<!-- widget body -->
{/if}
</div>
</div>
Two contracts must be respected:
widget-header must exist — WidgetManager attaches drag listeners to it.invoke('widget_blackboard__remove_widget', { widgetId }) to close.Adapt the body for the widget's purpose using entityData.properties for entity data.
Edit src/lib/components/widgets/WidgetManager.svelte:
<script>:import <PascalCaseName>Widget from './<PascalCaseName>Widget.svelte';
{#each widgets} dispatch block, after the last {:else if}:{:else if widget.widget_type === '<type_id>'}
<<PascalCaseName>Widget widgetId={widget.id} entityId={widget.entity_id} />
Run cargo check to confirm no Rust regressions (the ontology registration requires no Rust changes):
cargo check --manifest-path src-tauri/Cargo.toml
Confirm with the user that the widget appears correctly in the Inspector header when an entity of the supported class is open.
foundation:Widget_{type_id}_{entity_id}. Adding a widget that already exists is a no-op.widgetUsageNote must lead with WHY — purpose first, creation steps second. This text is shown directly to the AI in the system prompt.widget-header class is mandatory — without it, drag doesn't work.