skills/moldable-apps/SKILL.md
Complete guide for building Moldable apps. Use this skill when creating new apps with scaffoldApp, modifying existing apps, implementing workspace-aware storage, integrating with the Moldable desktop via postMessage APIs (moldable:show-in-folder, moldable:set-chat-input, moldable:set-chat-instructions, moldable:save-file), configuring workspaces, managing skills/MCPs, or troubleshooting app issues. Essential for any Moldable app development task.
npx skillsauth add moldable-ai/skills moldableInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill provides comprehensive knowledge for building and modifying apps within the Moldable desktop application.
| Resource | Path |
| ---------------- | ----------------------------------------------------------- |
| App source code | ~/.moldable/shared/apps/{app-id}/ |
| App runtime data | ~/.moldable/workspaces/{workspace-id}/apps/{app-id}/data/ |
| Workspace config | ~/.moldable/workspaces/{workspace-id}/config.json |
| MCP config | ~/.moldable/shared/config/mcp.json |
| Skills | ~/.moldable/shared/skills/{repo}/{skill}/ |
| Environment | ~/.moldable/shared/.env |
@moldable-ai/storageMOLDABLE_APP_URL; Hono server reloads via tsx watchALWAYS use the scaffoldApp tool — never create app files manually.
scaffoldApp({
appId: "expense-tracker", // lowercase, hyphens only
name: "Expense Tracker", // Display name
icon: "💰", // Emoji icon
description: "Track expenses and generate reports",
extraDependencies: {
// Optional npm packages
zod: "^3.0.0",
},
});
After scaffolding, customize:
src/client/app.tsx — Main app viewsrc/server/app.ts or src/server/routes/ — Hono API routes (including /api/moldable/health and /api/moldable/today)src/client/components/ or src/components/ — React componentsThe home screen is the host-rendered Today view. Apps participate by implementing GET /api/moldable/today, which returns items/resume only when something genuinely needs the user (quiet by default). See references/today.md.
Read these for in-depth guidance:
GET /api/moldable/today, item kinds, actions, and the "quiet by default" rules.For any visible app UI, read references/design.md before editing src/client/app.tsx or client components. The design reference is self-contained and does not require other apps to be installed.
Always use @moldable-ai/ui for all UI work. It includes shadcn/ui components, theme support, and a rich text editor.
// Import components from @moldable-ai/ui (NOT from shadcn directly)
import {
Button,
Card,
Input,
Dialog,
Select,
Tabs,
ThemeProvider,
WorkspaceProvider,
useTheme,
Markdown,
CodeBlock,
downloadFile,
sendToMoldable,
} from "@moldable-ai/ui";
// For rich text editing
import { MarkdownEditor } from "@moldable-ai/editor";
Use semantic colors only:
// ✅ Correct
<div className="bg-background text-foreground border-border" />
<Button className="bg-primary text-primary-foreground" />
// ❌ Wrong - raw colors don't adapt to theme
<div className="bg-white text-gray-900" />
See references/ui.md for complete component list and usage.
All apps must isolate data per workspace:
// Client - use workspaceId in query keys
const { workspaceId, fetchWithWorkspace } = useWorkspace();
const { data } = useQuery({
queryKey: ["items", workspaceId], // ← Include workspace!
queryFn: () => fetchWithWorkspace("/api/items").then((r) => r.json()),
});
// Server - extract workspace from request
import { getWorkspaceFromRequest, getAppDataDir } from "@moldable-ai/storage";
export async function GET(request: Request) {
const workspaceId = getWorkspaceFromRequest(request);
const dataDir = getAppDataDir(workspaceId);
// Read/write files in dataDir
}
Apps communicate with Moldable desktop via postMessage:
// Open external URL
window.parent.postMessage(
{ type: "moldable:open-url", url: "https://..." },
"*",
);
// Show file in Finder
window.parent.postMessage(
{ type: "moldable:show-in-folder", path: "/path/to/file" },
"*",
);
// Pre-populate chat input
window.parent.postMessage(
{ type: "moldable:set-chat-input", text: "Help me..." },
"*",
);
// Provide context to AI
window.parent.postMessage(
{
type: "moldable:set-chat-instructions",
text: "User is viewing meeting #123...",
},
"*",
);
Required providers for Moldable apps:
// src/client/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { ThemeProvider, WorkspaceProvider } from "@moldable-ai/ui";
import { App } from "./app";
import { QueryProvider } from "./query-provider";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<ThemeProvider>
<WorkspaceProvider>
<QueryProvider>
<App />
</QueryProvider>
</WorkspaceProvider>
</ThemeProvider>
</StrictMode>,
);
Use sandbox: false for package manager commands:
await runCommand({
command: "cd ~/.moldable/shared/apps/my-app && pnpm add zod",
sandbox: false, // Required for network access
});
| Tool | Purpose | Reversible |
| --------------- | ------------------------------------------ | ------------------ |
| scaffoldApp | Create new app | — |
| getAppInfo | Check which workspaces use an app | — |
| unregisterApp | Remove from current workspace only | ✅ Re-add later |
| deleteAppData | Delete app's data (keep installed) | ❌ Data lost |
| deleteApp | Permanently delete from ALL workspaces | ❌ Everything lost |
~/.moldable/
├── shared/
│ ├── apps/{app-id}/ # App source code
│ │ ├── moldable.json # App manifest
│ │ ├── package.json
│ │ └── src/
│ ├── skills/{repo}/{skill}/ # Skills library
│ ├── mcps/{mcp-name}/ # Custom MCP servers
│ └── config/mcp.json # Shared MCP config
│
└── workspaces/{workspace-id}/
├── config.json # Registered apps
├── .env # Workspace env overrides
├── apps/{app-id}/data/ # App runtime data
└── conversations/ # Chat history
scaffoldApp@moldable-ai/storage; browser storage is only acceptable for disposable same-session UI state.getAppDataDir() for portabilitybg-background, not bg-gray-100)sandbox: false for network accessFor complex features, reference apps in ~/.moldable/shared/apps/:
These demonstrate data fetching, storage patterns, API routes, and UI components.
development
Search, scrape, crawl, map, parse, and operate Firecrawl browser/agent workflows through aivault-backed Firecrawl API capabilities. No Firecrawl API key is read by the skill runtime.
data-ai
Manage Trello boards/lists/cards via aivault-backed capabilities (no Trello key/token in skill runtime).
documentation
Manage Todoist tasks/projects/comments via aivault-backed capabilities (no Todoist token in skill runtime).
development
Transcribe local audio files with OpenAI speech-to-text through aivault capability json (no provider API key in skill runtime).