Install
openclaw skills install mindstudio-to-api-custom-function-builderBuild a complete MindStudio Run Function integration for any API the user wants to connect. Use this skill whenever the user mentions MindStudio, wants to connect an API to a workflow, asks for a "Run Function", wants to call an external service from MindStudio, or says things like "I want to use X API in MindStudio", "build me a MindStudio function for X", "how do I connect X to MindStudio", or "write me a script for MindStudio". Always use this skill — do not try to wing it from memory.
openclaw skills install mindstudio-to-api-custom-function-builderProduce a complete, ready-to-paste MindStudio custom function for any API the user wants to connect. Always output all three sections: Code Tab, Configuration Tab, and Test Data Tab.
Before writing, collect (from the conversation or by asking):
research_effort, language, model, etc.)If the user pastes API docs or a code example, extract all of the above from it directly. Only ask for what's missing.
Always produce exactly these three sections, in this order, formatted as fenced code blocks.
Rules:
ai.config.*inputVariable type config fields are resolved by MindStudio BEFORE the code runs. The value arrives as a plain string. Always read them as ai.config.fieldName directly. NEVER use ai.vars[ai.config.fieldName] for inputs.outputVariableName type config fields hold the NAME of a workflow variable chosen by the user. Always write outputs as ai.vars[ai.config.outputVarName] = value so results land in the right place.ai.log(...) to show progress to the user during long callsawait fetch(...) for HTTP calls — no imports needed in Sandboxinput not query for You.com APIs (learned fix)handler async functionTemplate structure:
// --- Read config ---
const apiKey = ai.config.apiKey;
const inputVal = ai.config.inputField; // inputVariable type: value is already resolved, read directly from ai.config
const optional = ai.config.optionalField || "default_value";
// --- Validate ---
if (!apiKey) throw new Error("Missing API key. Set it in block configuration.");
if (!inputVal) throw new Error("Missing [field]. Provide it in block configuration.");
ai.log("Calling [API name]...");
// --- Request ---
const url = "https://api.example.com/endpoint";
const res = await fetch(url, {
method: "POST", // or GET, etc.
headers: {
"Authorization": `Bearer ${apiKey}`, // adjust per API auth style
"Content-Type": "application/json"
},
body: JSON.stringify({
field: inputVal,
option: optional
})
});
if (!res.ok) {
const err = await res.text();
throw new Error(`[API name] error (${res.status}): ${err}`);
}
const data = await res.json();
ai.log("Done. Storing results...");
// --- Store outputs ---
// outputVariableName type: user names the variable, so use ai.vars[ai.config.outputMain] pattern
ai.vars[ai.config.outputMain] = data.someField ?? JSON.stringify(data);
ai.vars[ai.config.outputRaw] = JSON.stringify(data);
Rules:
"secret" type for API keys — never "text""inputVariable" type for fields that should accept a {{variable}} from the workflow. MindStudio resolves the value before code runs — read it in code as ai.config.fieldName, not via ai.vars"select" type with selectOptions for fixed-choice fields (e.g. model names, effort levels)"outputVariableName" type for fields where the user names their output variablestitle valueshelpText to every itemTemplate:
config = {
configurationSections: [
{
title: "API Settings",
items: [
{
type: "secret",
label: "API Key",
variable: "apiKey",
helpText: "Your [API name] API key. Stored securely, not transferred on remix."
},
{
type: "inputVariable",
label: "Input Field Label",
variable: "inputField",
helpText: "Description of what this input does. Use a {{variable}} from your workflow or type a value directly."
},
{
type: "select",
label: "Option Label",
variable: "optionalField",
helpText: "Description of this option.",
selectOptions: [
{ label: "Option A", value: "value_a" },
{ label: "Option B", value: "value_b" }
]
}
]
},
{
title: "Output",
items: [
{
type: "outputVariableName",
label: "Main Output Variable",
variable: "outputMain",
helpText: "Workflow variable where the main result will be stored."
},
{
type: "outputVariableName",
label: "Raw Response Variable",
variable: "outputRaw",
helpText: "Workflow variable for the full raw JSON response."
}
]
}
]
}
Rules:
ai.config.* variable used in the codeinputVariable type fields, set the value directly in config (not in vars) — e.g. inputField: "AAPL". MindStudio does not require a vars entry for these during testing.Template:
environment = {
vars: {},
config: {
apiKey: "your-api-key-here",
inputField: "A realistic example input for this API",
optionalField: "value_a",
outputMain: "result",
outputRaw: "resultJSON"
}
}
| Auth type | Header / approach |
|---|---|
| API key header | "X-API-Key": apiKey |
| Bearer token | "Authorization": \Bearer ${apiKey}`` |
| Basic auth | "Authorization": "Basic " + btoa(user + ":" + pass) |
| No auth | Omit headers object or leave empty |
Sandbox (default — use unless told otherwise):
fetch, JSON, ai.* methods all availableURLSearchParams, Buffer, process, require, crypto, fs, or pathVirtual Machine (use when npm packages needed):
handler function:import * as someLib from 'some-lib';
export const handler = async () => {
// your code here
ai.vars.result = someLib.doSomething();
};
ai.vars[ai.config.fieldName] for input fields. inputVariable type config fields are resolved by MindStudio before the code runs and arrive as plain strings via ai.config.fieldName. Only use the ai.vars[ai.config.outputVarName] pattern for output variables where the user has named where results should land.URLSearchParams in Sandbox — it is not available. Build query strings manually instead:
let query = "?token=" + apiKey;
if (symbol) query += "&symbol=" + encodeURIComponent(symbol);
const url = "https://api.example.com/endpoint" + query;
Buffer, process, require, crypto, or fs in Sandbox — these are Node.js APIs not available therequery as a body field for You.com APIs — use input{{variables}} into HTML — use <script type="application/json"> insteadai.config.apiKey with "secret" typeai.vars.outputName = value when the output variable name is user-configured — use ai.vars[ai.config.outputVarName] = valueai.vars insteadAlways end with a short note explaining: