Skip to main content
Like AOF? Give us a star!
If you find AOF useful, please star us on GitHub. It helps us reach more developers and grow the community.

Jira Integration Reference

Complete reference for Jira platform integration with AOF.

Platform Support Statusโ€‹

PlatformStatusNotes
Jira Cloudโœ… StableFully tested with Atlassian Cloud
Jira Server๐Ÿงช ExperimentalCompatible API, needs validation
Jira Data Center๐Ÿงช ExperimentalCompatible API, needs validation

Important:

  • This documentation focuses on Jira Cloud, which is the primary tested platform
  • Jira Server and Data Center use compatible REST APIs but may have version-specific differences
  • Self-hosted deployments require additional network configuration (webhooks must reach AOF daemon)

Overviewโ€‹

AOF provides deep Jira integration through webhook-based triggers and the Jira REST API, enabling agents to automate issue triage, sprint management, work logging, and cross-platform workflows with GitHub.

Key Capabilities:

  • Automatic issue triage and categorization
  • AI-powered bug analysis and estimation
  • Sprint planning and backlog refinement
  • Work logging and time tracking automation
  • Multi-project coordination
  • GitHub/Jira cross-reference sync
  • Custom workflow automation

Architectureโ€‹

Jira integration consists of three components:

  1. Jira Trigger - Receives webhook events from Jira
  2. Jira Platform Adapter - Parses events and manages API calls
  3. Agents/Flows - Process events and take actions
Jira Webhook โ†’ AOF Daemon โ†’ Trigger โ†’ Agent/Flow โ†’ Jira API

Configuration Referenceโ€‹

Daemon Configurationโ€‹

The DaemonConfig enables Jira as a platform and configures authentication. Event filtering and command routing are defined in Triggers, not here.

Configure Jira platform in daemon.yaml:

apiVersion: aof.dev/v1
kind: DaemonConfig
metadata:
name: aof-daemon

spec:
server:
port: 3000
host: "0.0.0.0"
cors: true
timeout_secs: 60

# Enable platforms
platforms:
jira:
enabled: true
base_url: https://yourcompany.atlassian.net # Jira Cloud URL
auth:
type: api_token # api_token, oauth2, or pat
email_env: JIRA_EMAIL # For API token auth
token_env: JIRA_API_TOKEN
webhook_secret_env: JIRA_WEBHOOK_SECRET
bot_name: aofbot # Optional: for @mentions

# Resource discovery
triggers:
directory: ./triggers/
watch: true

agents:
directory: ./agents/

fleets:
directory: ./fleets/

flows:
directory: ./flows/
enabled: true

runtime:
max_concurrent_tasks: 10
task_timeout_secs: 300

Platform Configuration Fieldsโ€‹

FieldTypeRequiredDescription
enabledboolYesEnable Jira webhook endpoint (/webhook/jira)
base_urlstringYesJira instance URL (Cloud or self-hosted)
auth.typestringYesAuthentication type: api_token, oauth2, or pat
auth.email_envstringConditionalRequired for api_token auth
auth.token_envstringYesEnvironment variable name for token/PAT
webhook_secret_envstringYesEnvironment variable name for webhook secret
bot_namestringNoBot name for @mentions (default: "aofbot")

Authentication Typesโ€‹

API Token (Recommended for Cloud):

auth:
type: api_token
email_env: JIRA_EMAIL
token_env: JIRA_API_TOKEN

Personal Access Token (Server/Data Center):

auth:
type: pat
token_env: JIRA_PAT

OAuth 2.0 (Advanced):

auth:
type: oauth2
token_env: JIRA_OAUTH_TOKEN
# Additional OAuth config...

Self-Hosted Jira Configurationโ€‹

For Jira Server or Data Center deployments:

platforms:
jira:
enabled: true
base_url: https://jira.yourcompany.com # Self-hosted URL
auth:
type: pat
token_env: JIRA_PAT
webhook_secret_env: JIRA_WEBHOOK_SECRET

# Optional: Proxy configuration
proxy:
http_proxy: http://proxy.company.com:8080
https_proxy: https://proxy.company.com:8080
no_proxy: localhost,127.0.0.1

# Optional: TLS configuration
tls:
verify: true
ca_cert_path: /etc/ssl/certs/company-ca.pem

