Designing reliable automation: When to use rules, scripts, and agents

Not every task needs an agent. How to choose between automation rules, Runner scripts, and AI agents in Plane, with worked examples for each.

Alibha
14 Sep, 2026
Rules. Scripts. Agents. Which automation to pick, and when.

Every new layer of tooling arrives sold as a replacement for the last one. The project tool was going to end the status spreadsheet. Templates were going to end copy-and-paste. Automation rules were going to end the manual chasing. All three shipped, and all three are still running next to the thing they replaced. Someone on your team has a spreadsheet open right now that the project tool was supposed to make unnecessary, and they are right to keep it.

What happens instead is duller than the pitch. The new layer takes the work the old one could not reach, the boundary between them settles, and teams run both for years without thinking about it again.

Agents are the current arrival, and the pattern is holding. Automation is not a binary choice between workflows and AI. Different tasks need different levels of determinism and autonomy, and what decides the layer is how much interpretation a task requires and how much responsibility you are willing to hand to something that might get it wrong.

You feel the boundary the first time a request arrives that the automation builder has no shape for. "Flag anything in this cycle that looks likely to slip." There is no condition that means likely.

The spectrum of automation in Plane

Requests like that one do not fail because the tool is missing a feature. They fail because they were sent to the wrong layer.

Plane gives you three layers of automation. They differ by one thing: how much of the decision the system makes on its own.

Custom automations → Runner scripts → Agents

All three run inside a boundary a person draws. You decide what each layer may do before it runs, and you pick up whatever it hands back. For a custom automation, that boundary is the condition you wrote. For a Runner script, it is the code. For an agent, it is the playbook, which you write in prose, and which leaves no boundary if you skip it.

This is not a maturity ladder. Nobody graduates from custom automations. A team running two hundred rules and no agents is not behind a team running five agents. Each step along the list gives the system more room to decide, and more room to get it wrong too.

What separates the layers is what you have to specify.

Approach
System is told
System decides

Custom automations

Exact condition and action

Almost nothing

Runner Scripts

Procedure and logic

How to execute the procedure

Agent

Instructions, triggers, tools

How to accomplish the goal

More autonomy does not mean better automation. It means more responsibility is being handed to the system.

These layers solve different classes of problems. A custom automation cannot interpret. An agent should not be trusted to flip the same boolean two hundred times a day and get it right every time. Neither of those is a defect.

1. Event-driven custom automation rules

Plane's trigger-based automations follow one shape: when a trigger fires, if conditions are met, perform actions. Five event triggers cover work item created, work item updated, state changed, assignee changed, and comment added. A scheduled trigger accepts daily, weekly, monthly or custom cron expressions with a timezone. Conditions filter on state, priority, assignees, labels, work item type, and created by, with AND logic across conditions and optional OR groups.

A worked example - Your support team files bugs through Intake, and urgent ones sit unacknowledged over weekends:

  • Trigger: Work item created
  • Conditions: Work item type is Bug, AND Priority is Urgent
  • Actions: Change property to set Assignees to the on-call engineer, and add a comment with a template variable naming the reporter and the SLA clock

That automation will do the same thing on its four thousandth run as it did on its first.

What you can use custom automations for:

  • Status transitions- A merged pull request moves the work item to In Review without anyone remembering to do it.
  • Notifications- The on-call engineer hears about an urgent bug, and the rest of the channel does not.
  • Field synchronization- A priority change on the parent pushes down to every child that inherited it.
  • Ownership changes- reassignment on escalation, or on a state that belongs to another team.
  • SLA reminders- a comment lands before the clock runs out, not in the report afterwards.

Those tasks share a property. The correct answer is known before the trigger fires. Nothing is being figured out.

Characteristics:

  • Stateless - The rule holds nothing between runs.
  • Predictable - The same input produces the same action every time.
  • Low maintenance - A rule that has run quietly for eighteen months is doing what it did on day one.
  • No interpretation - The rule cannot weigh two signals against each other, which is exactly why it never surprises you.

Change property and add comment work on all plans of Plane. Send webhook and run script are Enterprise Grid actions, and Business plans get project-level automations only, so workspace-level scope also means Enterprise Grid. Check that before you design around this layer.

A custom automation matches a condition on one work item and acts on that same item. The moment the decision depends on a second one, you are in Runner territory. "Close the parent when the last child finishes" is the wall most teams hit first, because the rule fires on the child while the answer lives with its siblings.

2. Runner scripts for deterministic workflows

Plane Runner is programmable automation: a sandboxed environment that runs JavaScript and TypeScript in response to workspace events, on a schedule, or during a workflow transition.

