Skip to content

Events & Async Actions

Foundation uses Forge’s event system for two purposes:

  1. Product event triggers — Jira fires events on issue/sprint/link changes; the backend catches them to keep the issue cache fresh
  2. Async event consumers — Long-running operations (sync agent execution, cache refresh, resource leveling, WBS generation, import) run in async context with a 15-minute timeout


Defined in manifest.yml under modules.trigger. These handlers respond to Jira platform events.

Handles all issue lifecycle events. This is the primary mechanism for keeping the issue cache fresh.

Trigger KeyEventDescription
icavi:jira:created:issueNew issue created in Jira
iuavi:jira:updated:issueIssue field changed (self-skipped via ignoreSelf: true)
idavi:jira:deleted:issueIssue deleted from Jira
ilcavi:jira:created:issuelinkIssue link created
ildavi:jira:deleted:issuelinkIssue link deleted

Processing flow:

  1. Extract issue ID(s) and project key(s) from the event payload
  2. Set per-project event timestamps in KVS (last-issue-event-ts:${projectKey}) for staleness detection
  3. For created/updated events:
    • Fetch the full issue from Jira (2 API points)
    • Upsert into issue_cache
    • Find which lenses contain this issue
    • Publish hierarchy_changed realtime event to affected lenses
    • Trigger auto-sync for affected projects
  4. For deleted events:
    • Delete from issue_cache
    • Remove hierarchy nodes referencing the deleted issue
    • Publish hierarchy_changed to affected lenses
  5. For link events:
    • Re-fetch both linked issues to update links_json
    • Update cache entries

Cost: Product event triggers themselves are free (no API points). The handler’s fetchIssueByKey() call costs 2 points.

Known limitation (ECO-395): avi:jira:updated:issue does NOT fire when workflow transitions use Custom Event Notifications. Cache may go stale for up to 60 minutes in this case.

Handles sprint lifecycle events.

Trigger KeyEvent
speavi:jira:started:sprint
speavi:jira:closed:sprint
speavi:jira:updated:sprint

Processing flow:

  1. Extract sprint ID from event
  2. Fetch all issues in the sprint via JQL: sprint = ${sprintId}
  3. Upsert each issue into the cache (updates sprint state: active/closed/future)
  4. Find affected lenses and publish hierarchy_changed events

Uninstall Handler (events/uninstall-handler.ts)

Section titled “Uninstall Handler (events/uninstall-handler.ts)”
Trigger KeyEvent
oauavi:forge:uninstalled:app

Handles app uninstallation. Performs cleanup of app-specific data.


Cache Integrity Check (events/cache-integrity.ts)

Section titled “Cache Integrity Check (events/cache-integrity.ts)”
Trigger KeyScheduleTimeout
cicEvery hour25 seconds (standard)

Periodic cache maintenance:

  1. Stale entry re-fetch: Finds cache entries with cached_at older than 2 hours. Re-fetches from Jira (max 50 per run). Respects rate limit budget.
  2. Deleted issue cleanup: If a re-fetch returns null (issue deleted in Jira), deletes the cache entry and removes orphaned hierarchy nodes. This catches missed avi:jira:deleted:issue events.
  3. Orphan node cleanup: Finds hierarchy nodes referencing non-existent cache entries.

Daily Health Check (events/daily-health-check.ts)

Section titled “Daily Health Check (events/daily-health-check.ts)”
Trigger KeyScheduleTimeout
dhtEvery day900 seconds (15 min)

Daily analytics and alerting:

  1. Processes all lenses in batches of 25
  2. For each lens:
    • Loads all issue nodes with cached data
    • Computes health metrics: total items, completed, overdue, unassigned, story points
    • Calculates a health score (0-100)
    • Upserts a lens_snapshots row for the current date
  3. Evaluates alert rules from automation_rules table
  4. Creates alerts in the alerts table when thresholds are breached

