Skip to content

Step Types

Complete reference for all 46 step types available in SideButton (43 implemented, 3 chat types pending).

Browser Steps

browser.navigate

Navigate to a URL.

yaml
- type: browser.navigate
  url: "https://example.com"
  new_tab: false  # Optional: open in new tab
ParameterTypeRequiredDescription
urlstringYesURL to navigate to
new_tabbooleanNoOpen in new tab (default: false)

browser.click

Click an element.

yaml
- type: browser.click
  selector: "button.submit"
  new_tab: false  # Optional: Ctrl+click to open in new tab
ParameterTypeRequiredDescription
selectorstringYesCSS selector or text selector
new_tabbooleanNoCtrl+click for new tab

Selector formats:

  • CSS: button.submit, #login-btn
  • Text: button:has-text('Submit')
  • Aria: [aria-label="Close"]

browser.type

Type text into an input.

yaml
- type: browser.type
  selector: "input[name='email']"
  text: "[email protected]"
ParameterTypeRequiredDescription
selectorstringYesCSS selector for input
textstringYesText to type

browser.scroll

Scroll the page.

yaml
- type: browser.scroll
  direction: down
  amount: 500  # pixels
ParameterTypeRequiredDescription
directionstringYesup, down, left, right
amountnumberNoPixels to scroll (default: 300)

Scroll in containers

Use browser.hover first to position the cursor inside a scrollable container.

browser.hover

Hover over an element.

yaml
- type: browser.hover
  selector: ".dropdown-menu"
ParameterTypeRequiredDescription
selectorstringYesCSS selector

browser.wait

Wait for element or delay.

yaml
# Wait for element
- type: browser.wait
  selector: ".loading-complete"
  timeout: 10000

# Fixed delay
- type: browser.wait
  ms: 2000

# Named delay constant (resolves to base value +/-10% jitter)
- type: browser.wait
  ms: "mid"
ParameterTypeRequiredDescription
selectorstringNoWait for element to appear
msnumber | DelayConstantNoFixed delay in milliseconds or named constant
timeoutnumberNoMax wait time (default: 30000)

browser.extract

Extract text from an element.

yaml
- type: browser.extract
  selector: "h1"
  as: page_title
ParameterTypeRequiredDescription
selectorstringYesCSS selector
asstringYesVariable name to store result

browser.extractAll

Extract text from multiple elements.

yaml
- type: browser.extractAll
  selector: ".list-item"
  as: items
  separator: ", "  # Optional
ParameterTypeRequiredDescription
selectorstringYesCSS selector
asstringYesVariable name
separatorstringNoJoin separator (default: ", ")

browser.extractMap

Extract structured data from repeated elements, mapping child selectors to named fields.

yaml
- type: browser.extractMap
  selector: ".user-row"
  fields:
    name:
      selector: ".user-name"
    email:
      selector: ".user-email"
    role:
      selector: ".user-role"
      attribute: "data-role"
  as: user_data
ParameterTypeRequiredDescription
selectorstringYesCSS selector for container elements
fieldsobjectYesMap of field names to { selector, attribute? }
asstringYesVariable name to store result
separatorstringNoRow separator (default: newline)

browser.exists

Check if element exists.

yaml
- type: browser.exists
  selector: ".error-message"
  as: has_error
  timeout: 1000
ParameterTypeRequiredDescription
selectorstringYesCSS selector
asstringYesVariable name (boolean)
timeoutnumberNoWait timeout (default: 1000)

browser.key

Send keyboard key.

yaml
- type: browser.key
  key: Enter
  selector: "input.search"  # Optional: focus first
ParameterTypeRequiredDescription
keystringYesKey name
selectorstringNoElement to focus first

Supported keys: Escape, Enter, Tab, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Backspace, Delete, Space

browser.snapshot

Capture an accessibility snapshot of the page. Returns a structured YAML representation of the page's accessibility tree, useful for LLM-driven analysis.

yaml
- type: browser.snapshot
  as: page_snapshot
  includeContent: true
ParameterTypeRequiredDescription
asstringYesVariable name to store snapshot
includeContentbooleanNoInclude visible text content (default: false)

browser.screenshot

Capture the page — or a crop of it — and write a PNG to a file on the machine running SideButton. The image bytes never enter the agent's context; the step returns only the path it wrote.

yaml
- type: browser.screenshot
  selector: "#app"
  path: "~/shots/01-dashboard.png"
  as: shot_path
ParameterTypeRequiredDescription
pathstringYesWhere to write the PNG. ~/…, absolute, or relative to ~/workspace
selectorstringNoCSS selector to crop to. Empty or omitted = full viewport
refnumberNoElement reference from a prior browser.snapshot
regionobjectNoManual crop: {x, y, width, height} in CSS pixels
asstringNoVariable name to store the written path

