AI prompts for writing code
Prefer to use your own AI? Every code editor in FlowFn has an AI prompt button. Click it to copy a ready-made prompt that teaches any external AI (ChatGPT, Claude, etc.) FlowFn's exact runtime and capability API for that surface — then describe what you want, and paste the generated code back into the editor. The same prompts are below; replace the <DESCRIBE WHAT YOU WANT> line with your task.
These describe the live APIs. If something doesn't work, check the feature's own docs page — the editor button always has the current version.
Playground server code (the Server tab)
Write FlowFn playground SERVER code (the "Server" tab). It runs in a sandboxed V8 isolate on FlowFn's backend — no require, no process, no fetch/network except through the ctx capabilities below. Output ONLY JavaScript.
Declare functions as: module.exports.<name> = async (args, ctx) => { ... }
The page calls them with flowfn.server.call('<name>', args); args is the JSON the caller passed; return a JSON-serializable value (<=1MB). Each ctx.* call counts toward a 50-call budget; 25s timeout.
ctx capabilities:
- ctx.sheets (the linked Database): list(), listRows(slug,{offset,limit}), query(slug,query), getRow(slug,rowId), insertRow(slug,cells), updateRow(slug,rowId,cells), deleteRow(slug,rowId). (No databaseId arg -> the playground's linked DB.)
- ctx.tools.invoke(keyName, inputs) — run a configured @key platform/AI action with the team's credentials.
- ctx.fetch(refKey, inputs) — run a configured Fetch-tab entry.
- ctx.http.fetch(url, opts) / .get / .head — SSRF-guarded outbound HTTP to PUBLIC urls only.
- ctx.workflows.run(workflowId, input) -> {run_id}; ctx.agents.run(agentId, input) -> {job_id} (fire-and-forget, same team).
- ctx.streams.publish(streamCode, room, channel, payload).
- ctx.auth (only when end-user auth is enabled). PREFER the one-call flows: login(identifier, password, { type? }) -> { userId, user, type }; signup(fields, { type?, autoLogin? }) -> { userId, user } (hashes the password for you); changePassword(rowId, oldPassword, newPassword); requestPasswordReset(identifier) -> { ok, code } (YOU deliver the code via email/SMS, never to the browser; needs an OTP column); resetPassword(identifier, code, newPassword); logout(). Lower-level primitives: hashPassword(pw), verifyPassword(rowId, pw), createSession(rowId), destroySession(), currentUser() -> { userId, user, cells } | null, decryptField(rowId, col), generateOtp(), verifyOtp(code, hash), signResetToken(rowId), verifyResetToken(token, hash), revokeSessions(rowId), rateLimit(username). No ctx.auth.hash — use hashPassword or signup. THE user OBJECT (returned by login/signup/currentUser; currentUser also aliases it as cells) is the user row's CELLS keyed by your user-sheet COLUMN name, with secured columns redacted — there is NO top-level user.email/user.name. Read fields by column, e.g. const me = await ctx.auth.currentUser(); const email = me && me.user.email (assumes a column named email).
- ctx.env.KEY — resolved env vars (plain + secure; server-only).
Globals: console.*, await sleep(ms) (<=5000), atob, btoa. No Buffer, no require, no bare fetch.
Now write a function that: <DESCRIBE WHAT YOU WANT>
Playground page code (HTML / CSS / JS)
Write the CLIENT-side HTML / CSS / JS for a FlowFn playground page. It runs in a sandboxed iframe (origin null) — it CANNOT call your backend or /api directly. Use the injected window.flowfn SDK for all data + actions. Output the HTML, CSS, and JS the task needs.
window.flowfn SDK:
- flowfn.server.call(fnName, args) -> calls a Server-tab function, resolves its return value.
- flowfn.data.*: get(slug) (loaded rows, sync), fetch(slug) (async), query(slug, q) -> {items,total}, insert(slug, cells), update(slug, rowId, cells), delete(slug, rowId), findRow(slug, where).
- flowfn.invoke(keyName, inputs) — fire a bound @key action; flowfn.fire(triggerKey) — fire a trigger; flowfn.fetchData(refKey, inputs) — run a Fetch entry.
- flowfn.upload(fileOrInput, opts) -> {id,url,...}; flowfn.state.get/set(key, val, {persist}) (per-user KV); flowfn.navigate(path).
- flowfn.userId — signed-in end-user id (or null); flowfn.currentPage — current page slug ('' on home); flowfn.env — PLAIN env only; flowfn.on('ready'|'load'|'navigate', cb).
Data binding: add data-key="x" to an element and define a matching @key (input | text | trigger | js_value | action). FlowFn templates (runtime): {{ expr }} interpolation, <template ff-if="expr">...</template>, <template ff-each="(item, i) in expr">...</template>, and ff-html="expr" for raw HTML.
Now build a page that: <DESCRIBE WHAT YOU WANT>
Workflow Code task
Write a FlowFn workflow "Code" task (one step of an automation). It runs in a sandboxed isolate (30s, no network, no require). Output ONLY the function body (JavaScript), no wrapper.
Your code runs as: async ({ inputs, workflow, workflowRun, task, taskRun }, ctx) => { ...your code... }
So in scope you have:
- inputs — this task's resolved inputs (object).
- workflowRun.tasks — prior tasks: [{ reference_code, title, type, status, inputs, outputs }] — read UPSTREAM outputs here. Also workflowRun.trigger.inputs.
- ctx.sheets(databaseId) — list / listRows / query / insertRow / updateRow / deleteRow(slug, ...). You MUST pass an explicit databaseId (no linked DB here; no getRow).
You MUST return an object whose keys match the task's declared OUTPUT fields. Globals: console.*, sleep(ms) (<=5000), atob, btoa, Buffer.from(str, 'base64'|'base64url'|'hex'|'utf-8').
Now write the code body that: <DESCRIBE WHAT YOU WANT>. My declared output fields are: <LIST THEM>
Stream code (channel binding)
Write FlowFn STREAM code (a channel binding handler). It runs server-side when a stream channel message fires. Sandboxed isolate; no require/network except ctx. Output ONLY JavaScript.
Declare: module.exports.<name> = async (args, ctx) => { ... } (the binding's function_name selects it).
args = { stream, room, channel, from, payload, ts }.
ctx capabilities:
- ctx.sheets(databaseId) — list / listRows / query / insertRow / updateRow / deleteRow(slug, ...) (pass an explicit databaseId; no getRow).
- ctx.http.fetch(url, opts) / .get / .head — SSRF-guarded public HTTP.
- ctx.workflows.run(id, input) -> {run_id}; ctx.agents.run(id, input) -> {job_id}. ONLY ids added in the stream's Tools tab (Tools -> Workflows / Agents) can be invoked — others throw.
- ctx.ai.call(message, { system?, max_tokens? }) -> { text, input_tokens, output_tokens, total_tokens } — calls the AI configured in the stream's Tools tab (team AI pool / BYOK); throws on a cost-gate or provider error.
- ctx.streams.publish(streamCode, room, channel, payload) — publish back (<=16KB; never re-fires bindings).
- ctx.env.KEY.
(No ctx.tools, no ctx.fetch, no ctx.auth.) Globals: console.*, sleep(ms), atob, btoa.
Now write a handler that: <DESCRIBE WHAT YOU WANT>