Note: Event filtering, project filtering, and command routing are configured in Trigger files, not in DaemonConfig. This separation keeps daemon config minimal and allows per-trigger customization.

Trigger Configurationโ€‹

Create trigger in triggers/jira-bug-triage.yaml:

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: jira-bug-triage

spec:
type: Jira

config:
webhook_secret_env: JIRA_WEBHOOK_SECRET

# Event filters
events:
- issue_created
- issue_updated
- comment_created

# Project filters
filters:
projects:
- "PROJ"
- "TEAM"

# Issue type filters
issue_types:
- "Bug"
- "Task"
- "Story"

# Status filters
statuses:
- "To Do"
- "In Progress"
- "Blocked"

# Priority filters (optional)
priorities:
- "High"
- "Critical"

# Label filters (optional)
labels:
- "needs-triage"
- "security"

# User filtering
allowed_users:
- "alice.developer"
- "bob.manager"

# Command routing
commands:
/triage:
agent: bug-triager
description: "Analyze and categorize this bug"

/estimate:
agent: story-estimator
description: "Estimate complexity and effort"

/analyze:
fleet: analysis-fleet
description: "Deep analysis of issue"

default_agent: jira-assistant

Trigger Configuration Fieldsโ€‹

FieldTypeRequiredDescription
typestringYesMust be Jira
config.webhook_secret_envstringYesEnvironment variable for webhook secret
config.eventsarrayYesJira webhook events to listen for
config.filtersobjectNoFilter events by project, type, status, etc.
config.allowed_usersarrayNoWhitelist of Jira usernames
commandsmapNoCommand routing to agents/fleets
default_agentstringNoDefault agent for unmatched events

Multi-Project Configurationโ€‹

AOF uses a single DaemonConfig + multiple Triggers architecture for multi-project Jira automation.

Architecture Overviewโ€‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Jira Webhook (single URL: /webhook/jira) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ DaemonConfig (global) โ”‚
โ”‚ - Enables Jira platform โ”‚
โ”‚ - Points to triggers/ directory โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ–ผ โ–ผ โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ bugs.yaml โ”‚ โ”‚ features.yaml โ”‚ โ”‚ support.yaml โ”‚
โ”‚ projects: PROJ โ”‚ โ”‚ projects: FEAT โ”‚ โ”‚ projects: SUP โ”‚
โ”‚ types: Bug โ”‚ โ”‚ types: Story โ”‚ โ”‚ types: Support โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Example: Per-Team Triggersโ€‹

Directory structure:

config/
daemon.yaml # Global config

triggers/
jira-bugs.yaml # Bug triage team
jira-features.yaml # Feature team
jira-support.yaml # Support team
jira-devops.yaml # DevOps team

Bug triage trigger (triggers/jira-bugs.yaml):

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: bug-triage-bot
labels:
team: qa

spec:
type: Jira
config:
webhook_secret_env: JIRA_WEBHOOK_SECRET

events:
- issue_created
- issue_updated
- comment_created

filters:
projects:
- "PROJ"
- "API"
issue_types:
- "Bug"
statuses:
- "Open"
- "To Do"
- "Reopened"

commands:
/triage:
agent: bug-triager

/reproduce:
agent: bug-reproducer

/assign:
agent: bug-assigner

default_agent: bug-assistant

Feature planning trigger (triggers/jira-features.yaml):

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: feature-planning-bot
labels:
team: product

spec:
type: Jira
config:
webhook_secret_env: JIRA_WEBHOOK_SECRET

events:
- issue_created
- issue_updated
- sprint_started
- sprint_closed

filters:
projects:
- "FEAT"
- "PROD"
issue_types:
- "Story"
- "Epic"
statuses:
- "Backlog"
- "Ready for Dev"

commands:
/estimate:
agent: story-estimator

/refine:
fleet: refinement-fleet

/acceptance:
agent: acceptance-criteria-writer

default_agent: product-assistant

Support team trigger (triggers/jira-support.yaml):

apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: support-bot
labels:
team: support

spec:
type: Jira
config:
webhook_secret_env: JIRA_WEBHOOK_SECRET

events:
- issue_created
- comment_created

filters:
projects:
- "SUP"
- "HELP"
issue_types:
- "Support"
- "Incident"
priorities:
- "High"
- "Critical"

