Stacker

Search Documentation

Search for pages and topics in the documentation

6 min read

Automations

Automations run your own JavaScript or Python in a secure sandbox whenever something happens in your app — a record changes, a button is clicked, or an agent calls them. Each automation has full access to your app's data through the built-in stacker SDK. You can build them in the Automations UI, or create and refine them in a thread — the same conversational workflow you use to build portals and agents.

Create automations in a thread

You don't need to write code by hand to get started. Open a thread, describe what should happen in plain language, and the AI writes the automation, picks a trigger, and can test runs or read execution logs when something fails. Use the portal builder thread or an agent thread with Modify workflows enabled — see Building with threads in Core Concepts for where each conversation lives.

Plain language is enough — no special syntax. Good prompts name the outcome, the trigger, and any constraints:

Example prompts

Record change

"When a new row is added to Orders, email the customer with the order total and line items."

Button trigger

"Add a callable automation that recalculates tax on an invoice — I'll call it from a portal button."

Fix and iterate

"The welcome-email automation failed on the last three runs — read the logs and fix the template."

Chain with agents

"When a support ticket is marked urgent, run an automation that pings our on-call agent in a dedicated thread."

Automations created in a thread show up in the Automations sidebar like any other — you can open them there to edit code, change triggers, or review runs by hand.

Finding Automations

Open your app and look in the left sidebar for the Automationsitem (above your agents). There you can create automations manually, edit their code, run them for testing, and review every execution's logs. The neighbouring Data item lets you browse the records your automations read and write.

Triggers

Choose how each automation runs:

  • Record change — runs when records in a chosen table are created or updated. Use it to validate input, derive fields, or fan out notifications.
  • Button — runs when a user clicks a button in your portal. Call stacker.triggerWorkflow(slug, params) from a portal page.
  • Agent — a worker agent runs the automation as a tool (the agent needs the Run automations permission).
  • Callable — a function-style automation with no automatic trigger. Agents, app pages, skills, and other automations all call it with stacker.runWorkflow(slug, input) and it reads the passed inputs with stacker.getInput(). You can declare its inputs(name, type, required) in the automation's detail view — calls that omit a required input or pass the wrong type are then rejected. Great for shared logic you want to reuse.
  • Manual — runs only when you test it from the Automations UI. Pass a JSON Test inputto simulate the inputs a caller would send. Great while you're building.

The Stacker SDK

Your code runs with a pre-injected stacker object scoped to this app only. The most-used helpers:

  • stacker.getTrigger() — the event that started this run (the changed record, button params, or agent input).
  • stacker.records — read, create, and update records in your app's tables.
  • stacker.log(...) — write a line to the execution log, visible in the Automations UI.
  • stacker.getInput() — the input object passed to this run (button params, agent params, or the input from another automation that called it). Same as stacker.getTrigger().input.
  • stacker.runWorkflow(slug, input) — call another automation in this app like a function, passing an input object. The call is queued and runs independently; loop protection applies (see below).
  • stacker.sendAgentMessage({ agentId, message, threadKey, newThread }) — send a message to one of your worker agents. By default, every run of the automation posts into the same shared thread, so the conversation keeps growing. Pass a stable threadKey to keep a specific conversation (e.g. one thread per order), or set newThread: true to start a fresh thread for that call.
  • stacker.sendEmail({ to, subject, html, text }) — send a transactional email from your app's noreply address (e.g. "Your App <[email protected]>"). to accepts a single address or an array; provide html or text. Optional replyTo, cc, and bcc.
  • stacker.shareFile({ fileName, text, contentBase64, sourceUrl, contentType }) — save content as a downloadable file and get a signed share link (valid for 7 days). Same capability as the agent share_file tool and skill code's stacker.share_file. Works in any automation run — including record-change and button triggers that have no agent thread. Provide exactly one of text (CSV, markdown, JSON, plain text), contentBase64 (binary bytes), or sourceUrl (re-host a public file). Returns a url you can pass to sendEmail as an attachment or include in an agent message.
JavaScript example
// Runs on new orders, greets the customer via an agent
const { record } = await stacker.getTrigger();

stacker.log("New order received", { orderId: record.id });

// Reuse one thread per order (same threadKey = same conversation):
await stacker.sendAgentMessage({
  agentId: "support-agent",
  message: `A new order ${record.id} was placed for ${record.total}.`,
  threadKey: `order-${record.id}`,
});

// ...or start a brand-new thread every run instead:
// await stacker.sendAgentMessage({
//   agentId: "support-agent",
//   message: "Daily summary ready.",
//   newThread: true,
// });

Languages & packages

Automations can be written in JavaScript or Python. You can declare a list of npm or pip packages for an automation; Stacker installs them ahead of time so runs start quickly. If a package can't be pre-installed, the automation still falls back to installing it at run time.

Logs, errors & loop protection

Every run is recorded with its status, duration, return value, and the lines you wrote with stacker.log(). Open any execution in the Automations UI to diagnose failures.

Stacker automatically prevents runaway loops: whether an automation re-triggers itself through record writes or calls another automation directly with stacker.runWorkflow(), the platform tracks the cause-chain and stops it when it gets too deep or the same automation appears too many times in one chain. Automations also respect your workspace's usage limits — runs are metered, and an automation is blocked before it starts if the workspace is out of credit.

Automations run server-side in an isolated sandbox and can only touch the data in their own app. They never receive credentials or data from other apps or workspaces.