Set up a service production readiness scorecard
Scorecards let you define maturity levels for your services, giving platform engineers and R&D managers a clear view of which services meet your organization's readiness standards and which need attention. This guide demonstrates how to set up a service production readiness scorecard using data from GitHub, GitLab, or Azure DevOps integrations, evaluating services against progressive maturity levels: Bronze, Silver, and Gold.
Common use cases
- Define clear, enforceable standards for service ownership and documentation.
- Identify unmaintained or undocumented services before they become incidents.
- Gate deployments or trigger alerts when services drop below a minimum readiness level.
- Give developers a self-service view of exactly what their service is missing.
Prerequisites
This guide assumes the following:
- You have a Port account and have completed the onboarding process.
- You have installed a GitHub, GitLab, or Azure DevOps integration.
- You have verified that the
serviceblueprint has values for the repository metadata used in this scorecard (url,readme,gitignore,language,pr_template,visibility, andcodeowners) in your environment.
All core rules in this scorecard use repository metadata that your git integration can supply. Depending on your provider and mapping, you might need to map some properties to service first. The extend with additional integrations section describes how to enrich the scorecard with data from other tools once you have them installed.
Maturity levels
Port scorecards use four fixed maturity levels. An entity must pass all rules at a given level (and all levels below it) to achieve that level.
| Level | Order | Description |
|---|---|---|
| Basic | 0 (default) | Entity exists but meets no scorecard criteria |
| Bronze | 1 | Foundational hygiene: ownership and documentation present |
| Silver | 2 | Good practices: actively maintained, metadata complete |
| Gold | 3 | Excellence: strict governance and high activity |
Create the scorecard
Blueprint: Service
All rules in the core scorecard use repository metadata on the service blueprint that should be populated from your GitHub, GitLab, or Azure DevOps integration mapping.
| # | Rule | Level | Property | Condition | Requires |
|---|---|---|---|---|---|
| 1 | Has repository URL | Bronze | url | is not empty | Git integration |
| 2 | Has README | Bronze | readme | is not empty | Git integration |
| 3 | Has team assigned | Bronze | team (relation) | is not empty | Git integration |
| 4 | Has .gitignore | Bronze | gitignore | is not empty | Git integration |
| 5 | Has language defined | Bronze | language | is not empty | Git integration |
| 6 | Has PR template | Silver | pr_template | is not empty | Git integration |
| 7 | Private repository | Silver | visibility | = "private" | Git integration |
| 8 | Has criticality defined | Silver | criticality | is not empty | Git integration |
| 9 | Active repo (last 30 days) | Silver | days_since_last_push | < 30 | Git integration |
| 10 | Has CODEOWNERS | Gold | codeowners | is not empty | Git integration |
| 11 | Active repo (last 7 days) | Gold | days_since_last_push | < 7 | Git integration |
Steps
-
Go to the Builder page of your portal.
-
Search for the Service blueprint and select it.
-
Click on the Scorecards tab.
-
If the
production_readinessscorecard does not exist, click + New Scorecard. If it already exists, open it instead. -
Click on the
{...} Edit JSONbutton in the top right corner. -
Paste the following JSON configuration:
Service Production Readiness scorecard (click to expand)
{
"identifier": "production_readiness",
"title": "Service Production Readiness",
"levels": [
{
"color": "paleBlue",
"title": "Basic"
},
{
"color": "bronze",
"title": "Bronze"
},
{
"color": "silver",
"title": "Silver"
},
{
"color": "gold",
"title": "Gold"
}
],
"rules": [
{
"identifier": "has_url",
"title": "Has repository URL",
"description": "Service has a repository URL set, confirming it is linked to source control.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "isNotEmpty",
"property": "url"
}
]
}
},
{
"identifier": "has_readme",
"title": "Has README",
"description": "Service has a README file in the repository, providing basic documentation.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "isNotEmpty",
"property": "readme"
}
]
}
},
{
"identifier": "has_team",
"title": "Has team assigned",
"description": "Service has a team relation set, ensuring clear ownership.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "isNotEmpty",
"relation": "team"
}
]
}
},
{
"identifier": "has_gitignore",
"title": "Has .gitignore",
"description": "Repository has a .gitignore file, preventing accidental commits of build artifacts or secrets.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "isNotEmpty",
"property": "gitignore"
}
]
}
},
{
"identifier": "has_language",
"title": "Has language defined",
"description": "Repository has a detected primary language, useful for routing and tooling decisions.",
"level": "Bronze",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "isNotEmpty",
"property": "language"
}
]
}
},
{
"identifier": "has_pr_template",
"title": "Has PR template",
"description": "Repository includes a pull request template to guide contributors.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "isNotEmpty",
"property": "pr_template"
}
]
}
},
{
"identifier": "private_visibility",
"title": "Private repository",
"description": "Repository visibility is private, reducing exposure of internal code.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "visibility",
"value": "private"
}
]
}
},
{
"identifier": "has_criticality",
"title": "Has criticality defined",
"description": "Service has a criticality level set, enabling incident routing and risk prioritization.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "isNotEmpty",
"property": "criticality"
}
]
}
},
{
"identifier": "active_repo_30d",
"title": "Active repo (last 30 days)",
"description": "Repository has been pushed to within the last 30 days, indicating it is actively maintained.",
"level": "Silver",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "days_since_last_push",
"value": 30
}
]
}
},
{
"identifier": "has_codeowners",
"title": "Has CODEOWNERS",
"description": "Repository has a CODEOWNERS file, enforcing mandatory code review by designated owners.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "isNotEmpty",
"property": "codeowners"
}
]
}
},
{
"identifier": "active_repo_7d",
"title": "Active repo (last 7 days)",
"description": "Repository has been pushed to within the last 7 days — elite activity level.",
"level": "Gold",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "<",
"property": "days_since_last_push",
"value": 7
}
]
}
}
]
} -
Click Save to create the scorecard.
days_since_last_push is a calculated property on service and requires last_push to be populated. Properties like codeowners, pr_template, gitignore, and visibility come from your git integration mapping. criticality is typically set by your team as service metadata. Newly ingested services might show Basic until the integration completes its first sync and your mappings populate these fields.
Extend with additional integrations
The core scorecard covers everything a git integration provides. Once you install other tools, you can append additional rules to the rules array to capture signals from those systems. Some examples:
- PagerDuty: check that each service has an active on-call assignment (
pagerduty_oncallis not empty). Useful as a Gold-level requirement for production services. - SonarQube: enforce minimum code coverage, cap the number of open code smells, or require a passing security rating.
- Snyk: gate Silver or Gold on having zero critical vulnerabilities or a clean dependency audit.
- Datadog / New Relic: require that services have APM monitoring configured as a Gold-level requirement.
- CI coverage by provider: optionally add a CI rule using your provider-specific property (for example,
workflow_countfor GitHub orpipeline_countfor GitLab) after you verify the property exists onservice.
To add a rule, go to the Service blueprint in the Builder, open the Scorecards tab, click Service Production Readiness → Edit JSON, and append the new rule object to the rules array.
Visualize scorecard results
Once the scorecard is in place, create a dashboard to monitor production readiness across all services.
Create the dashboard
- Navigate to your software catalog.
- Click on the
+button in the left sidebar. - Select New folder.
- Name the folder Engineering Intelligence and click Create.
- Inside the Engineering Intelligence folder, click
+again. - Select New dashboard.
- Name the dashboard Service Production Readiness Scorecards and click Create.
Add widgets
You can populate the dashboard using either an API script or by manually creating each widget through the UI.
- API script
- Manual setup
The fastest way to set up the dashboard is by using Port's API to create all widgets at once.
Get your Port API token
-
In your Port portal, click on your profile picture in the top right corner.
-
Select Credentials.
-
Click Generate API token.
-
Copy the generated token and store it as an environment variable:
export PORT_ACCESS_TOKEN="YOUR_GENERATED_TOKEN"EU regionIf your portal is hosted in the EU region, replace
api.port.iowithapi.port-eu.ioin the dashboard creation command below.
Create the dashboard with widgets
Save the following JSON to a file named pr_scorecards_dashboard.json:Dashboard JSON payload (click to expand)
{
"identifier": "production_readiness_scorecards",
"title": "Service Production Readiness Scorecards",
"icon": "Shield",
"type": "dashboard",
"parent": "engineering_intelligence",
"widgets": [
{
"id": "prScorecardsDashboardWidget",
"type": "dashboard-widget",
"layout": [
{
"height": 400,
"columns": [
{"id": "serviceLevelDistribution", "size": 6},
{"id": "servicesBelowBronze", "size": 6}
]
},
{
"height": 400,
"columns": [
{"id": "serviceReadinessTable", "size": 12}
]
}
],
"widgets": [
{
"id": "serviceLevelDistribution",
"type": "entities-pie-chart",
"title": "Service Production Readiness Level Distribution",
"icon": "Pie",
"description": "Distribution of production readiness scorecard levels across services",
"blueprint": "service",
"property": "scorecard#production_readiness",
"dataset": {
"combinator": "and",
"rules": []
}
},
{
"id": "servicesBelowBronze",
"type": "entities-number-chart",
"title": "Services Below Bronze",
"icon": "Alert",
"description": "Number of services that have not reached Bronze readiness level",
"blueprint": "service",
"chartType": "countEntities",
"calculationBy": "entities",
"func": "count",
"unit": "none",
"dataset": {
"combinator": "and",
"rules": [
{
"operator": "=",
"property": "scorecard#production_readiness",
"value": "Basic"
}
]
}
},
{
"id": "serviceReadinessTable",
"type": "table-entities-explorer",
"displayMode": "widget",
"title": "Service Production Readiness Overview",
"icon": "Table",
"description": "Services with their production readiness scorecard level and key hygiene indicators",
"blueprint": "service",
"dataset": {"combinator": "and", "rules": []},
"excludedFields": [],
"blueprintConfig": {
"service": {
"groupSettings": {"groupBy": ["team"]},
"propertiesSettings": {
"order": ["$title", "team", "scorecard-property#production_readiness", "readme", "codeowners", "criticality", "visibility", "days_since_last_push", "language"],
"shown": ["$title", "team", "scorecard-property#production_readiness", "readme", "codeowners", "criticality", "visibility", "days_since_last_push", "language"]
},
"filterSettings": {"filterBy": {"combinator": "and", "rules": []}},
"sortSettings": {"sortBy": []}
}
}
}
]
}
]
}
Then run the following command to create the dashboard with all widgets:
curl -s -X POST "https://api.port.io/v1/pages" \
-H "Authorization: Bearer $PORT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d @pr_scorecards_dashboard.json | python3 -m json.tool
The script assumes an engineering_intelligence folder already exists in your catalog. If you haven't created it yet, follow steps 1–4 in the Create the dashboard section first.
Scorecard level distribution
Production readiness level distribution pie chart (click to expand)
- Click
+ Widgetand select Pie Chart. - Title:
Service Production Readiness Level Distribution. - Description:
Distribution of production readiness scorecard levels across services. - Choose Service as the Blueprint.
- Select
Service Production Readinessfrom the Breakdown by property dropdown (this is thescorecard#production_readinessproperty). - Click Save.
Attention metrics
Services below bronze number chart (click to expand)
-
Click
+ Widgetand select Number Chart. -
Title:
Services Below Bronze. -
Description:
Number of services that have not reached Bronze readiness level. -
Select
Count EntitiesChart type and choose Service as the Blueprint. -
Add this JSON to the Additional filters editor:
{
"combinator": "and",
"rules": [
{
"operator": "=",
"property": "scorecard#production_readiness",
"value": "Basic"
}
]
} -
Click Save.
Scorecard table
Service production readiness overview table (click to expand)
- Click
+ Widgetand select Table. - Title:
Service Production Readiness Overview. - Description:
Services with their production readiness scorecard level and key hygiene indicators. - Choose Service as the Blueprint.
- Group by Team.
- Configure the displayed columns to show: title, team, production readiness level, README, CODEOWNERS, criticality, visibility, days since last push, and language.
- Click Save.
Next steps
- Add automations: Use Port automations to notify teams via Slack when their service drops below Bronze, or create Jira tickets for services missing ownership.
- Customize thresholds: The
active_repo_30dandactive_repo_7drules usedays_since_last_push. Adjust these values to match your team's release cadence. - Combine with delivery metrics: Combine this scorecard with the Measure PR delivery metrics guide to get both hygiene and velocity signals in one dashboard.
Related guides
- Measure PR delivery metrics : Configure the delivery metrics properties that complement this readiness scorecard.
- Ensure production readiness : A broader guide covering PagerDuty on-call mapping and deployment gating.