commands:
/escalate:
flow: escalation-flow

/investigate:
fleet: support-fleet

default_agent: support-assistant

Webhook Routingโ€‹

When a webhook arrives, AOF:

  1. Parses the project key from the event payload
  2. Matches against filters.projects in each Trigger
  3. Routes to the first matching Trigger
  4. If no match, event is ignored (logged as unhandled)

Event Referenceโ€‹

Supported Eventsโ€‹

AOF supports all major Jira webhook events:

Event TypeActionDescription
issue_createdN/ANew issue created
issue_updatedN/AIssue fields updated (status, assignee, etc.)
issue_deletedN/AIssue deleted
comment_createdN/ANew comment posted
comment_updatedN/AComment edited
comment_deletedN/AComment deleted
sprint_createdN/ANew sprint created
sprint_startedN/ASprint started
sprint_closedN/ASprint closed
sprint_updatedN/ASprint details updated
sprint_deletedN/ASprint deleted
worklog_createdN/AWork logged on issue
worklog_updatedN/AWork log updated
worklog_deletedN/AWork log deleted

Event Detailsโ€‹

issue_createdโ€‹

Triggered when a new issue is created.

When it fires:

  • User creates issue via UI
  • Issue created via API
  • Issue imported from CSV/external system

Payload fields:

  • issue - Full issue object
  • user - User who created the issue
  • changelog - N/A (new issue)

issue_updatedโ€‹

Triggered when any issue field changes.

When it fires:

  • Status transition
  • Assignee changed
  • Fields updated (priority, labels, custom fields)
  • Attachments added/removed

Payload fields:

  • issue - Updated issue object
  • user - User who made the change
  • changelog - Array of field changes with old/new values

Common changelog items:

FieldDescription
statusStatus transition (e.g., "To Do" โ†’ "In Progress")
assigneeAssignee changed
priorityPriority changed
labelsLabels added/removed
sprintSprint added/removed
fixVersionsFix versions changed
descriptionDescription updated
summaryTitle updated

comment_createdโ€‹

Triggered when a comment is posted on an issue.

When it fires:

  • User posts comment via UI
  • Comment added via API
  • Bot or integration posts comment

Payload fields:

  • issue - Issue the comment is on
  • comment - Comment object with body, author, created timestamp
  • user - User who posted the comment

sprint_startedโ€‹

Triggered when a sprint begins.

When it fires:

  • Sprint manually started by Scrum Master
  • Sprint auto-started at scheduled time

Payload fields:

  • sprint - Sprint object (id, name, startDate, endDate, goal)
  • board - Board the sprint belongs to

sprint_closedโ€‹

Triggered when a sprint ends.

When it fires:

  • Sprint manually completed
  • Sprint auto-completed at end date

Payload fields:

  • sprint - Sprint object
  • board - Board object
  • issues_completed - Count of issues completed
  • issues_incomplete - Count of issues not completed

Webhook Payload Structureโ€‹

AOF normalizes Jira webhook payloads into a consistent structure.

Common Fieldsโ€‹

All Jira webhooks include these base fields:

{
"webhookEvent": "jira:issue_created",
"issue_event_type_name": "issue_created",
"user": {
"accountId": "5b10a2844c20165700ede21g",
"displayName": "Alice Developer",
"emailAddress": "alice@company.com"
},
"timestamp": 1640000000000
}

Issue Eventsโ€‹

{
"webhookEvent": "jira:issue_updated",
"issue": {
"id": "10001",
"key": "PROJ-123",
"fields": {
"summary": "Fix login bug",
"description": "Users cannot log in with SSO",
"status": {
"name": "In Progress",
"statusCategory": {
"key": "indeterminate"
}
},
"issuetype": {
"name": "Bug",
"subtask": false
},
"priority": {
"name": "High"
},
"assignee": {
"accountId": "5b10a2844c20165700ede21g",
"displayName": "Alice Developer"
},
"reporter": {
"accountId": "5b10a2844c20165700ede22h",
"displayName": "Bob Manager"
},
"labels": ["security", "sso"],
"created": "2024-01-15T10:30:00.000+0000",
"updated": "2024-01-15T14:45:00.000+0000"
}
},
"changelog": {
"items": [
{
"field": "status",
"fieldtype": "jira",
"from": "10000",
"fromString": "To Do",
"to": "10001",
"toString": "In Progress"
}
]
}
}

