Trigger GitHub Copilot from Port
This guide demonstrates how to set up GitHub Copilot triggers from Port, enabling AI-powered coding assistance in your development workflow.
By leveraging AI coding agents like Copilot, you can significantly reduce manual coding tasks and enhance productivity, allowing developers to focus on more complex problem-solving. You will learn how to create self-service actions that can assign issues to GitHub Copilot and configure the necessary GitHub workflows to handle the assignment process.

Common use casesโ
- Assign issues to Copilot for automated code generation and assistance
- Integrate Copilot with Port workflows for seamless AI-powered development
Prerequisitesโ
This guide assumes the following:
- You have a Port account and have completed the onboarding process.
- Port's GitHub app is installed in your account.
- You have access to create and configure AI agents in Port.
- GitHub Copilot is enabled in your repository.
Set up data modelโ
We need to create a GitHub issue blueprint to support our Copilot workflow. This blueprint will be used to track issues that can be assigned to Copilot.
Create GitHub issue blueprintโ
When installing Port's GitHub app, the pull request and repository blueprints are created by default. However, the GitHub issue blueprint needs to be created manually.
-
Go to the builder page of your portal.
-
Click on
+ Blueprint
. -
Click on the
{...} Edit JSON
button. -
Copy and paste the following JSON configuration:
GitHub issue blueprint (Click to expand)
{
"identifier": "githubIssue",
"title": "Issue",
"icon": "Github",
"schema": {
"properties": {
"creator": {
"title": "Creator",
"type": "string"
},
"assignees": {
"title": "Assignees",
"type": "array"
},
"labels": {
"title": "Labels",
"type": "array"
},
"status": {
"title": "Status",
"type": "string",
"enum": [
"open",
"closed"
],
"enumColors": {
"open": "green",
"closed": "purple"
}
},
"createdAt": {
"title": "Created At",
"type": "string",
"format": "date-time"
},
"closedAt": {
"title": "Closed At",
"type": "string",
"format": "date-time"
},
"updatedAt": {
"title": "Updated At",
"type": "string",
"format": "date-time"
},
"description": {
"title": "Description",
"type": "string",
"format": "markdown"
},
"issueNumber": {
"title": "Issue Number",
"type": "number"
},
"link": {
"title": "Link",
"type": "string",
"format": "url"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"repository": {
"target": "githubRepository",
"required": true,
"many": false
}
}
} -
Click
Create
to save the blueprint.
Auto-assign issues to request creatorโ
To ensure that issues created through Port are assigned to the user who initiated the request, follow these steps:
-
Ingest GitHub Users: Ensure GitHub users are imported into Port via the default integration.
-
Create Relations Between Users and GitHub Users: Use the
Onboard user
self-service action to link each Port user to their GitHub username.
This linkage keeps users connected to the issues they create and improves accountability.
Set up self-service actionsโ
We will create self-service actions that can create and assign GitHub issues to Copilot. First, we need to add the necessary secrets to Port.
Add GitHub secretsโ
In your GitHub repository, go to Settings > Secrets and add the following secrets:
PORT_CLIENT_ID
- Port Client ID learn more.PORT_CLIENT_SECRET
- Port Client Secret learn more.PORT_GITHUB_TOKEN
: A GitHub fine-grained personal access token is required. This token must have read and write permissions for the "Issues", "Metadata" and "Pull request" section of your repositories.
Add Port secretsโ
To add these secrets to your portal:
-
Click on the
...
button in the top right corner of your Port application. -
Click on Credentials.
-
Click on the
Secrets
tab. -
Click on
+ Secret
and add the following secret:GITHUB_TOKEN
- A GitHub fine-grained personal access token is required. This token must have read and write permissions for the "Issues", "Metadata" and "Pull request" section of your repositories.
NoteThe
GITHUB_TOKEN
mentioned here is the same token that was created and added as a secret in GitHub in the previous steps.
Create GitHub issue actionโ
-
Go to the self-service page of your portal.
-
Click on
+ New Action
. -
Click on the
{...} Edit JSON
button. -
Copy and paste the following JSON configuration:
Create GitHub issue action (Click to expand)
{
"identifier": "create_github_issue",
"title": "Create GitHub Issue",
"icon": "Github",
"description": "Create a new issue in this GitHub repository",
"trigger": {
"type": "self-service",
"operation": "DAY-2",
"userInputs": {
"properties": {
"title": {
"icon": "DefaultProperty",
"type": "string",
"title": "Issue Title",
"description": "A short description for the task"
},
"labels": {
"items": {
"type": "string"
},
"icon": "DefaultProperty",
"type": "array",
"title": "Issue Labels",
"description": "Labels to add to the issue, following format: [\"label1\",\"label2\"]"
},
"body": {
"title": "Issue Body",
"icon": "DefaultProperty",
"type": "string",
"description": "The actual task expected. Add here additional context like the latest change or related commits/PR, relevant people for this task, and other relevant instructions",
"format": "markdown"
}
},
"required": [
"title",
"body"
],
"order": [
"title",
"body",
"labels"
]
},
"blueprintIdentifier": "githubRepository"
},
"invocationMethod": {
"type": "WEBHOOK",
"url": "https://api.github.com/repos/{{ .entity.identifier }}/issues",
"agent": false,
"synchronized": true,
"method": "POST",
"headers": {
"Accept": "application/vnd.github+json",
"Authorization": "Bearer {{ .secrets.GITHUB_TOKEN }}",
"X-GitHub-Api-Version": "2022-11-28",
"Content-Type": "application/json"
},
"body": {
"title": "{{ .inputs.title }}",
"body": "{{ .inputs.body }}",
"labels": "{{ .inputs.labels }}"
}
},
"requiredApproval": false
} -
Click
Save
to create the action.
Assign issue to Copilot actionโ
-
Go to the self-service page of your portal.
-
Click on
+ New Action
. -
Click on the
{...} Edit JSON
button. -
Copy and paste the following JSON configuration:
Assign to Copilot action (Click to expand)
Modification RequiredMake sure to replace
<GITHUB_ORG>
and<GITHUB_REPO>
with your GitHub organization and repository names respectively.{
"identifier": "assign_to_copilot",
"title": "Assign to Copilot",
"icon": "Github",
"description": "Assign this issue to GitHub Copilot coding agent",
"trigger": {
"type": "self-service",
"operation": "DAY-2",
"userInputs": {
"properties": {
"triggered_by": {
"title": "Triggered By",
"icon": "DefaultProperty",
"type": "string"
}
},
"required": [],
"order": [
"triggered_by"
]
},
"blueprintIdentifier": "githubIssue"
},
"invocationMethod": {
"type": "GITHUB",
"org": "<GITHUB-ORG>",
"repo": "<GITHUB-REPO>",
"workflow": "assign_to_copilot.yml",
"workflowInputs": {
"issue_number": "{{ .entity.properties.issueNumber }}",
"port_run_id": "{{ .run.id }}",
"repository_owner": "{{ .entity.relations.repository | split(\"/\") | .[0] }}",
"repository_name": "{{ .entity.relations.repository | split(\"/\") | .[1] }}",
"trigger_user_email": "{{ .inputs.triggered_by }}"
},
"reportWorkflowStatus": true
},
"requiredApproval": false
} -
Click
Save
to create the action.
Add GitHub workflowโ
Create the file .github/workflows/assign_to_copilot.yml
in the .github/workflows
folder of your repository.
This workflow will check if Copilot is enabled for the repository and return its unique ID. It also handles the assignment of issues to Copilot and the triggering author, and includes progress reporting back to Port.
GitHub workflow for Copilot assignment (Click to expand)
name: Assign Issue to Copilot
on:
workflow_dispatch:
inputs:
issue_number:
description: 'The number of the issue to assign to Copilot'
required: true
repository_owner:
description: 'Repository owner (org or user)'
required: true
type: string
repository_name:
description: 'Repository name'
required: true
type: string
port_run_id:
description: 'Port run ID, used for reporting back to Port'
required: false
issue_context_to_comment:
description: 'Context to add to the issue comment'
required: false
type: string
trigger_user_email:
description: 'Email of the triggering user'
required: false
type: string
default: ''
jobs:
assign_to_copilot:
runs-on: ubuntu-latest
steps:
- name: Validate inputs
run: |
echo "Target repository: ${{ inputs.repository_owner }}/${{ inputs.repository_name }}"
echo "Issue number: ${{ inputs.issue_number }}"
- name: Report progress to Port - Starting
if: ${{ inputs.port_run_id != '' }}
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
baseUrl: https://api.getport.io
operation: PATCH_RUN
runId: ${{ inputs.port_run_id }}
logMessage: "Workflow started for issue #${{ inputs.issue_number }} in ${{ inputs.repository_owner }}/${{ inputs.repository_name }}"
- name: Check if Copilot is enabled and get Bot ID
id: get_copilot_id
run: |
response=$(gh api graphql -f query='
query {
repository(owner: "${{ inputs.repository_owner }}", name: "${{ inputs.repository_name }}") {
suggestedActors(capabilities: [CAN_BE_ASSIGNED], first: 100) {
nodes {
login
__typename
... on Bot {
id
}
... on User {
id
}
}
}
}
}
')
# Extract Copilot bot ID
copilot_id=$(echo "$response" | jq -r '.data.repository.suggestedActors.nodes[] | select(.login == "copilot-swe-agent") | .id')
if [ -z "$copilot_id" ]; then
echo "Error: Copilot coding agent is not enabled in repository ${{ inputs.repository_owner }}/${{ inputs.repository_name }}"
exit 1
fi
echo "copilot_id=$copilot_id" >> $GITHUB_OUTPUT
echo "Found Copilot bot with ID: $copilot_id"
env:
# Use PAT instead of GITHUB_TOKEN for cross-org access
GH_TOKEN: ${{ secrets.PORT_GITHUB_TOKEN }}
- name: Report progress to Port - Found Copilot Bot
if: ${{ inputs.port_run_id != '' }}
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
baseUrl: https://api.getport.io
operation: PATCH_RUN
runId: ${{ inputs.port_run_id }}
logMessage: "Found Copilot bot with ID: ${{ steps.get_copilot_id.outputs.copilot_id }}"
- name: Get Issue ID
id: get_issue_id
run: |
response=$(gh api graphql -f query='
query {
repository(owner: "${{ inputs.repository_owner }}", name: "${{ inputs.repository_name }}") {
issue(number: ${{ inputs.issue_number }}) {
id
title
state
}
}
}
')
issue_id=$(echo "$response" | jq -r '.data.repository.issue.id')
issue_title=$(echo "$response" | jq -r '.data.repository.issue.title')
issue_state=$(echo "$response" | jq -r '.data.repository.issue.state')
if [ -z "$issue_id" ] || [ "$issue_id" = "null" ]; then
echo "Error: Issue #${{ inputs.issue_number }} not found in ${{ inputs.repository_owner }}/${{ inputs.repository_name }}"
exit 1
fi
if [ "$issue_state" = "CLOSED" ]; then
echo "Warning: Issue #${{ inputs.issue_number }} is closed"
fi
echo "issue_id=$issue_id" >> $GITHUB_OUTPUT
echo "issue_title=$issue_title" >> $GITHUB_OUTPUT
echo "Found issue: $issue_title (ID: $issue_id)"
env:
GH_TOKEN: ${{ secrets.PORT_GITHUB_TOKEN }}
- name: Report progress to Port - Found Issue
if: ${{ inputs.port_run_id != '' }}
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
baseUrl: https://api.getport.io
operation: PATCH_RUN
runId: ${{ inputs.port_run_id }}
logMessage: "Found issue '${{ steps.get_issue_id.outputs.issue_title }}' (ID: ${{ steps.get_issue_id.outputs.issue_id }})"
- name: Comment on issue before assignment
id: comment_on_issue
if: ${{ inputs.issue_context_to_comment != '' }}
run: |
gh issue comment ${{ inputs.issue_number }} \
--repo "${{ inputs.repository_owner }}/${{ inputs.repository_name }}" \
--body "$ISSUE_CONTEXT"
env:
GH_TOKEN: ${{ secrets.PORT_GITHUB_TOKEN }}
ISSUE_CONTEXT: ${{ inputs.issue_context_to_comment }}
- name: Report progress to Port - Commented on issue
if: ${{ inputs.port_run_id != '' }}
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
baseUrl: https://api.getport.io
operation: PATCH_RUN
runId: ${{ inputs.port_run_id }}
logMessage: "Added initial comment to issue #${{ inputs.issue_number }}."
- name: Get Trigger User from Port
id: port_user_lookup
if: ${{ inputs.trigger_user_email != '' && inputs.trigger_user_email != 'null' }}
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
baseUrl: https://api.getport.io
operation: GET
identifier: ${{ inputs.trigger_user_email }}
blueprint: _user
- name: Extract GitHub Username
id: extract_username
if: ${{ inputs.trigger_user_email != '' && inputs.trigger_user_email != 'null' }}
run: |
username=$(echo '${{ steps.port_user_lookup.outputs.entity }}' | jq -r '.entity.properties.git_hub_username // .properties.git_hub_username')
if [ "$username" = "null" ] || [ -z "$username" ]; then
echo "No GitHub username found for ${{ inputs.trigger_user_email }}"
echo "github_username=" >> $GITHUB_OUTPUT
else
echo "Found GitHub username: $username"
echo "github_username=$username" >> $GITHUB_OUTPUT
fi
- name: Assign issue to Copilot
id: assign_issue
run: |
actor_ids="[\"${{ steps.get_copilot_id.outputs.copilot_id }}\"]"
# Only try to add the initiator if the extract_username step actually ran
if [ "${{ inputs.trigger_user_email }}" != "null" ] && [ -n "${{ steps.extract_username.outputs.github_username }}" ]; then
user_id=$(gh api graphql -f query="query { user(login: \"${{ steps.extract_username.outputs.github_username }}\") { id }}" | jq -r '.data.user.id')
if [ -n "$user_id" ] && [ "$user_id" != "null" ]; then
echo "Found user ID for initiator: $user_id"
actor_ids="[\"${{ steps.get_copilot_id.outputs.copilot_id }}\", \"$user_id\"]"
else
echo "No valid GitHub user ID found for initiator"
fi
else
echo "Skipping initiator assignment (no trigger_user_email or username)"
fi
response=$(gh api graphql -f query="
mutation {
replaceActorsForAssignable(input: {
assignableId: \"${{ steps.get_issue_id.outputs.issue_id }}\",
actorIds: $actor_ids
}) {
assignable {
... on Issue {
id
title
assignees(first: 10) {
nodes {
login
}
}
}
}
}
}
")
assignees=$(echo "$response" | jq -r '.data.replaceActorsForAssignable.assignable.assignees.nodes[].login' 2>/dev/null)
if echo "$assignees" | grep -q "Copilot"; then
echo "โ
Successfully assigned issue to Copilot"
else
echo "โ Failed to assign issue to Copilot"
exit 1
fi
env:
GH_TOKEN: ${{ secrets.PORT_GITHUB_TOKEN }}
- name: Report back to Port (if triggered from Port)
if: ${{ inputs.port_run_id != '' }}
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
baseUrl: https://api.getport.io
operation: PATCH_RUN
runId: ${{ inputs.port_run_id }}
status: "SUCCESS"
logMessage: |
โ
Workflow completed successfully.
Assigned issue #${{ inputs.issue_number }} to GitHub Copilot.
Repository: ${{ inputs.repository_owner }}/${{ inputs.repository_name }}
Issue: ${{ steps.get_issue_id.outputs.issue_title }}
Set up automationsโ
We will create an automation that automatically assigns GitHub issues to Copilot when they have the "auto_assign" label.
Automation to assign to Copilotโ
This automation ensures that when a GitHub issue has the auto_assign
label, it is automatically assigned to the Copilot agent. This streamlines the workflow by reducing manual intervention and ensuring that tasks are promptly assigned to the appropriate coding agent.
-
Go to the automations page of your portal.
-
Click on
+ Automation
. -
Copy and paste the following JSON schema:
Assign to Copilot automation (Click to expand)
{
"identifier": "assign_to_copilot_automation",
"title": "Assign to Copilot",
"description": "When GitHub issue has auto_assign label, assign to Copilot",
"icon": "GithubCopilot",
"trigger": {
"type": "automation",
"event": {
"type": "ENTITY_UPDATED",
"blueprintIdentifier": "githubIssue"
},
"condition": {
"type": "JQ",
"expressions": [
".diff.after.properties.labels | index(\"auto_assign\") != null",
".diff.after.properties.assignees | index(\"Copilot\") == null"
],
"combinator": "and"
}
},
"invocationMethod": {
"type": "WEBHOOK",
"url": "https://api.getport.io/v1/actions/assign_to_copilot/runs",
"agent": false,
"synchronized": true,
"method": "POST",
"headers": {
"RUN_ID": "{{ .run.id }}",
"Content-Type": "application/json"
},
"body": {
"entity": "{{ .event.diff.after.identifier }}",
"properties": {
"triggered_by": "{{ .trigger.by.user.email }}"
}
}
},
"publish": true
} -
Click
Create
to save the automation.
Test the workflowโ
Now let us test the complete workflow to ensure everything works correctly.
Run the self-service actionโ
- Run the self-service action to create a new GitHub issue.
- Make sure to add the
auto_assign
label to the issue. - Go to the issue in GitHub and verify that Copilot is assigned.
- Check that a pull request (PR) is opened for the issue.

Related guidesโ
- Set up the Task Manager AI agent - Create an AI agent to manage and prioritize development tasks