Every script is one exported function. Event scripts receive the full event payload. Scheduled scripts receive variables only, and the scheduler checks roughly every five minutes.

plaintext
export async function main(input: AutomationEventInput, variables: Record<string, string>) {
  const projectId = input.event.project_id;
  const workItemId = input.event.entity_id;
  return { success: true, message: "Done!" };
}

Inside that function you get an injected Plane SDK, a library of reusable functions, environment variables, and fetch. The SDK retrieves and updates work items, lists and creates states and labels, adds comments, creates relations, and runs filtered search. Built-in functions include getSiblings, getChildren, addComment, addLabel, postToSlack and httpRequest. Outbound fetch is restricted to an allowlist you configure per script.

Example use cases, all four of which ship as documented scripts:

  1. Close the parent when the last child is done

The script runs on work item updated. It retrieves the item, exits if there is no parent, lists states to map state IDs to their groups, confirms the item just landed in a completed group, calls Functions.getSiblings(), and updates the parent only when every sibling is also complete. Seven steps, one correct answer, no judgment anywhere in it.

  1. Create dependent work across projects - Take three variables, sourceProjectId, sourceProjectStateName set to something like "Ready for QA", and destinationProjectId. When an item in the source project reaches that state, the script copies the name, description, and priority into a new work item in the QA project and links the two with a relates_to relation. The QA lead stops chasing engineers for handoffs, and the trail between the two items survives in the relation.
  2. Sync Git metadata and external services into work items - Functions.httpRequest and fetch both work, with ENV.API_TOKEN for credentials, so a nightly script can pull build or deployment data from an external API and write it into structured fields.
  3. Nightly backlog hygiene and recurring operational work - A cron-triggered script uses advanced search to find items untouched for thirty days, labels them, comments, and reports the count. Nobody runs a Friday cleanup meeting for this.
  4. Enforce a precondition on a transition - Attach a script as a precondition on the To Do to In Progress transition. It retrieves the item, checks for a non-empty assignees array and an estimate_point, collects the missing fields, and throws an error naming all of them. The throw blocks the transition and shows the message to the person who tried it.
plaintext
// return { success: true }   allows the transition
// return { success: false }  blocks it
// throw new Error("reason")  blocks it and shows the reason to the user

Why scripts instead of custom automations?

Because the workflow is a procedure. Every step in it has one correct outcome. "Close the parent when every child is done" has exactly one correct answer at any moment. Reaching it takes a query, a loop, and a conditional. It takes no interpretation, which is why handing it to an agent would be a downgrade.

Runner is deliberately constrained, and the constraints tell you what it is for. Execution times out at 10 seconds, initialization at 5, memory caps at 128 MB. requireModule imports, Node APIs like fs and child_process, eval and prototype manipulation are all blocked. Runner is built for bounded procedures. A data pipeline belongs outside it.

One availability note, because it changes who this section is for. Plane Runner and scheduled automations are Enterprise Grid features. On Pro or Business, this layer is a purchase decision before it is a design decision. Check plans

Where deterministic automation breaks down

Take a request every release manager has made:

"Identify the five work items most likely to delay the release."

You can encode this deterministically, and teams do. Weight staleness, add points for unestimated scope, subtract for an active assignee. It works, right up to the point where the criteria move.

When automation rules fail:

  • Multiple signals - Stale updates, blocker relations, unestimated scope, a reassignment three days ago. None is decisive alone.
  • Conflicting priorities - A P1 with an active owner is safer than a P2 nobody has touched.
  • Historical context - This team's In Review has meant four days for the last six cycles.
  • Natural language updates - The most informative content sits in comments, not fields.
  • Dependency interpretation - A blocker relation pointing at an item that was itself descoped is not a blocker.

You could encode a scoring function for this, and teams do. Weight staleness, add points for unestimated scope, subtract for an active assignee. It works until the shape of the project changes, and then you have a script that confidently returns the wrong five items. That is worse than returning nothing, because someone will act on it.

3. Reasoning agents

Give agents a job, not just a prompt.

A prompt gets answered once. A job has an owner, a definition of done, boundaries, and a trigger that fires without anyone remembering to ask. That difference is what separates this layer from a chat window.

A reasoning agent takes structured project data and unstructured context, plans intermediate steps, and produces a decision, a recommendation, or a generated artifact.

That is the layer, not a product SKU. Plane does not ship one fixed agent. You start from a template or build your own, and either way you define four things: what it owns, the playbook it follows, when it starts, and what it can reach.

The five templates show what the layer is for, and each one names the tools it needs:

Agent
What it does
Connected tools

Standup

Collects progress, blockers, and next steps, and turns them into one update

Slack, Gmail, Projects

Delivery Risk

Watches for stalls, blockers, dependencies, and slipping timelines