Comment Eventsโ€‹

{
"webhookEvent": "comment_created",
"comment": {
"id": "10200",
"body": "I can reproduce this on staging",
"author": {
"accountId": "5b10a2844c20165700ede21g",
"displayName": "Alice Developer"
},
"created": "2024-01-15T15:00:00.000+0000",
"updated": "2024-01-15T15:00:00.000+0000"
},
"issue": {
"key": "PROJ-123",
"fields": { ... }
}
}

Sprint Eventsโ€‹

{
"webhookEvent": "sprint_started",
"sprint": {
"id": 42,
"name": "Sprint 10",
"state": "active",
"startDate": "2024-01-15T09:00:00.000Z",
"endDate": "2024-01-29T17:00:00.000Z",
"goal": "Complete authentication refactor"
},
"board": {
"id": 1,
"name": "Engineering Board",
"type": "scrum"
}
}

Context Variablesโ€‹

When an agent is triggered by a Jira event, these variables are available in metadata:

Common Variablesโ€‹

VariableTypeDescription
event_typestringEvent type (issue_created, etc.)
timestampintegerEvent timestamp (milliseconds)
user_account_idstringUser account ID
user_display_namestringUser display name
user_emailstringUser email address

Issue Variablesโ€‹

Available for all issue events:

VariableTypeDescription
issue_idstringIssue ID
issue_keystringIssue key (PROJ-123)
issue_summarystringIssue title
issue_descriptionstringIssue description
issue_typestringIssue type (Bug, Story, etc.)
issue_statusstringCurrent status
issue_prioritystringPriority (High, Medium, Low)
issue_assignee_idstringAssignee account ID
issue_assignee_namestringAssignee display name
issue_reporter_idstringReporter account ID
issue_reporter_namestringReporter display name
issue_labelsarrayLabels on issue
issue_createdstringCreation timestamp
issue_updatedstringLast update timestamp
project_keystringProject key
project_namestringProject name

Comment Variablesโ€‹

Available for comment events:

VariableTypeDescription
comment_idstringComment ID
comment_bodystringComment text
comment_author_idstringAuthor account ID
comment_author_namestringAuthor display name
comment_createdstringComment creation timestamp

Sprint Variablesโ€‹

Available for sprint events:

VariableTypeDescription
sprint_idintegerSprint ID
sprint_namestringSprint name
sprint_statestringSprint state (future, active, closed)
sprint_start_datestringSprint start date
sprint_end_datestringSprint end date
sprint_goalstringSprint goal
board_idintegerBoard ID
board_namestringBoard name

Changelog Variablesโ€‹

Available for issue_updated events:

VariableTypeDescription
changelog_itemsarrayArray of changed fields

Each changelog item has:

  • field - Field name (status, assignee, etc.)
  • from_string - Old value (human-readable)
  • to_string - New value (human-readable)

Usage in Agent Instructionsโ€‹

spec:
instructions: |
You are analyzing issue {{ metadata.issue_key }}.

Issue Details:
- Title: {{ metadata.issue_summary }}
- Type: {{ metadata.issue_type }}
- Status: {{ metadata.issue_status }}
- Priority: {{ metadata.issue_priority }}
- Assignee: {{ metadata.issue_assignee_name }}
- Reporter: {{ metadata.issue_reporter_name }}

Description:
{{ metadata.issue_description }}

{% if metadata.comment_body %}
Latest Comment by {{ metadata.comment_author_name }}:
{{ metadata.comment_body }}
{% endif %}

{% if metadata.changelog_items %}
Recent Changes:
{% for item in metadata.changelog_items %}
- {{ item.field }}: {{ item.from_string }} โ†’ {{ item.to_string }}
{% endfor %}
{% endif %}

API Actionsโ€‹

Actions agents can perform on Jira via built-in tools.

Post Commentโ€‹

Post a comment on an issue.

# In agent instructions
tools:
- jira_post_comment

# Usage
Post a comment to {{ metadata.issue_key }}:
"This issue has been triaged and assigned to the backend team."

Rust API:

platform.post_comment("PROJ-123", "Comment text").await?;