Parent directories are created as needed, the file is written 0600, and an existing file at the same path is overwritten — so a retried step lands on the same file rather than leaving a numbered trail.

Paths are contained to the home directory

path must resolve inside the home directory of the user running SideButton; .. traversal and symlinks that escape it are rejected. This matches the rule publish_artifact enforces, so anything this step writes can be published directly.

Redact before you capture

Pair it with browser.injectCSS to blur sensitive elements before the shot, so no unredacted image is ever written:

yaml
- type: browser.navigate
  url: "{{url}}"
- type: browser.injectCSS
  id: sb-redact
  css: ".user-email, .invoice-total { filter: blur(6px); }"
- type: browser.wait
  ms: 400
- type: browser.screenshot
  selector: "#app"
  path: "~/shots/01-dashboard.png"

This is exactly the bundled docs_screenshot workflow.

browser.injectCSS

Inject CSS styles into the page.

yaml
- type: browser.injectCSS
  css: |
    .highlight { background: yellow; }
  id: "my-styles"
ParameterTypeRequiredDescription
cssstringYesCSS rules to inject
idstringNoStyle element ID for replacement/idempotency

Idempotent injection

When id is provided and a style element with that ID already exists, its content is replaced instead of creating a duplicate.

browser.injectJS

Inject JavaScript into the page.

yaml
- type: browser.injectJS
  js: |
    document.querySelector('.dropdown').click();
  id: "my-script"
ParameterTypeRequiredDescription
jsstringYesJavaScript code to inject
idstringNoScript element ID for replacement/idempotency

Idempotent injection

When id is provided and a script element with that ID already exists, its content is replaced instead of creating a duplicate.

browser.select_option

Select an option from a <select> dropdown. Matches by value or visible label text.

yaml
- type: browser.select_option
  selector: "select#country"
  label: "United States"
ParameterTypeRequiredDescription
selectorstringYesCSS selector for <select> element
valuestringNoOption value to select
labelstringNoOption visible text to select

browser.scrollIntoView

Scroll an element into the visible viewport.

yaml
- type: browser.scrollIntoView
  selector: "#footer-section"
  block: center
ParameterTypeRequiredDescription
selectorstringYesCSS selector
blockstringNoScroll alignment: start, center (default), end, nearest

browser.fill

Set an input value directly. Works with React controlled inputs by using native value setters and dispatching synthetic events.

yaml
- type: browser.fill
  selector: "input[name='date']"
  value: "2026-03-01"
ParameterTypeRequiredDescription
selectorstringYesCSS selector for input
valuestringYesValue to set

When to use fill vs type

Use browser.fill instead of browser.type for date inputs, React-controlled inputs, or when you need to set a value without triggering the native input UI (e.g., date pickers).

Shell Steps

shell.run

Execute a shell command.

yaml
- type: shell.run
  cmd: "echo 'Hello World'"
  cwd: "/path/to/dir"  # Optional
  as: output          # Optional
ParameterTypeRequiredDescription
cmdstringYesCommand to run
cwdstringNoWorking directory
asstringNoVariable for stdout

terminal.open

Open a visible terminal window (macOS).

yaml
- type: terminal.open
  title: "My Terminal"
  cwd: "/path/to/project"
ParameterTypeRequiredDescription
titlestringNoTerminal window title
cwdstringNoStarting directory

terminal.run

Run command in open terminal.

yaml
- type: terminal.run
  cmd: "npm run dev"
ParameterTypeRequiredDescription
cmdstringYesCommand to run

LLM Steps

Requires API Key

Set OPENAI_API_KEY environment variable or configure in Settings.

llm.classify

Classify text into categories.

yaml
- type: llm.classify
  input: "{{message}}"
  categories:
    - urgent
    - normal
    - spam
  as: category
ParameterTypeRequiredDescription
inputstringYesText to classify
categoriesarrayYesList of categories
asstringYesVariable for result

llm.generate

Generate text with AI.

yaml
- type: llm.generate
  prompt: "Summarize this article:\n{{content}}"
  as: summary
ParameterTypeRequiredDescription
promptstringYesPrompt for the LLM
asstringYesVariable for result

llm.decide

Present a situation and a list of possible actions to the LLM, and let it pick the best one based on its role context.

yaml
- type: llm.decide
  input: "{{situation}}"
  actions:
    - id: escalate
      description: "Escalate to a human"
    - id: respond
      description: "Send an automated response"
    - id: ignore
      description: "No action needed"
  as: chosen_action
ParameterTypeRequiredDescription
inputstringYesSituation description
actionsarrayYesList of { id, description } actions
asstringYesVariable for chosen action ID