GitHub, Slack, Projects

Spec

Turns rough requests into structured requirements and finds the gaps

Figma, Wiki

Request Triage

Reviews incoming work, spots duplicates, adds context, routes it

Slack, Projects, Intake

Customer Feedback

Groups feedback into themes and surfaces what keeps recurring

Slack, Projects, Wiki

Build your own

Whatever handoff your team currently does by hand

Any MCP server you connect

Custom agents cover the handoffs the templates do not. One example, triggered on assignment:

A root cause agent handles incident enrichment. Sentry's integration files a work item when an alert fires, carrying the error context with it. The agent is assigned to that item, reads the Sentry error, queries Datadog over MCP for logs around the same window, and comments its findings back on the work item. Its only action is the comment, so an engineer opens the item with the investigation already done.

Plane's Sentry integration creates the work item when an alert fires. The agent picks it up on assignment, pulls the matching window from Datadog over MCP, and writes what it found back as a comment. Four lines of playbook, one external tool, one permitted action, no state changes.

You can build multiple agents as per the use cases -

Use case
What the agent does

Release risk

Weighs stale updates, blockers, and slipping dates against each other and flags what is likely to slip

Root cause

Reads an alert, pulls matching logs from a connected tool, and comments the findings

Cycle summary

Reads the cycle's activity and writes what actually happened

Dependency check

Walks the relation graph and separates real blockers from stale ones

Duplicate detection

Spots that two differently worded reports describe one defect

Status reporting

Turns a project's activity into an update written for a specific audience

Each of these ends in something a person reads and acts on.

Work with a known answer belongs one layer down.

Task
Layer that owns it

Updating a field

Custom automations

Closing completed work

Runner script

Assigning labels from explicit rules

Custom automations

An agent can update a field. A custom automation already does it correctly every time, with a log you can read.

What the agent layer asks of you

The next request is always "do that every Monday, and fix what you find." An agent will take it. The second half of that sentence is the part that needs writing carefully.

Probabilistic systems can answer the same question two defensible ways, so you sample quality instead of running a test that passes. A goal without a boundary invites action nobody asked for.

Permissions compound too. An agent that can read your knowledge base, create work items, and post to Slack has more reach than any one of those permissions suggests, and that is how something confidential ends up in a channel it should not be in.

So the playbook and the access scope are the two fields worth real time. The good version of "fix what you find" reads "summarize what you find, comment it on the cycle, change nothing else."

A decision matrix for choosing the right layer

Design automation around the decision, not the technology.

Work down these in order. Stop at the first one you answer yes to.

  1. Is the action fully determined by the trigger plus a few field conditions? Custom automations
  2. Does deciding require reading something the trigger did not hand you? Runner
  3. Does it need loops, external APIs, or data transformation? Runner
  4. Is the correct output unknowable before the task runs? Agent
  5. Does being wrong cost more than being slow? Human, with an agent preparing the input.
If your task requires...
Use
Looks like

One trigger, one action

Custom automations

Urgent bug filed, assign the on-call engineer, comment the SLA clock

Conditional logic

Runner

Close the parent when the last child reaches a completed state

Loops, APIs, data transformation

Runner

Nightly sync of build metadata from an external API into work items

Contextual interpretation

Agent

Root cause enrichment from an alert plus logs in another system

Organizational judgment

Human + Agent

Ship or slip the release

Signs you picked the wrong layer

Automation drifts. The symptoms are easy to spot once you know what they look like.

Symptom
What it means
Move to

The rule has four OR groups and still misses cases

The decision needs data the trigger does not carry

Runner

The script hand-tunes weights to rank things

You are encoding judgment as arithmetic

Agent

Someone edits the agent's output every time before using it

The task had a knowable answer

Runner or Custom automation

The agent needs another tool connection every few weeks

Its scope is drifting past what it owns

Split it into two agents

The automation runs, and nobody opens the result

The task did not need automating

Delete it

Composing automation pipelines

The interesting systems are not built on one layer. They hand off.

Example pipeline:

  1. A pull request merges. The GitHub integration moves the linked work item to Merged.
  2. An automation rule triggers on that state change.
  3. A Runner script validates the linked work items, creates the QA item in the QA project, and updates dependent items across projects.
  4. The Delivery Risk Agent reviews release health across the cycle and drafts a summary.
  5. A human approves the release.

Steps two and three stay deterministic. Step four is interpretation and could not be a script. Step five carries organizational consequence and should not be delegated.

The skill worth developing is knowing when to switch from deterministic execution to probabilistic reasoning, and when to switch back. Most badly designed automation gets the second switch wrong. It lets the agent that wrote the summary also close the items.

Guardrails for reliable automation