Parameters:

  • issue_key (string) - Issue key (PROJ-123)
  • body (string) - Comment text (supports Jira markup)

Returns: Comment ID

Update Issueโ€‹

Update issue fields.

# Usage
Update {{ metadata.issue_key }}:
- Set status to "In Progress"
- Set assignee to "alice.developer"
- Add labels ["backend", "urgent"]

Rust API:

use serde_json::json;

platform.update_issue("PROJ-123", json!({
"fields": {
"assignee": {"accountId": "5b10a2844c20165700ede21g"},
"labels": ["backend", "urgent"],
"priority": {"name": "High"}
}
})).await?;

Parameters:

  • issue_key (string) - Issue key
  • fields (object) - Fields to update

Common fields:

FieldValue FormatExample
assignee{"accountId": "..."}Assign to user
priority{"name": "High"}Set priority
labels["label1", "label2"]Set labels
descriptionStringUpdate description
summaryStringUpdate title
Custom fieldsVaries by field typeSee Jira API docs

Transition Issueโ€‹

Change issue status (transition workflow).

# Usage
Transition {{ metadata.issue_key }} to "In Progress"

Rust API:

platform.transition_issue("PROJ-123", "31").await?;

Parameters:

  • issue_key (string) - Issue key
  • transition_id (string) - Transition ID (get from workflow)

Finding transition IDs:

curl -u email@example.com:api_token \
https://yourcompany.atlassian.net/rest/api/3/issue/PROJ-123/transitions

Add Labelโ€‹

Add labels to an issue.

# Usage
Add labels ["needs-review", "security"] to {{ metadata.issue_key }}

Rust API:

platform.add_labels("PROJ-123", &["needs-review", "security"]).await?;

Parameters:

  • issue_key (string) - Issue key
  • labels (array) - Labels to add

Remove Labelโ€‹

Remove a label from an issue.

# Usage
Remove label "needs-triage" from {{ metadata.issue_key }}

Rust API:

platform.remove_label("PROJ-123", "needs-triage").await?;

Parameters:

  • issue_key (string) - Issue key
  • label (string) - Label to remove

Assign Userโ€‹

Assign an issue to a user.

# Usage
Assign {{ metadata.issue_key }} to "alice.developer"

Rust API:

platform.assign_issue("PROJ-123", "5b10a2844c20165700ede21g").await?;

Parameters:

  • issue_key (string) - Issue key
  • account_id (string) - User account ID

Finding account IDs:

curl -u email@example.com:api_token \
https://yourcompany.atlassian.net/rest/api/3/user/search?query=alice

Log Workโ€‹

Log time spent on an issue.

# Usage
Log 2 hours of work on {{ metadata.issue_key }}
Comment: "Fixed authentication bug"

Rust API:

use serde_json::json;

platform.log_work("PROJ-123", json!({
"timeSpent": "2h",
"comment": "Fixed authentication bug",
"started": "2024-01-15T09:00:00.000+0000"
})).await?;

Parameters:

  • issue_key (string) - Issue key
  • time_spent (string) - Time format (e.g., "2h 30m", "1d")
  • comment (string, optional) - Work log comment
  • started (string, optional) - Start timestamp

Time formats:

  • 1w - 1 week
  • 2d - 2 days
  • 4h - 4 hours
  • 30m - 30 minutes
  • 1h 30m - Combined

Create a link between two issues.

# Usage
Link {{ metadata.issue_key }} to PROJ-456 as "relates to"

Rust API:

use serde_json::json;

platform.link_issues(json!({
"type": {"name": "Relates"},
"inwardIssue": {"key": "PROJ-123"},
"outwardIssue": {"key": "PROJ-456"}
})).await?;

Parameters:

  • type (string) - Link type name
  • inward_issue (string) - Source issue key
  • outward_issue (string) - Target issue key

Common link types:

TypeDescription
BlocksThis issue blocks another
RelatesGeneral relationship
DuplicatesDuplicate issue
CausesThis issue causes another
ClonesCloned from another issue

Securityโ€‹

Webhook Verificationโ€‹

AOF validates webhook requests using a shared secret.

How it works:

  1. Configure webhook secret in Jira webhook settings
  2. AOF validates incoming requests against configured secret
  3. Requests without valid signature are rejected

Configuration:

