agentleFS
DenchHQDenchHQ/ironclaw/skills/app-builder/platform-api/SKILL.md

platform-api

Skill1.7k starsChanged 7 months agoMITView on GitHub

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.

  • Sends data out

2 other projects use a version of this.

Trending

Quiet since February.thin dataabout the whole repository

Dec 2025: 0 mentionsJan 2026: 0 mentionsFeb 2026: 1 mentionMar 2026: 0 mentionsApr 2026: 0 mentionsMay 2026: 0 mentionsJun 2026: 0 mentionsJul 2026: 0 mentionsAug 2026: 0 mentionsSep 2026: 0 mentionsOct 2026: 0 mentionsNov 2026: 0 mentions
Dec 2025Jun 2026Nov 2026
Mentions a month of the DenchHQ/ironclaw repository that our weekly crawl found: only 1 in all, so this is a hint, not a trend. There is no adoption data for this file yet.

Most recently taken up by

Who's talking about DenchHQ/ironclaw

The biggest 1 of 1 mention linking to the repository that our crawl found. Each line is their own headline.

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 4 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Keep the UI compact — widgets have limited space

    line 246
  2. Distinctive:

    Use large, readable numbers and minimal text

    line 247
  3. Distinctive:

    Avoid scroll bars — all content should be visible

    line 248
  4. Distinctive:

    Use the refresh interval for auto-updating data

    line 250

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
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" });
}

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.