Control Flow Steps

control.if

Conditional branching.

yaml
- type: control.if
  condition: "{{status}} == 'ready'"
  then:
    - type: browser.click
      selector: ".start-btn"
  else_steps:
    - type: control.stop
      message: "Not ready"
ParameterTypeRequiredDescription
conditionstringYesCondition to evaluate
thenarrayYesSteps if true
else_stepsarrayNoSteps if false

Operators: ==, !=

control.retry

Retry steps on failure.

yaml
- type: control.retry
  max_attempts: 3
  delay_ms: 1000
  steps:
    - type: browser.click
      selector: ".flaky-button"
ParameterTypeRequiredDescription
stepsarrayYesSteps to retry
max_attemptsnumberNoMax retries (default: 3)
delay_msnumber | DelayConstantNoDelay between retries (default: 1000)

control.foreach

Iterate over a list of items.

yaml
- type: control.foreach
  items: "{{user_list}}"
  as: user
  separator: ","
  delay_ms: "small"
  steps:
    - type: browser.click
      selector: "button[data-user='{{user}}']"
ParameterTypeRequiredDescription
itemsstringYesInterpolated string to split into items
asstringYesVariable name for current item
stepsarrayYesSteps to execute per item
separatorstringNoItem separator (default: ,)
index_asstringNoVariable name for current index
max_itemsnumberNoMax items to process (default: 1000)
delay_msnumber | DelayConstantNoDelay between iterations (default: 0)

control.stop

Stop workflow execution.

yaml
- type: control.stop
  message: "Completed successfully"
ParameterTypeRequiredDescription
messagestringNoMessage to log

Workflow Steps

workflow.call

Call another workflow.

yaml
- type: workflow.call
  workflow: extract_data
  params:
    url: "{{target_url}}"
  as: data  # Namespace for child variables
ParameterTypeRequiredDescription
workflowstringYesWorkflow ID to call
paramsobjectNoParameters to pass
asstringNoNamespace for variables
timeoutnumberNoMax execution time in ms

Data Steps

data.first

Get first item from a list.

yaml
- type: data.first
  input: "{{items}}"
  as: first_item
  separator: ", "
ParameterTypeRequiredDescription
inputstringYesComma-separated list
asstringYesVariable for first item
separatorstringNoList separator (default: ", ")

data.get

Get an item from a list by index.

yaml
- type: data.get
  input: "{{items}}"
  index: "2"
  as: third_item
  separator: ", "
ParameterTypeRequiredDescription
inputstringYesDelimited list
indexstringYesZero-based index (supports interpolation)
asstringYesVariable for result
separatorstringNoList separator (default: ", ")

variable.set

Set a variable value directly.

yaml
- type: variable.set
  name: base_url
  value: "https://example.com"
ParameterTypeRequiredDescription
namestringYesVariable name to set
valuestringYesValue to assign (supports interpolation)

Issues Steps

Abstract issue tracker steps. Provider is auto-detected from environment variables (Jira, GitHub Issues, etc.).

Requires Provider

Configure an issues provider (e.g., set JIRA_HOST, JIRA_EMAIL, JIRA_API_TOKEN for Jira).

issues.create

Create a new issue.

yaml
- type: issues.create
  project: "PROJ"
  summary: "Bug: login fails on mobile"
  description: "Steps to reproduce..."
  issue_type: "Bug"
  labels:
    - mobile
    - critical
  as: issue_key
ParameterTypeRequiredDescription
projectstringYesProject key
summarystringYesIssue title
descriptionstringNoIssue body
issue_typestringNoIssue type (e.g., Bug, Story)
labelsarrayNoLabels to apply
providerstringNoForce specific provider
sitestringNoProvider site/host
asstringNoVariable for issue key

issues.get

Get issue details.

yaml
- type: issues.get
  issue_key: "PROJ-123"
  fields: "summary,status,assignee"
  as: issue
ParameterTypeRequiredDescription
issue_keystringYesIssue identifier
fieldsstringNoComma-separated fields to return
providerstringNoForce specific provider
sitestringNoProvider site/host
asstringNoVariable for result

Search for issues.

yaml
- type: issues.search
  query: "project = PROJ AND status = 'To Do'"
  max_results: 10
  as: results
ParameterTypeRequiredDescription
querystringYesSearch query (JQL for Jira)
max_resultsnumberNoMax results to return
fieldsstringNoComma-separated fields to return
providerstringNoForce specific provider
sitestringNoProvider site/host
asstringNoVariable for results

issues.attach

Attach files to an issue.

yaml
- type: issues.attach
  issue_key: "PROJ-123"
  files:
    - filename: "screenshot.png"
      data: "{{screenshot_base64}}"
      content_type: "image/png"
  as: result