Defined in manifest.yml under modules.consumer. These process messages from Forge queues with extended timeouts (up to 15 minutes).

Sync Agent Executor (events/sync-agent-executor.ts)

Section titled “Sync Agent Executor (events/sync-agent-executor.ts)”
Consumer KeyQueueFunctionTimeout
saegenerator-queuesaDefault (25s)

Executes all sync agents for a lens sequentially.

Processing flow for each sync agent:

  1. Read the generator’s config (JQL query, generator type, parent node)
  2. For jql_insert generators:
    • Execute JQL query via fetchIssuesByJql()
    • Upsert fetched issues into cache
    • Add new hierarchy nodes for issues not yet in the lens
    • Delete hierarchy nodes for issues no longer matching the JQL
  3. For child_extend generators:
    • Fetch children of specified parent issues
    • Add child nodes to the hierarchy under their parents
  4. For hierarchy_builder generators:
    • Build a full project hierarchy from Jira parent-child relationships
  5. For auto_project generators:
    • Verify project still exists in Jira
    • If missing, clean up stale issues and delete the generator
    • If available, sync all project issues
  6. Update generator execution status (last_executed_at, last_execution_status, last_known_total)
  7. Store incremental diff in KVS for the frontend to display

Concurrency: Uses concurrency: { key: 'gen-${lensId}', limit: 1 } to ensure only one sync runs per lens at a time.

Job tracking: Active jobs are tracked in KVS at active-gen-job:${lensId}. The marker is set before queue push and cleared after completion (or expires after 15 minutes).

Leveling Executor (events/leveling-executor.ts)

Section titled “Leveling Executor (events/leveling-executor.ts)”
Consumer KeyQueueFunction
lveleveling-queuele

Runs the resource leveling algorithm for a lens. Updates leveling_jobs status as it progresses.

Cache Refresh Executor (events/cache-refresh-executor.ts)

Section titled “Cache Refresh Executor (events/cache-refresh-executor.ts)”
Consumer KeyQueueFunctionTimeout
crecache-refresh-queuecr120 seconds

Processes per-project cache refresh requests (initiated by admin).

Per-project flow:

  1. Read the job status from KVS
  2. Mark project as refreshing
  3. Check rate limit budget (estimated 501 points per project)
  4. Fetch all issues via JQL: project = "${pk}" ORDER BY updated DESC (max 500)
  5. Batch upsert into cache
  6. Reconcile deleted issues
  7. Mark project as completed (or throttled/failed)
  8. Check if all projects are done; if so, mark the overall job as completed

Import Executor (events/import-executor.ts)

Section titled “Import Executor (events/import-executor.ts)”
Consumer KeyQueueFunctionTimeout
imeimport-queueih900 seconds

Processes hierarchy import jobs (third-party imports, project imports).

Consumer KeyQueueFunctionTimeout
wbewbs-queuewb900 seconds

Processes AI-driven Work Breakdown Structure generation jobs.


Defined in manifest.yml under modules.action. These are invoked by the Rovo AI agent (conversational interface in Jira’s Rovo Chat sidebar).

VerbBehaviorUse For
GETAuto-executes without user confirmationRead-only queries
CREATERequires user confirmationCreating new data
UPDATERequires user confirmationModifying existing data
DELETERequires user confirmationRemoving data
TRIGGERRequires user confirmationOperations with side effects

Each action maps to a function handler in foundation/src/actions/:

