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]
- A user (or system) performs an action in Jira that triggers an event
- ScriptForge's event trigger handler receives the event
- It finds all enabled listeners subscribed to that event
- For each matching listener, it evaluates the condition expression (if configured)
- If the condition passes (or there is no condition), the script executes
- Output and results are logged to execution history
Available Events (37+)
Issue Events
avi:jira:created:issue— Issue createdavi:jira:updated:issue— Issue updated (any field change)avi:jira:deleted:issue— Issue deleted
Comment Events
avi:jira:created:comment— Comment addedavi:jira:updated:comment— Comment editedavi:jira:deleted:comment— Comment deleted
Attachment Events
avi:jira:created:attachment— File attachedavi:jira:deleted:attachment— Attachment removed
Sprint Events
avi:jira:created:sprint— Sprint createdavi:jira:updated:sprint— Sprint updated (started, completed, etc.)avi:jira:deleted:sprint— Sprint deleted
Issue Link Events
avi:jira:created:issuelink— Link added between issuesavi:jira:deleted:issuelink— Link removed
Version Events
avi:jira:created:version— Version createdavi:jira:updated:version— Version updated (released, etc.)avi:jira:deleted:version— Version deleted
Worklog Events
avi:jira:created:worklog— Work loggedavi:jira:updated:worklog— Worklog editedavi:jira:deleted:worklog— Worklog removed
Project Events
avi:jira:created:project— Project createdavi:jira:updated:project— Project updatedavi:jira:deleted:project— Project deleted (soft-delete)
User Events
avi:jira:created:user— User added to siteavi:jira:updated:user— User profile updated
Filter Events
avi:jira:created:filter— Saved filter createdavi:jira:updated:filter— Saved filter updatedavi:jira:deleted:filter— Saved filter deleted
Issue Type Events
avi:jira:created:issuetype— Issue type createdavi:jira:updated:issuetype— Issue type updatedavi: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);
});
}