spec:
config:
webhook_secret_env: JIRA_WEBHOOK_SECRET # Required

Generate secure secret:

openssl rand -hex 32

Authentication Methodsโ€‹

Create API token:

  1. Go to https://id.atlassian.com/manage-profile/security/api-tokens
  2. Click "Create API token"
  3. Copy token and store securely

Configure:

export JIRA_EMAIL="your-email@company.com"
export JIRA_API_TOKEN="your-api-token"

Permissions: Inherits permissions from your Jira Cloud account.

Personal Access Token (Self-Hosted)โ€‹

For Jira Server/Data Center:

  1. Go to Profile โ†’ Personal Access Tokens
  2. Create new token with required permissions
  3. Copy token immediately (shown only once)

Configure:

export JIRA_PAT="your-personal-access-token"

OAuth 2.0 (Advanced)โ€‹

For programmatic access without user credentials:

  1. Register OAuth 2.0 app in Jira
  2. Obtain client ID and secret
  3. Implement OAuth flow
  4. Store refresh token

Configuration:

platforms:
jira:
auth:
type: oauth2
client_id_env: JIRA_OAUTH_CLIENT_ID
client_secret_env: JIRA_OAUTH_SECRET
token_env: JIRA_OAUTH_TOKEN

Project Filteringโ€‹

Whitelist projects for security:

filters:
projects:
- "PROJ" # Specific project
- "TEAM" # Another project
- "PROD-*" # Pattern matching (if supported)

User Filteringโ€‹

Restrict who can trigger automation:

config:
allowed_users:
- "alice.developer"
- "bob.manager"
- "qa-bot"

Events from users not in this list will be ignored.

Note: User filtering is based on Jira usernames/account IDs. Group-based authorization is planned for a future release.


Rate Limitingโ€‹

Jira API Limitsโ€‹

TypeLimitNotes
Jira CloudVaries by plan~100-300 req/sec depending on subscription
Jira ServerConfigurableSet by admin in Rate Limiting settings
Search API20 req/secLower limit for JQL searches

Jira Cloud rate limits:

  • Free tier: ~100 requests/second
  • Standard/Premium: ~200-300 requests/second
  • Enterprise: Custom limits

Mitigation Strategiesโ€‹

  1. Batch operations - Update multiple fields in single API call
  2. Use webhooks - React to events instead of polling
  3. Cache data - Store frequently accessed data locally
  4. Implement backoff - Retry with exponential backoff
  5. Use bulk APIs - Bulk update, bulk delete operations

Check rate limit:

# Jira Cloud
curl -u email@example.com:api_token \
-X GET "https://yourcompany.atlassian.net/rest/api/3/myself" \
-H "Accept: application/json"

Check response headers:

  • X-RateLimit-Limit - Rate limit ceiling
  • X-RateLimit-Remaining - Requests left in window
  • Retry-After - Seconds until retry (if rate limited)

AOF handles retries automatically with exponential backoff when rate limit is hit.


Environment Variablesโ€‹

# Jira Cloud (API Token)
export JIRA_EMAIL="your-email@company.com"
export JIRA_API_TOKEN="your-api-token"
export JIRA_WEBHOOK_SECRET="random-secret-key"

# Jira Server/Data Center (PAT)
export JIRA_PAT="your-personal-access-token"
export JIRA_WEBHOOK_SECRET="random-secret-key"

# LLM provider
export GOOGLE_API_KEY="xxxxx"
# OR
export ANTHROPIC_API_KEY="xxxxx"

Examplesโ€‹

Auto-Triage Bugsโ€‹

# triggers/jira-bug-triage.yaml
apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: bug-triage

spec:
type: Jira
config:
webhook_secret_env: JIRA_WEBHOOK_SECRET
events:
- issue_created
filters:
projects: ["PROJ"]
issue_types: ["Bug"]

default_agent: bug-triager
# agents/bug-triager.yaml
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: bug-triager

spec:
model: google:gemini-2.5-flash

instructions: |
Analyze bug {{ metadata.issue_key }}.

Issue: {{ metadata.issue_summary }}
Description: {{ metadata.issue_description }}

1. Determine severity based on description
2. Set priority (Critical/High/Medium/Low)
3. Add relevant labels (backend, frontend, database, etc.)
4. Suggest assignee based on component
5. Post analysis comment