ParameterTypeRequiredDescription
issue_keystringYesIssue identifier
filesarrayYesFiles to attach: { filename, data, content_type? }
providerstringNoForce specific provider
sitestringNoProvider site/host
asstringNoVariable for result

issues.transition

Transition an issue to a new status.

yaml
- type: issues.transition
  issue_key: "PROJ-123"
  status: "In Progress"
  as: result
ParameterTypeRequiredDescription
issue_keystringYesIssue identifier
statusstringYesTarget status name
providerstringNoForce specific provider
sitestringNoProvider site/host
asstringNoVariable for result

issues.comment

Add a comment to an issue.

yaml
- type: issues.comment
  issue_key: "PROJ-123"
  body: "Automated test passed. Ready for review."
  as: comment_id
ParameterTypeRequiredDescription
issue_keystringYesIssue identifier
bodystringYesComment text
providerstringNoForce specific provider
sitestringNoProvider site/host
asstringNoVariable for comment ID

Git Steps

Abstract git platform steps. Provider is auto-detected from environment (GitHub, etc.).

Requires Provider

Configure a git provider (e.g., set GITHUB_TOKEN for GitHub).

git.listPRs

List pull requests.

yaml
- type: git.listPRs
  repo: "org/repo"
  state: "open"
  limit: 10
  as: pull_requests
ParameterTypeRequiredDescription
repostringNoRepository (default: detected from env)
statestringNoFilter by state: open, closed, all
limitnumberNoMax results
providerstringNoForce specific provider
asstringNoVariable for results

git.getPR

Get pull request details.

yaml
- type: git.getPR
  repo: "org/repo"
  number: 42
  as: pr
ParameterTypeRequiredDescription
repostringNoRepository
numbernumberYesPR number
providerstringNoForce specific provider
asstringNoVariable for result

git.createPR

Create a pull request.

yaml
- type: git.createPR
  repo: "org/repo"
  title: "feat: add login flow"
  body: "Implements the new login flow"
  head: "feat/login"
  base: "main"
  as: pr_url
ParameterTypeRequiredDescription
repostringNoRepository
titlestringYesPR title
bodystringNoPR description
headstringYesSource branch
basestringNoTarget branch (default: main)
providerstringNoForce specific provider
asstringNoVariable for PR URL

git.listIssues

List repository issues.

yaml
- type: git.listIssues
  repo: "org/repo"
  state: "open"
  labels: "bug,critical"
  limit: 20
  as: issues
ParameterTypeRequiredDescription
repostringNoRepository
statestringNoFilter by state: open, closed, all
labelsstringNoComma-separated label filter
limitnumberNoMax results
providerstringNoForce specific provider
asstringNoVariable for results

git.getIssue

Get issue details.

yaml
- type: git.getIssue
  repo: "org/repo"
  number: 15
  as: issue
ParameterTypeRequiredDescription
repostringNoRepository
numbernumberYesIssue number
providerstringNoForce specific provider
asstringNoVariable for result

Chat Steps

Not Yet Implemented

Chat steps are registered but not yet functional. They will be available when a chat provider (e.g., Slack) is integrated.

chat.listChannels

List available channels.

yaml
- type: chat.listChannels
  limit: 50
  as: channels
ParameterTypeRequiredDescription
typesstringNoChannel type filter
limitnumberNoMax results
providerstringNoForce specific provider
asstringNoVariable for results

chat.readChannel

Read messages from a channel.

yaml
- type: chat.readChannel
  channel: "#general"
  limit: 20
  as: messages
ParameterTypeRequiredDescription
channelstringYesChannel name or ID
limitnumberNoMax messages
max_daysnumberNoLimit to recent days
providerstringNoForce specific provider
asstringNoVariable for messages

chat.readThread

Read a message thread.

yaml
- type: chat.readThread
  channel: "#general"
  thread_ts: "1234567890.123456"
  as: thread
ParameterTypeRequiredDescription
channelstringYesChannel name or ID
thread_tsstringYesThread timestamp ID
max_daysnumberNoLimit to recent days
providerstringNoForce specific provider
asstringNoVariable for messages

Delay Constants

Any delay_ms or ms parameter that accepts a number also accepts a named delay constant. Named constants resolve to a base millisecond value with +/-10% random jitter on each invocation, making automation timing less predictable and more human-like.

ConstantBaseRange
"small"500ms450-550ms
"mid"1000ms900-1100ms
"large"5000ms4500-5500ms

Raw numeric values are used as-is without jitter.

Applies to: browser.waitms, control.retrydelay_ms, control.foreachdelay_ms

Released under the Apache-2.0 License.