Automation is only reliable when you control what it can do, what happens when it fails, and how its actions can be reviewed or undone. Rules need this as much as agents do, because a rule with the wrong condition executes its mistake four thousand times.

Permissions and scope

  • Give automation only the permissions it needs
  • Restrict agents and runners to the projects, work items, and actions they actually require
  • Apply the same access controls to automated actions as to human actions

Plane's agent configuration supports this. You pick the projects, trusted web sources, and connected tools each agent can reach, and you decide whether it acts through a person's account or a team-managed service account. The Spec Agent gets Figma and Wiki. It has no reason to hold the Slack token the Standup Agent uses.

Runner has one real scoping control, and it is worth using well. Each script carries its own allowed-domains list, so the Slack notification script gets hooks.slack.com and nothing else. A script that reaches a payments API cannot quietly start posting to a webhook you did not authorize.

The gap is on the Plane side of the boundary. Activating and managing scripts requires Workspace Admin, and the documented access scope is "read and write access to all workspace resources and your user profile." A script that only needs to read one project gets the whole workspace. Until that is scoped per script, least privilege here is something you enforce by code review and convention, not something the platform enforces for you.

Retries and failure handling

  • Retry transient failures automatically
  • Set limits so failed workflows do not loop indefinitely
  • Make failures visible instead of silently dropping work
  • Define what happens when a downstream service is unavailable

What Plane documents today is narrower than that list. For workflow transition scripts: "If they fail, the transition still stands, and the error is logged." No retry policy is described.

In practice, that means retry logic and the partial-failure decision live inside your script. A nightly sync that touches 300 work items and dies at item 180 on a 502 needs to know where it stopped, and the 10-second execution ceiling means it cannot simply start over from item 1. Write it to record progress, skip what it already did, and be safe to run twice. Functions.httpRequest Throws on any non-2xx response, so a try/catch around the external call is the difference between a script that logs "third-party API returned 503, 120 items remaining" and one that just says errored.

Auditability

  • Record what triggered the automation
  • Capture actions taken and their outcomes
  • Make agent-generated decisions or artifacts distinguishable from deterministic changes
  • Preserve enough history to understand why a change happened

Runner execution records capture trigger type, timing, errors, and return values, which is why the return { success: true, message: "..." } at the end of a script is worth filling in properly. message: "Closed parent PROJ-441, 6 of 6 children complete" reads usefully in the log six months from now. message: "Done" does not. Test runs are tagged trigger_type: "test" and reviewed separately from production runs. Agent activity is visible as it starts, returns and asks for input. At the workspace level, API-enabled audit logs are an Enterprise Grid feature.

The third bullet is the one teams skip. "Who changed this" and "was this a judgment call" are different questions, and a timestamp only answers the first.

Approval gates

Not every automated action should execute immediately.

Use approval gates when automation can:

  • Change critical project state
  • Affect multiple teams or projects
  • Trigger external actions
  • Make consequential recommendations
  • Move work across a defined control boundary

Plane's workflows support approvals with designated approvers per transition. A single workflow comes with Business, and multiple workflows with approvals are Enterprise Grid.

Approvals and pre-condition scripts are complementary controls. A pre-condition script checks whether defined conditions are met, so nobody moves a work item into In Progress without an assignee and an estimate, and it names the field that is missing. An approval gate captures a person's sign-off, which is a judgment no condition can express. Use the script to keep incomplete work out of a state, and the gate where someone has to own the call.

Choose the least autonomy that solves the problem

Every automation you build will eventually raise the same question. Someone will ask why it did what it did.

An automation rule answers in one line: this trigger, this condition, this action. A Runner script answers with an execution log and the source that produced it. An agent answers with an account of its reasoning that may not be the reasoning. A person answers by explaining the call they made and why.

All four are acceptable answers. They are not equally cheap, and the difference only shows up on the day something goes wrong.

That is the case for picking the least autonomous layer that can do the job. It is also the one that can explain itself in the fewest steps. Rules where the answer is known, Runner where the procedure is known, agents where the path needs interpretation, humans where the decision carries consequence.

Before you build, decide which of those four answers you want to be giving. It usually settles the layer faster than the requirements do.

Pick the automation your team complains about most this week, and check whether it needs more than a trigger and an action. Most of them don't.

Trigger-based automations ship on every Plane plan. Start free or read the automation docs.

Already past automations? Plane Runner and Agents are on Enterprise Grid. Talk to us about your workflow.

Recommended for you

View all blogs
Plane

Every team, every use case, the right momentum

Hundreds of Jira, Linear, Asana, and ClickUp customers have rediscovered the joy of work. We’d love to help you do that, too.
Plane
Nacelle