Agent skill
platform-api
Platform API reference for DenchClaw apps — UI integration, per-app storage, HTTP proxy, real-time events, inter-app messaging, cron scheduling, webhooks, clipboard, context, and widget mode.
Install this agent skill to your Project
npx add-skill https://github.com/DenchHQ/DenchClaw/tree/main/skills/app-builder/platform-api
Metadata
Additional technical details for this skill
- openclaw
-
{ "emoji": "\u26a1", "always": true, "inject": true }
SKILL.md
App Platform API
This skill documents the platform-level APIs available to DenchClaw apps. For core app structure, see the parent app-builder skill. For data/objects, see data-builder. For AI chat, see agent-builder.
UI Integration (ui permission required)
// Show a toast notification in the parent DenchClaw UI
await dench.ui.toast("Record saved successfully", { type: "success" });
await dench.ui.toast("Something went wrong", { type: "error" });
await dench.ui.toast("Processing...", { type: "info" });
// Navigate DenchClaw to a workspace path (opens object, file, or app)
await dench.ui.navigate("/people"); // open the people object
await dench.ui.navigate("/apps/my-app.dench.app"); // open another app
// Open an entry detail modal
await dench.ui.openEntry("people", "entry_id_here");
// Update the app's tab title dynamically
await dench.ui.setTitle("My App — 5 results");
// Show a confirmation dialog
const confirmed = await dench.ui.confirm("Delete this record?");
if (confirmed) { /* proceed */ }
// Show a prompt dialog
const name = await dench.ui.prompt("Enter a name:", "Default Name");
if (name !== null) { /* use name */ }
Per-App KV Store (store permission required)
Persistent key-value storage scoped to each app. Data survives app reloads and is stored in the workspace.
// Store a value (any JSON-serializable value)
await dench.store.set("lastQuery", { sql: "SELECT * FROM people", timestamp: Date.now() });
await dench.store.set("theme", "custom-dark");
await dench.store.set("counter", 42);
// Read a value
const lastQuery = await dench.store.get("lastQuery");
// Returns the value, or null if not found
// Delete a key
await dench.store.delete("lastQuery");
// List all keys
const keys = await dench.store.list();
// Returns ["theme", "counter"]
// Clear all stored data
await dench.store.clear();
Storage is backed by a JSON file at {workspace}/.dench-app-data/{appName}/store.json. Each app gets its own isolated namespace.
HTTP Proxy (http permission required)
Make HTTP requests from apps without CORS restrictions. Requests are proxied through the DenchClaw server.
// Simple GET
const data = await dench.http.fetch("https://api.example.com/data");
// Returns { status, statusText, headers, body }
// POST with headers and body
const result = await dench.http.fetch("https://api.example.com/submit", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer sk-..."
},
body: JSON.stringify({ query: "test" })
});
console.log(result.status); // 200
console.log(result.body); // response body as string
Security: requests to localhost, private IPs, and internal DenchClaw URLs are blocked.
Real-time Events (events permission required)
Subscribe to workspace events for live updates.
// Subscribe to theme changes
dench.events.on("theme.changed", (data) => {
document.body.className = data.theme;
});
// Subscribe to object entry changes
dench.events.on("object.entry.created", (data) => {
console.log(`New entry in ${data.objectName}: ${data.entryId}`);
refreshList();
});
dench.events.on("object.entry.updated", (data) => {
console.log(`Entry ${data.entryId} updated in ${data.objectName}`);
});
dench.events.on("object.entry.deleted", (data) => {
console.log(`Entry ${data.entryId} deleted from ${data.objectName}`);
});
// App visibility events
dench.events.on("app.visible", () => { resumeAnimations(); });
dench.events.on("app.hidden", () => { pauseAnimations(); });
// File change events
dench.events.on("file.changed", (data) => {
console.log(`File changed: ${data.path}`);
});
// Unsubscribe
dench.events.off("theme.changed");
Context (no permission required)
// Get workspace info
const workspace = await dench.context.getWorkspace();
// Returns { name, path, agentId }
// Get app info
const app = await dench.context.getAppInfo();
// Returns { appPath, folderName, permissions, manifest }
Inter-App Messaging (apps permission required)
Apps can communicate with other open apps for composite workflows.
// Send a message to another app
await dench.apps.send("analytics-dashboard.dench.app", {
action: "refresh",
filter: { status: "Active" }
});
// Listen for messages from other apps
dench.apps.on("message", (event) => {
console.log(`Message from ${event.from}:`, event.message);
if (event.message.action === "refresh") {
reloadData(event.message.filter);
}
});
// List currently active (open) apps
const activeApps = await dench.apps.list();
// Returns [{ name: "analytics-dashboard.dench.app", manifest: {...} }, ...]
Cron Scheduling (cron permission required)
Schedule recurring tasks that send messages to the agent.
// Schedule a cron job
const { jobId } = await dench.cron.schedule({
expression: "0 9 * * *", // 9 AM daily
message: "Generate the daily sales report and save it to workspace",
channel: "announce" // "announce" (delivers result) or "none" (silent)
});
// List all cron jobs
const jobs = await dench.cron.list();
// Returns array of { id, expression, message, enabled, nextRunAt, ... }
// Run a job immediately
await dench.cron.run(jobId);
// Cancel/remove a job
await dench.cron.cancel(jobId);
Webhooks (webhooks permission required)
Receive external HTTP webhooks inside your app.
// Register a webhook endpoint
const hook = await dench.webhooks.register("github-push");
console.log(hook.url);
// e.g. "https://your-denchclaw-host/api/apps/webhooks/my-app.dench.app/github-push"
// Listen for incoming webhooks
dench.webhooks.on("github-push", (payload) => {
console.log("Received webhook:", payload);
// payload: { method: "POST", headers: {...}, body: "...", receivedAt: 1234567890 }
processGithubPush(JSON.parse(payload.body));
});
// Poll for webhooks (useful for catching events received while app was closed)
const events = await dench.webhooks.poll("github-push", { since: lastTimestamp });
Clipboard (clipboard permission required)
// Write to clipboard
await dench.clipboard.write("Copied text content");
// Read from clipboard
const text = await dench.clipboard.read();
Note: clipboard operations are proxied through the parent DenchClaw window.
Widget Mode
Apps can render as compact widgets in a dashboard grid instead of full-page tabs.
Manifest Configuration
name: "Quick Stats"
display: "widget"
widget:
width: 2 # Grid columns (1-4)
height: 1 # Grid rows (1-4)
refreshInterval: 60 # Auto-refresh in seconds (optional)
permissions:
- database
Widget Design Guidelines
- Keep the UI compact — widgets have limited space
- Use large, readable numbers and minimal text
- Avoid scroll bars — all content should be visible
- Support both light and dark themes
- Use the refresh interval for auto-updating data
Widget Example
<!DOCTYPE html>
<html>
<head>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, sans-serif;
padding: 16px;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
}
body.dark { background: #0f0f1a; color: #e8e8f0; }
body.light { background: #fff; color: #1a1a2e; }
.metric { font-size: 48px; font-weight: 700; }
.label { font-size: 13px; opacity: 0.6; margin-bottom: 4px; }
</style>
</head>
<body>
<div class="label">Total Records</div>
<div class="metric" id="count">—</div>
<script>
async function init() {
const theme = await dench.app.getTheme().catch(() => "dark");
document.body.className = theme;
const result = await dench.db.query("SELECT SUM(entry_count) as total FROM objects");
document.getElementById("count").textContent = result.rows[0]?.total ?? 0;
}
init();
</script>
</body>
</html>
Widget-mode apps appear in the DenchClaw dashboard view alongside other widgets, arranged in a responsive grid.
Patterns
Multi-App Dashboard
Build a dashboard that aggregates data from multiple widget apps:
// In the main dashboard app
async function loadWidgetData() {
const apps = await dench.apps.list();
const widgets = apps.filter(a => a.manifest.display === "widget");
for (const widget of widgets) {
// Request data from each widget app
await dench.apps.send(widget.name, { action: "getData" });
}
}
dench.apps.on("message", (event) => {
if (event.message.action === "dataResponse") {
updateDashboardPanel(event.from, event.message.data);
}
});
External API Integration
// Fetch data from an external API via proxy
async function loadWeather(city) {
const result = await dench.http.fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=YOUR_KEY`
);
if (result.status === 200) {
const weather = JSON.parse(result.body);
displayWeather(weather);
}
}
Automation Workflow
// Set up a cron job that processes data and sends results
async function setupAutomation() {
const { jobId } = await dench.cron.schedule({
expression: "0 */6 * * *",
message: "Check the tasks object for overdue items and send a summary to Telegram"
});
await dench.store.set("automationJobId", jobId);
dench.ui.toast("Automation scheduled every 6 hours", { type: "success" });
}
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
dench-integrations
Connected app integration recipes for Dench Integrations (Gmail, Slack, GitHub, Notion, Google Calendar, Linear, Stripe, YouTube, and 500+ more)
gstack-workflow
Structured AI-assisted development workflow with specialist roles — Think, Plan, Build, Review, Test, Ship, Reflect. Adapted from garrytan/gstack (MIT).
plan-ceo-review
CEO/founder-mode plan review. Rethink the problem, find the 10-star product, challenge premises. Four modes: SCOPE EXPANSION, SELECTIVE EXPANSION, HOLD SCOPE, SCOPE REDUCTION. Use when reviewing strategy, questioning scope, or before engineering review.
investigate
Systematic root-cause debugging. Four phases: investigate, analyze, hypothesize, implement. Iron Law: no fixes without root cause investigation first. Use when debugging errors, unexpected behavior, or troubleshooting.
design-consultation
Build a complete design system from scratch. Research the landscape, propose safe choices AND creative risks, generate DESIGN.md. Use when creating a new design system or establishing design foundations for a project.
land-and-deploy
Merge the PR, wait for CI and deploy, verify production health. Takes over after ship. One command from "approved" to "verified in production."
Didn't find tool you were looking for?