tools:
- jira_update_issue
- jira_add_labels
- jira_post_comment

Story Point Estimationโ€‹

# triggers/jira-estimation.yaml
apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: story-estimation

spec:
type: Jira
config:
events:
- issue_created
filters:
projects: ["FEAT"]
issue_types: ["Story", "Task"]

commands:
/estimate:
agent: story-estimator
# agents/story-estimator.yaml
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: story-estimator

spec:
model: google:gemini-2.5-flash

instructions: |
Estimate story points for {{ metadata.issue_key }}.

Story: {{ metadata.issue_summary }}
Description: {{ metadata.issue_description }}

Analyze complexity based on:
1. Technical complexity
2. Unknown factors
3. Dependencies
4. Testing requirements

Recommend story points (1, 2, 3, 5, 8, 13) and explain reasoning.
Post comment with analysis.

tools:
- jira_post_comment

Sprint Planning Automationโ€‹

# triggers/jira-sprint.yaml
apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: sprint-planning

spec:
type: Jira
config:
events:
- sprint_started
- sprint_closed

default_fleet: sprint-fleet
# fleets/sprint-fleet.yaml
apiVersion: aof.dev/v1
kind: Fleet
metadata:
name: sprint-fleet

spec:
agents:
- name: sprint-analyzer
role: coordinator
- name: velocity-tracker
role: specialist
- name: report-generator
role: specialist

workflow: |
On sprint start:
1. sprint-analyzer: Analyze sprint capacity and commitments
2. velocity-tracker: Calculate team velocity from previous sprints
3. report-generator: Generate sprint kickoff report

On sprint close:
1. sprint-analyzer: Review completed vs planned work
2. velocity-tracker: Update velocity metrics
3. report-generator: Generate retrospective report

GitHub/Jira Cross-Referenceโ€‹

# agents/github-jira-sync.yaml
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: github-jira-sync

spec:
model: google:gemini-2.5-flash

instructions: |
You sync GitHub PRs with Jira issues.

When PR is opened:
1. Extract Jira issue key from PR title (PROJ-123)
2. Post comment on Jira issue with PR link
3. Add "in-review" label to Jira issue

When PR is merged:
1. Transition Jira issue to "Done"
2. Post merge confirmation comment
3. Log work time based on PR size

tools:
- jira_post_comment
- jira_transition_issue
- jira_add_labels
- jira_log_work

Webhook Setupโ€‹

1. Create Webhook in Jiraโ€‹

Jira Cloudโ€‹

  1. Go to Settings โ†’ System โ†’ WebHooks
  2. Click Create a WebHook
  3. Configure:
    • Name: AOF Automation
    • Status: Enabled
    • URL: https://your-domain.com/webhook/jira
    • Secret: Your JIRA_WEBHOOK_SECRET value
    • Events: Select desired events or check "All issues"
    • Exclude body: Uncheck (AOF needs full payload)

Jira Server/Data Centerโ€‹

  1. Go to Settings โ†’ System โ†’ Advanced โ†’ WebHooks
  2. Create webhook with same configuration as Cloud
  3. Ensure firewall allows webhook traffic to AOF daemon

2. Expose Endpointโ€‹

For production:

# HTTPS required
https://your-domain.com/webhook/jira

For local testing: Use a tunnel service:

# Option 1: Cloudflared (no signup)
brew install cloudflared
cloudflared tunnel --url http://localhost:3000

# Option 2: ngrok (free account)
ngrok http 3000

Use tunnel URL as webhook URL in Jira.

3. Verify Webhookโ€‹

  1. Test webhook in Jira webhook settings
  2. Check webhook delivery logs in Jira
  3. Verify AOF logs show received event
# Check logs
tail -f /var/log/aof/daemon.log

# Look for:
# INFO Jira webhook received: issue_created
# INFO Posted comment to PROJ-123

Troubleshootingโ€‹

Webhook Not Triggeringโ€‹

Symptoms: Jira webhook shows success but agent doesn't run

Solutions:

  1. Check webhook delivery logs in Jira admin panel
  2. Verify webhook secret matches JIRA_WEBHOOK_SECRET
  3. Check firewall allows Jira Cloud IPs (if using Cloud)
  4. Verify daemon is running: aofctl serve --config daemon.yaml
  5. Check logs: RUST_LOG=debug aofctl serve

