Install
openclaw skills install pulse-app-skillUse this skill to help developers get started building Pulse Apps — full-stack React extensions for Pulse Editor that use Module Federation. Trigger when a u...
openclaw skills install pulse-app-skillA Pulse App is a module-federated, full-stack React extension that can run standalone or integrate into the Pulse Editor platform. Pulse Editor acts primarily as a hosting environment for these modular apps.
my-pulse-app/
├── pulse.config.ts # App metadata & Pulse Editor configuration
├── package.json
├── tsconfig.json
├── src/
│ ├── main.tsx # Frontend entry point (React UI)
│ ├── tailwind.css
│ ├── server-function/ # Backend endpoints (file path = URL path)
│ │ └── echo.ts # → POST /server-function/echo
│ └── skill/ # Agentic skills (AI-callable actions)
│ └── example-skill/
│ ├── SKILL.md # Skill definition (Anthropic YAML frontmatter format)
│ └── action.ts # Action handler (default export function)
pulse create
npm run dev
# Hosts at http://localhost:3030
# Register in Pulse Editor → Settings
npm run preview
# Note: Inter-Module-Communication features won't work in preview mode
npm run build # Full build (client + server)
npm run build-client # Frontend only
npm run build-server # Backend only
src/main.tsxThe single React entry point rendered by Pulse Editor as an extension UI. Uses Tailwind CSS for styling.
@pulse-editor/react-apiimport { useLoading, useActionEffect } from "@pulse-editor/react-api";
// useLoading — manage loading states
const { isLoading, setLoading } = useLoading();
// useActionEffect — register a handler for an app action
useActionEffect("mySkillName", {
beforeAction: (input) => {
setLoading(true);
return input; // optionally transform input
},
afterAction: (output) => {
setLoading(false);
console.log("Action completed:", output);
},
});
const response = await fetch("/server-function/echo", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message: "hello" }),
});
const data = await response.json();
src/server-function/Files in this directory are automatically mapped to HTTP endpoints:
| File path | Endpoint |
|---|---|
src/server-function/echo.ts | POST /server-function/echo |
src/server-function/hello/hello-world.ts | POST /server-function/hello/hello-world |
// src/server-function/echo.ts
import { Request, Response } from "express";
export default async function handler(req: Request, res: Response) {
const { message } = req.body;
res.json({ echo: message });
}
src/skill/Skills are agentic capabilities — actions callable by AI agents, frontend components via useActionEffect, or Pulse Editor's automation platform.
Each skill lives in its own subdirectory with two files:
SKILL.md — Skill definition (Anthropic YAML frontmatter format)---
name: mySkill
description: Brief description of what this skill does
---
# My Skill
Longer description for the AI agent about when and how to use this skill.
action.ts — Action handler// src/skill/my-skill/action.ts
type Input = {
/** The main text to process */
text: string;
/** Optional count parameter */
count?: number;
};
type Output = {
result: string;
processedCount: number;
};
/**
* Default export is the action handler.
* Input/Output types + JSDoc comments are used for AI agent documentation.
*/
export default function mySkill({ text, count = 1 }: Input): Output {
return {
result: text.repeat(count),
processedCount: count,
};
}
pulse skill create
pulse.config.tsimport { AppConfig } from "@pulse-editor/shared-utils";
import pkg from "./package.json";
const config: AppConfig = {
id: pkg.name, // Must match package name — NO hyphens
version: pkg.version,
libVersion: pkg.dependencies["@pulse-editor/react-api"],
displayName: pkg.displayName,
description: pkg.description,
visibility: "unlisted", // or "public"
recommendedHeight: 640,
recommendedWidth: 360,
thumbnail: "./src/assets/thumbnail.png",
};
export default config;
Important: The
idfield must not contain hyphens. Use underscores or camelCase instead.
App Actions are the primary integration mechanism in Pulse Apps. They:
action.ts default exportSKILL.md definition)useActionEffect)beforeAction / afterAction PipelineThese work like middleware around action execution:
beforeAction(input) — runs before the action; return value becomes the action's input (use for UI state setup, input transformation)afterAction(output) — runs after the action completes (use for UI state teardown, handling results)const { isLoading, setLoading } = useLoading();
useActionEffect("processData", {
beforeAction: (input) => { setLoading(true); return input; },
afterAction: (output) => {
setLoading(false);
setResult(output.result);
},
});
// src/server-function/my-api.ts
import "dotenv/config";
export default async function handler(req, res) {
const apiKey = process.env.MY_API_KEY;
// ...
}
npm run dev), not preview mode@pulse-editor/react-api — React hooks for Pulse Editor integration@pulse-editor/shared-utils — Shared types including AppConfigpulse create, pulse skill create