Getting started with your first Autonomous Ticket Resolution agentic workflow
This guide walks you through building a complete Autonomous Ticket Resolution (ATR) workflow from scratch. By the end, a Jira ticket will arrive in Port already enriched with service context, scored for AI readiness, and delegated to Cursor after a single human approval.
The guide covers the Triage and Build stages of the ATR lifecycle:
- Triage - enrich the ticket with catalog context, then score it for AI readiness using deterministic scorecard rules.
- Build - surface the enriched ticket for human review via Slack, then delegate to Cursor with one click.
Want to follow the guide step by step? Scroll down to Build it step by step.
Or implement it in one shot with your coding assistant


Connect Port MCP to your coding assistant, then copy the prompt below to implement this entire guide automatically against your Port account.
I want to set up an Autonomous Ticket Resolution (ATR) workflow in Port.
Here is what I need you to do, step by step:
1. Extend the Jira Issue blueprint in Port with the following properties:
- serviceTier (string): tier of the related service, mirrored from the catalog
- activeIncidents (number): open incidents on the related service
- repoUrl (string, url): primary repository for the related service
- aiReadinessReason (string, markdown): reason the ticket passed or failed AI readiness scoring
Add a relation called "service" targeting the "service" blueprint (required: false, many: false).
2. Create a scorecard on the Jira Issue blueprint called "AI readiness" with these three rules:
- serviceTier != "Tier 1" (Tier 1 services need human oversight)
- activeIncidents == 0 (no active incidents on the service)
- description != "" (ticket must have a description)
Set Bronze level when all three rules pass.
3. Create a Port workflow with identifier "atr-workflow" and title "ATR: Triage and build".
The workflow must contain these nodes in sequence:
- trigger (EVENT_TRIGGER): fires on ENTITY_CREATED for jiraIssue blueprint
- enrich (AI): queries the catalog for service tier, active incidents, and repo URL related to the Jira issue. Uses tools get_entity and search_entities. Returns serviceTier (string), activeIncidents (number), repoUrl (string).
- writeback (UPSERT_ENTITY): writes serviceTier, activeIncidents, repoUrl back to the Jira issue entity using mapping.
- notify (WEBHOOK): POSTs a Slack message to {{ .secrets["SLACK_WEBHOOK_URL"] }} with the ticket title, service tier, active incidents count, and a link to the entity in Port.
- approve (INPUT): pauses the workflow and asks a human to approve or decline delegation to Cursor. Two buttons: Approve (PRIMARY) and Decline (DANGER). One responder required for each outlet.
- delegate (INTEGRATION_ACTION create_agent): launches a Cursor cloud agent via the [Cursor Cloud Agents](/workflows/build-workflows/nodes/action-nodes/integration-actions/ai/cursor-cloud-agents) integration, passes the ticket title, description, and service tier in the prompt, uses repoUrl from the enrich step as the repository, and sets autoCreatePr: true with reportCompletion enabled.
- update-status (UPSERT_ENTITY): writes the PR URL from the Cursor agent back to aiReadinessReason on the Jira issue entity.
Connections: trigger → enrich → writeback → notify → approve → delegate (approve outlet only) → update-status.
4. Add the required secret in Port Settings > Secrets:
- SLACK_WEBHOOK_URL: the Slack incoming webhook URL
Install the [Cursor Cloud Agents](/agent-management/external-agents/cursor-cloud-agents) integration and note the installation ID for the delegate node.
Use Port MCP to create each artifact. Confirm each step before moving to the next.
Prerequisites
- A Port account.
- Port's Jira integration installed and syncing issues.
- A
serviceblueprint in your catalog with at least one entity. If you haven't set this up, see Port's GitHub integration or create a service blueprint manually. - A Cursor API key.
- A Slack incoming webhook URL.
The scorecard and enrichment steps use the related service to determine AI readiness. You can still follow this guide with a manually created test service entity. The enrichment will be less rich, but the workflow structure is identical.
Build it step by step
This guide uses Jira for tickets, Port's service catalog for context, Slack for notifications, and Cursor for delegation. Each of these is a choice, not a requirement. The same workflow pattern works with Linear, your own entity model, any webhook-based notification channel, and any coding agent that accepts a prompt and a repository.
We need the Jira issue blueprint to store enrichment data and relate to a service. This is how Port knows which service a ticket touches.
Add properties
- Go to the Data model page in Port.
- Select the Jira Issue blueprint.
- Click
{...} Edit JSON. - Add the following properties to the
schema.propertiesobject:
Properties to add (click to expand)
"serviceTier": {
"type": "string",
"title": "Service tier",
"description": "Tier of the related service, mirrored from the catalog."
},
"activeIncidents": {
"type": "number",
"title": "Active incidents",
"description": "Number of open incidents on the related service."
},
"repoUrl": {
"type": "string",
"title": "Repository URL",
"format": "url",
"description": "Primary repository for the related service."
},
"aiReadinessReason": {
"type": "string",
"title": "AI readiness reason",
"format": "markdown",
"description": "Explanation of why this ticket passed or failed AI readiness scoring."
}
Add a service relation
Still in the JSON editor, add the following to the relations object:
"service": {
"title": "Service",
"target": "service",
"required": false,
"many": false
}
- Click Save to update the blueprint.
The Jira integration can auto-populate this relation using mapping rules if your Jira issues include a service label or component.
The scorecard is the governance layer. It evaluates every work item against deterministic rules and produces a clear pass/fail signal that the workflow reads automatically.
- Go to the Data model page in Port.
- Select the Jira Issue blueprint.
- Click Scorecards and then + New scorecard.
- Name it
AI readiness. - Add the following rules:
| Rule | Condition | Description |
|---|---|---|
| Service tier is not critical | serviceTier != "Tier 1" | Tier 1 services need human oversight. |
| No active incidents | activeIncidents == 0 | Don't delegate during an active incident. |
| Ticket has a description | description != "" | An agent needs enough context to work from. |
- Set the scorecard to Bronze level when all three rules pass.
- Click Save.
These three rules are a starting point. Your platform team will likely add more signals over time: priority level, blast radius score, service ownership completeness, or recent deploy frequency. The point is that routing is deterministic and auditable, not a judgment call.
This single workflow handles the full Triage and Build loop. It fires when a Jira issue is created, enriches the work item with catalog context, notifies the team in Slack, then pauses for a human to approve before launching a Cursor agent.
- Go to the workflows page.
- Click + New workflow.
- Toggle to JSON mode and paste the following:
ATR workflow JSON (click to expand)
{
"identifier": "atr-workflow",
"title": "ATR: Triage and build",
"nodes": [
{
"identifier": "trigger",
"title": "Jira issue created",
"config": {
"type": "EVENT_TRIGGER",
"event": {
"type": "ENTITY_CREATED",
"blueprintIdentifier": "jiraIssue"
}
}
},
{
"identifier": "enrich",
"title": "Query catalog context",
"config": {
"type": "AI",
"userPrompt": "Look up the service related to Jira issue {{ .outputs.trigger.entity.identifier }}. Return the service tier, number of active incidents, and the primary repository URL. If the issue has no service relation, return empty strings and 0 for incidents.",
"tools": ["get_entity", "search_entities"],
"outputSchema": {
"type": "object",
"properties": {
"serviceTier": { "type": "string" },
"activeIncidents": { "type": "number" },
"repoUrl": { "type": "string" }
}
}
}
},
{
"identifier": "writeback",
"title": "Write context to work item",
"config": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "jiraIssue",
"mapping": {
"identifier": "{{ .outputs.trigger.entity.identifier }}",
"properties": {
"serviceTier": "{{ .outputs.enrich.serviceTier }}",
"activeIncidents": "{{ .outputs.enrich.activeIncidents }}",
"repoUrl": "{{ .outputs.enrich.repoUrl }}"
}
}
}
},
{
"identifier": "notify",
"title": "Notify team in Slack",
"icon": "Slack",
"config": {
"type": "WEBHOOK",
"url": "{{ .secrets[\"SLACK_WEBHOOK_URL\"] }}",
"method": "POST",
"body": {
"text": "*New ticket ready for review*\n*Title:* {{ .outputs.trigger.entity.title }}\n*Service tier:* {{ .outputs.enrich.serviceTier | default \"unknown\" }}\n*Active incidents:* {{ .outputs.enrich.activeIncidents }}\n*View in Port:* https://app.port.io/jiraIssue/{{ .outputs.trigger.entity.identifier }}"
}
}
},
{
"identifier": "approve",
"title": "Approve delegation",
"config": {
"type": "INPUT",
"description": "Review the enriched ticket and approve or decline delegation to Cursor.",
"userInputs": {
"properties": {},
"buttons": [
{ "identifier": "approve", "label": "Approve", "variant": "PRIMARY" },
{ "identifier": "decline", "label": "Decline", "variant": "DANGER" }
]
},
"outlets": [
{ "evaluationMethod": "button", "identifier": "approve", "title": "Approved", "numOfResponders": 1 },
{ "evaluationMethod": "button", "identifier": "decline", "title": "Declined", "numOfResponders": 1 }
]
}
},
{
"identifier": "delegate",
"title": "Create Cursor cloud agent",
"config": {
"type": "INTEGRATION_ACTION",
"installationId": "<your-cursor-cloud-agents-installation-id>",
"integrationProvider": "cursor-cloud-agents",
"integrationInvocationType": "create_agent",
"integrationActionExecutionProperties": {
"apiVersion": "v0",
"reportCompletion": true,
"prompt": "Implement the following ticket:\n\nTitle: {{ .outputs.trigger.entity.title }}\nDescription: {{ .outputs.trigger.entity.properties.description }}\nService tier: {{ .outputs.enrich.serviceTier }}\n\nThis is a {{ .outputs.enrich.serviceTier }} service. Make targeted, safe changes. Open a pull request when complete.",
"repository": "{{ .outputs.enrich.repoUrl }}",
"ref": "main",
"config": {
"target": { "autoCreatePr": true }
}
}
}
},
{
"identifier": "update-status",
"title": "Update work item with PR link",
"icon": "GitPullRequest",
"config": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "jiraIssue",
"mapping": {
"identifier": "{{ .outputs.trigger.entity.identifier }}",
"properties": {
"aiReadinessReason": "Delegated to Cursor agent. PR: {{ .outputs.delegate.target.prUrl }}"
}
}
}
}
],
"connections": [
{ "sourceIdentifier": "trigger", "targetIdentifier": "enrich" },
{ "sourceIdentifier": "enrich", "targetIdentifier": "writeback" },
{ "sourceIdentifier": "writeback", "targetIdentifier": "notify" },
{ "sourceIdentifier": "notify", "targetIdentifier": "approve" },
{ "sourceIdentifier": "approve", "targetIdentifier": "delegate", "sourceOutletIdentifier": "approve" },
{ "sourceIdentifier": "delegate", "targetIdentifier": "update-status" }
]
}
- Click Save and then Publish.
Add secrets
- Go to Settings > Secrets in Port.
- Create a secret named
SLACK_WEBHOOK_URLwith your Slack incoming webhook URL. - Install the Cursor Cloud Agents integration if you have not already, and use its installation ID in the delegate node.
Once published, the workflow fires automatically whenever a Jira issue is created or synced into Port. It pauses at the approval node until someone responds.
Use Port's workflow test mode to run the workflow against an existing Jira issue before enabling it on all new tickets.
By default, any Port user with workflow run access can respond to the approval node. To restrict it to specific people, add a responders field to the approve node config:
"responders": {
"users": ["engineer@yourorg.com"]
}
Port notifies those users by email when the node is reached. They open the run in Port and click Approve or Decline.
- Create or sync a Jira issue in Port with a
servicerelation set. The workflow fires automatically. - Open the work item in Port. After the enrich step completes, you should see
serviceTier,activeIncidents, andrepoUrlpopulated. - Check your Slack channel for the notification.
- Review the AI readiness scorecard on the work item. If all three rules pass, the scorecard shows Bronze.
- Go to the workflow run in Port. The run is paused at the Approve delegation node. Click Provide inputs and then Approve.
- The Cursor agent launches on the linked repository and opens a pull request. The
aiReadinessReasonproperty updates with the PR link.
Go to the workflows page, open the ATR: Triage and build workflow, and use the test tab to run it against an existing entity.
What you built
A ticket arrives in Port with a title and description. One workflow handles everything: it pulls service tier, incidents, and repo from the catalog, writes them back to the work item, and posts a Slack notification. The workflow then pauses and waits. A human reviews the enriched ticket, checks the AI readiness scorecard, and clicks Approve. Cursor picks it up, opens a PR, and the link comes back to the work item.
That's the core ATR loop.
What's next
The workflow you built covers the Triage and Build stages. The next steps extend the same pattern to the full SDLC:
- Add more catalog context - connect GitHub or GitLab to populate repo data automatically and enrich your services with dependencies, recent deploys, and ownership history.
- Make the scorecard smarter - add rules for blast radius, priority, and service ownership completeness as your catalog grows.
- Automate the delegation decision - once you trust the scorecard, add a workflow condition that delegates automatically when AI readiness passes, keeping humans in the loop only for failed or borderline tickets.
- Add code review enrichment - use the PR Enricher agent to surface catalog context on the PR Cursor creates.
- Gate the release - add a blast radius check and deployment gates before the PR reaches production.
For the full picture of each stage, see the ATR solution overview.