Listeners

Listeners are event-driven scripts that execute automatically when something happens in Jira. When an issue is created, a comment is added, a sprint starts, or any of 37+ events occur — your listener script runs in response.

How Listeners Work

[User Action in Jira] → [Jira Event Fired] → [ScriptForge Matches Listeners] 
    → [Condition Evaluated] → [Script Executes]
  1. A user (or system) performs an action in Jira that triggers an event
  2. ScriptForge's event trigger handler receives the event
  3. It finds all enabled listeners subscribed to that event
  4. For each matching listener, it evaluates the condition expression (if configured)
  5. If the condition passes (or there is no condition), the script executes
  6. Output and results are logged to execution history

Available Events (37+)

Issue Events

  • avi:jira:created:issue — Issue created
  • avi:jira:updated:issue — Issue updated (any field change)
  • avi:jira:deleted:issue — Issue deleted

Comment Events

  • avi:jira:created:comment — Comment added
  • avi:jira:updated:comment — Comment edited
  • avi:jira:deleted:comment — Comment deleted

Attachment Events

  • avi:jira:created:attachment — File attached
  • avi:jira:deleted:attachment — Attachment removed

Sprint Events

  • avi:jira:created:sprint — Sprint created
  • avi:jira:updated:sprint — Sprint updated (started, completed, etc.)
  • avi:jira:deleted:sprint — Sprint deleted
  • avi:jira:created:issuelink — Link added between issues
  • avi:jira:deleted:issuelink — Link removed

Version Events

  • avi:jira:created:version — Version created
  • avi:jira:updated:version — Version updated (released, etc.)
  • avi:jira:deleted:version — Version deleted

Worklog Events

  • avi:jira:created:worklog — Work logged
  • avi:jira:updated:worklog — Worklog edited
  • avi:jira:deleted:worklog — Worklog removed

Project Events

  • avi:jira:created:project — Project created
  • avi:jira:updated:project — Project updated
  • avi:jira:deleted:project — Project deleted (soft-delete)

User Events

  • avi:jira:created:user — User added to site
  • avi:jira:updated:user — User profile updated

Filter Events

  • avi:jira:created:filter — Saved filter created
  • avi:jira:updated:filter — Saved filter updated
  • avi:jira:deleted:filter — Saved filter deleted

Issue Type Events

  • avi:jira:created:issuetype — Issue type created
  • avi:jira:updated:issuetype — Issue type updated
  • avi:jira:deleted:issuetype — Issue type deleted

Listener Configuration

Each listener has:

Field Description
Name A descriptive name for the listener
Description Optional — what the listener does
Events One or more events that trigger this listener
Projects Which projects to listen in (empty = all projects)
Condition Expression Optional JavaScript expression that must return true for the script to run
Script The JavaScript code to execute
Run As app (service account — full access) or user (triggering user's permissions)
Enabled Toggle on/off without deleting

Script Context

When a listener fires, your script receives the event data through the context:

// The event payload is available - contains the issue/entity that triggered the event
const issue = await WorkItems.getByKey(event.issue.key);
console.log(`Issue ${issue.key} triggered event`);

// For issue events, you get the issue data directly
// For comment events, you get the comment and parent issue
// For sprint events, you get the sprint details

Condition Expressions

Conditions are JavaScript expressions that gate whether the script runs. They have access to the same event data:

// Only run if issue is a Bug
event.issue.fields.issuetype.name === 'Bug'

// Only run if priority is High or Critical
['High', 'Critical'].includes(event.issue.fields.priority.name)

// Only run if issue is in a specific status
event.issue.fields.status.name === 'To Do'

If a condition returns false or throws an error, the script does not execute.

Loop Detection

ScriptForge includes a loop detector to prevent infinite recursion. If a listener updates an issue, which fires another event, which triggers the same (or another) listener — the system detects the loop and stops execution after a configured depth to prevent runaway automation chains.

Real-World Examples

Auto-assign issues to a team lead when priority is Critical:

const issue = await WorkItems.getByKey(event.issue.key);
if (issue.priority === 'Critical') {
  await issue.update(b => {
    b.setAssignee('5a_team_lead_account_id');
  });
  await issue.addComment('Auto-assigned to team lead due to Critical priority.');
}

Add a comment when an issue is linked:

const issue = await WorkItems.getByKey(event.issueLink.sourceIssueId);
await issue.addComment(
  `Linked to ${event.issueLink.destinationIssueId} via "${event.issueLink.type.name}"`
);

Auto-create a sub-task checklist when a Story is created:

const issue = await WorkItems.getByKey(event.issue.key);
const tasks = ['Write tests', 'Code review', 'Update documentation'];

for (const task of tasks) {
  await issue.createSubTask('Sub-task', b => {
    b.setSummary(task);
  });
}