Authentication Failedโ€‹

Symptoms: 401 Unauthorized in logs

Solutions:

  1. Verify API token/PAT is valid
  2. For API token: Confirm JIRA_EMAIL matches token owner
  3. Test credentials manually:
    curl -u email@example.com:api_token \
    https://yourcompany.atlassian.net/rest/api/3/myself
  4. Check token hasn't expired (PATs expire in Server/DC)

Cannot Post Commentsโ€‹

Symptoms: Agent runs but comments don't appear

Solutions:

  1. Verify token has correct permissions
  2. Check user has access to project
  3. Verify issue exists and is not deleted
  4. Test comment API manually:
    curl -u email@example.com:api_token \
    -X POST "https://yourcompany.atlassian.net/rest/api/3/issue/PROJ-123/comment" \
    -H "Content-Type: application/json" \
    -d '{"body": "Test comment"}'

Base URL Configurationโ€‹

Symptoms: 404 Not Found or connection errors

Solutions:

  1. Verify base_url format:
    • Jira Cloud: https://yourcompany.atlassian.net
    • Self-hosted: https://jira.yourcompany.com
  2. No trailing slash in URL
  3. For self-hosted: Verify DNS resolution and network access

Rate Limit Issuesโ€‹

Symptoms: 429 Too Many Requests errors

Solutions:

  1. Check rate limit headers in API responses
  2. Reduce webhook event frequency (filter by project/type)
  3. Implement caching for frequently accessed data
  4. Contact Atlassian support to increase limits (Cloud)

Best Practicesโ€‹

1. Filter Events Preciselyโ€‹

โŒ Too broad:

events:
- issue_created
- issue_updated
- comment_created

โœ… Specific:

events:
- issue_created
- comment_created
filters:
projects: ["PROJ"]
issue_types: ["Bug"]
statuses: ["Open"]

2. Use Project Filtersโ€‹

For production:

filters:
projects:
- "PROD"
- "API"
issue_types:
- "Bug"
- "Incident"

Prevents accidental automation on test projects.

3. Implement Approval Gatesโ€‹

For destructive actions:

spec:
instructions: |
Before transitioning to Done:

1. Verify all subtasks are complete
2. Check PR is merged (if linked)
3. Ensure QA has signed off
4. Confirm no blocking issues
5. Request human approval if uncertain

4. Cache Jira Dataโ€‹

Reduce API calls:

spec:
memory: "File:./jira-cache.json:1000"

instructions: |
Before making API calls, check memory cache for:
- User account IDs
- Transition IDs
- Custom field IDs

5. Use Structured Commentsโ€‹

Post comments with clear structure:

spec:
instructions: |
Post comment with this format:

h3. AI Analysis
[Analysis summary]

h4. Recommended Actions
* Action 1
* Action 2

h4. Severity Assessment
Priority: [High/Medium/Low]
Labels: [suggested-labels]

6. Log Work Automaticallyโ€‹

Track time spent on automated tasks:

spec:
instructions: |
After completing analysis:
1. Log work time based on complexity
2. Add comment explaining what was done
3. Update issue status if appropriate

Enterprise Considerationsโ€‹

Self-Hosted Deploymentโ€‹

Network requirements:

  • Jira must be able to reach AOF daemon webhook endpoint
  • Consider reverse proxy for SSL termination
  • Firewall rules to allow Jira โ†’ AOF traffic

Configuration:

platforms:
jira:
base_url: https://jira.company.internal
proxy:
http_proxy: http://proxy.company.com:8080
https_proxy: https://proxy.company.com:8080
tls:
verify: true
ca_cert_path: /etc/ssl/certs/company-ca.pem

High Availabilityโ€‹

Run multiple AOF daemon replicas:

# Kubernetes deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: aof-daemon
spec:
replicas: 3
template:
spec:
containers:
- name: aof
image: ghcr.io/agenticdevops/aof:latest

Scaling Recommendationsโ€‹

ScaleProjectsIssues/daySetup
Small1-10Up to 1000Single daemon
Medium10-501000-50002-3 replicas
Large50-2005000-20000Sharded by project
Enterprise200+20000+Message queue (planned)

See Alsoโ€‹