Automatically set relations between entities with automation
Send this guide to your coding agent.
Prerequisite: Install Port MCP
Open plan mode. Implement this Port guide in my org via MCP: https://docs.port.io/guides/all/automatically-set-relations-between-entities-with-automation/ Goal: get the guide's core flow working end-to-end in my org; adapting it to fit my existing setup takes priority over matching the guide 1:1. Plan: 1. Confirm MCP is connected, in the right org, with sufficient permissions. 2. Diff the guide's data model (blueprints, properties, relations, actions, agents, automations, integrations, secrets) against mine. 3. Propose adaptations for gaps, reusing existing blueprints/relations over guide-named duplicates. 4. Flag what needs a UI click, credential, or secret from me, testing MCP capability empirically before ruling anything out. 5. Stop on any blocker and give me options. Approving this plan authorizes the writes it lists; pause only for writes beyond what's listed. Build: - Extend blueprint schema additively when upserting; don't remove or overwrite existing properties, and treat type conflicts as a blocker, not an auto-fix. - List any mock data in the plan, minimal and labeled mock; once approved, seed it without re-asking, and tell me what you seeded. - For anything the guide writes downstream (e.g. a webhook target), use a real entity, not a mock. - For pages/widgets, use the real page identifier from the app URL, not a guessed slug. - When you hit a UI step confirmed (not assumed) unsupported via MCP, pause, give exact clicks, then resume via MCP. - Validate and give links after each meaningful step (only a tool-returned URL, no guessed paths); don't proceed if the last run wasn't a success. Done: - Confirm the guide's expected output exists and runs in Port. - Summarize adaptations, seeded data, what was mocked or skipped, remaining UI steps, and how to verify.
This guide demonstrates how to set up an automation in Port that automatically creates relations between entities. We will use a specific example of automatically linking new service entities to their owning teams based on GitHub repository metadata.
Once implemented, when a new service entity is created with a repository relation, the automation will automatically link it to the appropriate team based on the GitHub organization name.
Common use cases
- Team ownership: Automatically link services to their owning team based on repository metadata
- Environment mapping: Connect deployments to their target environments based on branch names or tags
- Service dependencies: Link services to their dependencies based on configuration files or API calls
- Infrastructure relationships: Connect cloud resources to the services that consume them based on tags or naming conventions
Prerequisites
This guide assumes the following:
-
You have a Port account and have completed the onboarding process.
-
Port's GitHub integration is installed in your account:
Port's GitHub Ocean integration is installed in your account.
-
You have setup automatic discovery between the
serviceandrepositoryblueprints. -
Permissions to create and edit Port automations.
Set up data model
After completing the onboarding process, you should have both a service blueprint and a team blueprint.
If you have installed Port's GitHub Ocean integration, you should have a repository blueprint and
your service blueprint should have a repository relation. Now we need to add a relation between the service and the team blueprints.
Add team relation to the service blueprint
-
Go to your Builder page.
-
Find and click on the
Serviceblueprint. -
Click on
New relation. -
Fill out the form:
- Title:
Owning Team - Identifier:
owning_team - Target Blueprint:
Team - Limit:
1 entity - Required: False
- Title:
-
Click
Createto add the relation.
Set up the automation
Now let's create an automation that automatically sets the team relation when a service is created.
-
Go to the Automations page in Port.
-
Click on
+ Automationto create a new automation. -
Copy and paste the following JSON structure for your automation:
Auto-assign service owner (Click to expand)
{"identifier": "auto_assign_service_owner","title": "Auto-assign Service Owner","description": "Automatically assigns services to teams based on repository owner","trigger": {"type": "automation","event": {"type": "ENTITY_CREATED","blueprintIdentifier": "service"},"condition": {"type": "JQ","expressions": [".diff.after.relations.repository != null"],"combinator": "and"}},"invocationMethod": {"type": "UPSERT_ENTITY","blueprintIdentifier": "service","mapping": {"identifier": "{{ .event.diff.after.identifier }}","title": "{{ .event.diff.after.title }}","properties": {},"relations": {"repository": "{{ .event.diff.after.relations.repository }}","owning_team": "{{ .event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\") }}"}}},"publish": true} -
Click
Saveto create the automation.
How the automation works
When a service entity is created with a repository relation, the automation will:
-
Extract the GitHub organization from the repository identifier (e.g.,
myorganization/acme-corp_my-service→acme_corp) -
Automatically set the
owning_teamrelation toacme_corp(assuming you have a team with that identifier) -
The service is now linked to its owning team
The automation uses this JQ expression to extract the team name:
.event.diff.after.relations.repository | split("_") | .[0] | split("/") | .[1] | gsub("-"; "_")
This expression works as follows:
-
split("_")splitsmyorganization/acme-corp_my-service→["myorganization/acme-corp", "my-service"] -
.[0]takes the first part →"myorganization/acme-corp" -
split("/")splits that →["myorganization", "acme-corp"] -
.[1]takes the second part →"acme-corp" -
gsub("-"; "_")converts hyphens to underscores →"acme_corp"
This automation assumes your team identifiers use underscores and match your GitHub organization names, and that repository identifiers follow the pattern username/organization_repository-name. If your naming convention is different, you'll need to adjust the JQ expression in the owning_team mapping accordingly.
Customizations
You can customize this automation to fit your specific naming conventions:
Different repository patterns
-
If your repository naming convention uses dashes instead of underscores:
"owning_team": "{{ .event.diff.after.relations.repository | split(\"-\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\") }}" -
If your GitHub organization name preserves hyphens (no conversion to underscores):
"owning_team": "{{ .event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] }}" -
If your team names have regional suffixes (e.g.,
acme-corp-region→acme_corp_region):"owning_team": "{{ .event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\") }}" -
If your team names have role-based suffixes (e.g.,
rnd-taskforce→rnd_taskforce):"owning_team": "{{ .event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\") }}" -
If your team names are complex with multiple segments (e.g.,
rnd-developer-team-product→rnd_developer_team_product):"owning_team": "{{ .event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\") }}"
Team suffix patterns
If your team identifiers include a suffix like "_team":
"owning_team": "{{ (.event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\")) + \"_team\" }}"
Additional conditions
To ensure the automation only runs when the service doesn't already have an owner:
"condition": {
"type": "JQ",
"expressions": [
".diff.after.relations.repository != null",
".diff.before.relations.owning_team == null"
],
"combinator": "and"
}
Additional examples
Here are more examples of automations that automatically set relations between entities:
Environment-based deployment relationships
Link deployments to environments based on branch names (Click to expand)
{
"identifier": "link_deployment_to_environment",
"title": "Link Deployment to Environment",
"description": "Automatically links deployments to environments based on branch name",
"trigger": {
"type": "automation",
"event": {
"type": "ENTITY_CREATED",
"blueprintIdentifier": "deployment"
},
"condition": {
"type": "JQ",
"expressions": [
".diff.after.properties.branch != null"
],
"combinator": "and"
}
},
"invocationMethod": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "deployment",
"mapping": {
"identifier": "{{ .event.diff.after.identifier }}",
"title": "{{ .event.diff.after.title }}",
"properties": {},
"relations": {
"environment": "{{ if (.event.diff.after.properties.branch | test(\"^main$|^master$\")) then \"production\" elif (.event.diff.after.properties.branch | test(\"^develop$|^dev$\")) then \"development\" elif (.event.diff.after.properties.branch | test(\"^staging$|^stage$\")) then \"staging\" else \"development\" end }}"
}
}
},
"publish": true
}
Cloud resource to service mapping
Link AWS resources to services based on tags (Click to expand)
{
"identifier": "map_aws_resources_to_services",
"title": "Map AWS Resources to Services",
"description": "Links AWS resources to services based on the 'service' tag",
"trigger": {
"type": "automation",
"event": {
"type": "ENTITY_CREATED",
"blueprintIdentifier": "awsResource"
},
"condition": {
"type": "JQ",
"expressions": [
".diff.after.properties.tags != null",
".diff.after.properties.tags | has(\"service\")"
],
"combinator": "and"
}
},
"invocationMethod": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "awsResource",
"mapping": {
"identifier": "{{ .event.diff.after.identifier }}",
"title": "{{ .event.diff.after.title }}",
"properties": {},
"relations": {
"consumingService": "{{ .event.diff.after.properties.tags.service }}"
}
}
},
"publish": true
}
Conclusion
By leveraging Port's automation capabilities, you can create a self-maintaining context lake that automatically establishes relationships between entities. This approach saves time, ensures consistency, reduces errors, and scales effortlessly to handle hundreds or thousands of entities automatically.
Start with simple property-based mappings and gradually implement more sophisticated logic as your needs grow.