KeyNameVerbHandlerDescription
addIssuesAdd IssuesCREATEactions/add-issuesAdd issues by JQL
createFlexItemFlex ItemCREATEactions/create-flex-itemCreate a grouping node
moveNodeMoveUPDATEactions/move-nodeMove node in hierarchy
bulkUpdateBulk UpdateUPDATEactions/update-fieldBulk update issue fields
createIssueNew IssueCREATEactions/create-and-add-issueCreate Jira issue + add
runSyncRun SyncTRIGGERactions/execute-sync-agentsExecute sync agents
lensSummarySummaryGETactions/get-summaryLens summary text
lensContextContextGETactions/get-lens-contextLens context data
issueHierHierarchyGETactions/get-work-issue-hierarchyIssue type hierarchy
buildWbsWBSCREATEactions/build-wbsAI WBS generation
analyzeGapsGapsGETactions/analyze-section-gapsGap analysis
removeNodesRemoveDELETEactions/remove-nodesRemove from hierarchy
orchestrateOrchestrateCREATEactions/orchestrate-lensMulti-step orchestration
applySuggestionApplyUPDATEactions/apply-suggestionApply AI suggestion
listLensesLensesGETactions/lens-crudList all lenses
listSyncList SyncGETactions/sync-agent-crudList sync agents
createSyncCreate SyncCREATEactions/sync-agent-crudCreate sync agent
deleteSyncDelete SyncDELETEactions/sync-agent-crudDelete sync agent
listViewsList ViewsGETactions/view-crudList views
cfgViewConfig ViewUPDATEactions/view-crudConfigure view
findNodesFindGETactions/find-nodesSearch nodes
bulkMoveBulk MoveUPDATEactions/bulk-move-nodesBulk move nodes
syncIssuesSyncTRIGGERactions/sync-issuesManual sync
getTransitionsTransitionsGETactions/get-transitions-actionStatus transitions
fieldOptsField OptsGETactions/get-field-options-actionField options
validateJqlCheck JQLGETactions/validate-jqlJQL validation
createViewNew ViewCREATEactions/view-crudCreate view
setDefViewDefault ViewUPDATEactions/view-crudSet default view
lensDetailsLens DetailsGETactions/get-lens-detailsLens detail data

These use a _action parameter to multiplex multiple sub-actions through a single manifest entry, conserving the limited action slot budget.

KeyNameVerbSub-actions
lensCrudLens CRUDTRIGGERcreateLens, renameLens, deleteLens
hierMetaHier MetaTRIGGERgetTransitions, getFieldOptions, getLensDetails, getNodeDetails, getSubtreeStats, groupNodesBy, sortNodes, renameFlexItem, flattenSubtree, mergeFlexItems
viewPermView PermTRIGGERcreateView, deleteView, setDefaultView, grantPermission, revokePermission
jiraUtilJira UtilGETvalidateJql, analyzeJiraProject, createFromTemplate
r2gR2GGET19 read-only intelligence/analytics actions
r2r5R2R5TRIGGER14 destructive operations requiring confirmation

See API Reference - Rovo Agent Dispatchers for the complete sub-action listing.


Functions are defined in manifest.yml under modules.function with 2-character keys to minimize CaaS manifest byte size:

KeyHandlerPurpose
rindex.handlerMain resolver (all frontend-invoked resolvers)
ieevents/issue-handler.handlerIssue events
seevents/sprint-handler.handlerSprint events
cievents/cache-integrity.handlerHourly cache check
dhevents/daily-health-check.handlerDaily health snapshots (900s timeout)
saevents/sync-agent-executor.handlerSync agent execution
leevents/leveling-executor.handlerResource leveling
crevents/cache-refresh-executor.handlerCache refresh (120s timeout)
ihevents/import-executor.handlerImport processing (900s timeout)
wbevents/wbs-executor.handlerWBS generation (900s timeout)
uhevents/uninstall-handler.handlerApp uninstall
f1-fw, g1-g3actions/*.handlerRovo agent action handlers

The Forge CaaS manifest has a ~257KB byte limit (ECO-1310). The current manifest uses slim conventions:

  • 2-char function keys
  • 2-3 char module/trigger/consumer keys
  • . for action descriptions
  • x for input titles
  • No optional fields

Current state: 35 actions, ~22,850 bytes with ~650 bytes of headroom. Run node scripts/check-manifest-limits.js before adding actions.