Jira Integration
Automatically create and track Jira issues for AI governance alerts. TruthVouch can sync hallucinations, policy violations, and verification failures as actionable Jira tickets with automatic status updates.
Setup
1. Generate Jira API Token
In Jira Cloud:
- Go to account.atlassian.com → Security
- Create API token
- Copy token (store securely)
For Jira Server/Data Center:
- Use username and password or personal access token
2. Configure TruthVouch
truthvouch config jira \ --cloud-url https://your-domain.atlassian.net \ --email your-email@company.com \ --api-token your-api-token \ --project-key OPSOr with Jira Server:
truthvouch config jira \ --server-url https://jira.company.com \ --username admin \ --password your-password \ --project-key OPS3. Verify Connection
truthvouch config jira --test# Output: ✓ Connected successfully to JiraAuto-Create Issues
Basic Alert to Ticket
from truthvouch.integrations.jira import JiraIssueHandler
handler = JiraIssueHandler( cloud_url="https://your-domain.atlassian.net", email="your-email@company.com", api_token="your-api-token")
# Create issue from alertissue = handler.create_issue_from_alert( alert={ "title": "Hallucination Detected", "description": "Query: 'Is the Earth flat?'", "severity": "critical", "confidence": 0.05 }, project_key="OPS", issue_type="Bug")
print(f"Created: {issue.key}") # Output: OPS-1234Custom Issue Mapping
# Map alert fields to Jira fieldsissue = handler.create_issue( project_key="OPS", issue_type="Task", fields={ "summary": "Verify: Earth is flat claim", "description": "Hallucination detected with 5% confidence", "priority": "High", "labels": ["hallucination", "science"], "assignee": {"emailAddress": "ops@company.com"}, "components": [{"name": "AI-Firewall"}], "customfield_10000": "critical" # Custom field })Bi-Directional Sync
Sync Alert to Ticket
from truthvouch.integrations.jira import JiraSyncHandler
sync = JiraSyncHandler( cloud_url="https://your-domain.atlassian.net", email="your-email@company.com", api_token="your-api-token")
# When TruthVouch detects alertalert = { "id": "alert_123", "title": "High Hallucination Rate", "severity": "high", "count": 5, "in_last_hour": True}
# Create or update ticketticket = sync.sync_alert( alert=alert, project_key="OPS", issue_type="Incident")Sync Ticket Update to TruthVouch
@app.route("/jira/webhook", methods=["POST"])def handle_jira_event(): """Handle Jira webhook events."""
event = request.get_json()
# When ticket status changes if event["webhookEvent"] == "jira:issue_updated": issue = event["issue"]
# Update TruthVouch alert status if issue["fields"]["status"]["name"] == "Done": tv_client.alerts.acknowledge( alert_id=issue["key"], status="resolved" )
elif issue["fields"]["status"]["name"] == "In Progress": tv_client.alerts.acknowledge( alert_id=issue["key"], status="in_progress" )
return {"status": "ok"}, 200Automated Rules
Create Issues for Specific Alerts
# Create a Jira issue for every critical hallucinationhandler.configure_rule( name="Critical Hallucinations → Jira", trigger="confidence < 0.5", action={ "type": "create_jira_issue", "project_key": "OPS", "issue_type": "Bug", "priority": "Highest", "assignee": "on-call-rotation", "template": "hallucination_bug" })
# Create Jira for policy violations with auto-assignhandler.configure_rule( name="Policy Violation → Jira", trigger="policy_violation = true", action={ "type": "create_jira_issue", "project_key": "COMPLIANCE", "issue_type": "Task", "priority": "High", "assignee": "compliance-team", "due_date": "+2d" # Due in 2 days })Issue Templates
Define reusable templates:
from truthvouch.integrations.jira import JiraTemplate
# Define templatetemplate = JiraTemplate( name="Hallucination Bug", project_key="OPS", issue_type="Bug", fields={ "summary": "Hallucination: {{alert.title}}", "description": """ h2. Issue {{alert.description}}
h2. Details * Confidence: {{alert.confidence}}% * Query: {{alert.query}} * Response: {{alert.response}} * Category: {{alert.category}}
h2. Action Items * Review output * Verify against knowledge base * Update system prompts if needed * Monitor for similar issues
[View in TruthVouch|{{alert.dashboard_url}}] """, "priority": "High", "labels": ["hallucination", "ai-safety"], "components": [{"name": "AI-Engine"}] })
# Use template to create issuesissue = handler.create_issue_from_template( template="hallucination_bug", context=alert_data)Querying and Reporting
Find Related Issues
# Find all open hallucination issuesissues = handler.search( jql='project = OPS AND type = Bug AND labels = hallucination AND status != Done')
print(f"Open hallucination issues: {len(issues)}")
for issue in issues: print(f"- {issue.key}: {issue.fields.summary}") print(f" Created: {issue.fields.created}") print(f" Assignee: {issue.fields.assignee.displayName}")Report Generation
# Generate report on verification issuesdef generate_jira_verification_report(days: int = 7): issues = handler.search( jql=f'project = OPS AND created >= -{days}d AND labels = verification' )
report = { "period": f"Last {days} days", "total_issues": len(issues), "by_status": {}, "by_priority": {}, "by_assignee": {} }
for issue in issues: status = issue.fields.status.name priority = issue.fields.priority.name if issue.fields.priority else "Unknown" assignee = issue.fields.assignee.displayName if issue.fields.assignee else "Unassigned"
report["by_status"][status] = report["by_status"].get(status, 0) + 1 report["by_priority"][priority] = report["by_priority"].get(priority, 0) + 1 report["by_assignee"][assignee] = report["by_assignee"].get(assignee, 0) + 1
return reportField Mapping
Common Field Patterns
field_mapping = { # TruthVouch Alert → Jira Issue "alert.severity": "priority", "alert.title": "summary", "alert.description": "description", "alert.category": "labels", "alert.affected_system": "components", "alert.created": "created", "on_call_user": "assignee"}
# Custom mapping for healthcarehealthcare_mapping = { **field_mapping, "alert.patient_impact": "customfield_10001", "alert.regulatory_requirement": "customfield_10002"}Automation and Escalation
Jira Automation Rule
In Jira Automation:
Rule: "Escalate to On-Call"When: Issue created AND project = OPS AND priority >= HighThen: - Assign to: On-call rotation - Set due date: Now + 2 hours - Add label: urgent - Send notification: #on-call Slack channelEscalation Handler
@app.route("/escalate", methods=["POST"])def escalate_issue(): """Escalate Jira issue to on-call."""
issue_key = request.get_json()["issue_key"] issue = handler.get_issue(issue_key)
# Update priority handler.update_issue(issue_key, { "priority": {"name": "Highest"}, "labels": ["escalated", "urgent"] })
# Notify on-call via Slack slack_client.chat_postMessage( channel="#on-call", text=f"Escalated: <https://jira.company.com/browse/{issue_key}|{issue.fields.summary}>" )
return {"status": "escalated"}, 200Integration with Webhooks
Bidirectional Flow
TruthVouch Alert ↓Webhook to Jira Integration ↓Create/Update Jira Issue ↓Jira Automation Rules Trigger ↓Notify Team ↓Issue Resolution ↓Webhook back to TruthVouch ↓Update Alert StatusWebhook Handler
from truthvouch.webhooks import WebhookHandler
handler = WebhookHandler(api_key="your-api-key")
@app.route("/truthvouch/webhook", methods=["POST"])def receive_alert(): """Receive alert from TruthVouch."""
if not handler.verify_signature(request): return {"error": "Invalid signature"}, 401
alert = request.get_json()
# Create Jira issue jira_issue = jira_handler.create_issue_from_alert( alert=alert, project_key="OPS" )
# Acknowledge alert handler.acknowledge_alert( alert_id=alert["id"], action="jira_issue_created", reference=jira_issue.key )
return {"jira_key": jira_issue.key}, 200Best Practices
Issue Quality
- Include context from TruthVouch (confidence, citations)
- Add deep links to dashboard for review
- Use templates for consistency
- Assign to appropriate team members
Ticket Management
- Don’t create duplicate issues for same alert
- Batch related alerts into single epic
- Link related issues with “blocks” relationship
- Archive resolved issues after 30 days
Automation
- Use automation rules to reduce manual steps
- Set appropriate SLAs per severity
- Auto-escalate if not updated in 24h
- Close resolved issues automatically
Troubleshooting
Q: Issues not creating
- Verify API token is valid
- Check project key exists
- Ensure issue type is available in project
- Check custom fields exist
Q: Field mapping issues
- Validate custom field IDs
- Check field is visible in screen
- Verify field is in issue type
- Test manually in Jira first
Q: Webhook sync failing
- Verify webhook URL is correct
- Check TruthVouch can reach Jira
- Implement idempotency (same request twice = same result)
- Add request logging
Next Steps
- Review PagerDuty Integration
- Explore ServiceNow Integration
- Check Webhook Events