Create the Engineering Intelligence Pulse
Engineering Intelligence Pulse is an agentic workflow that assesses your engineering data every week. It ranks the engineering improvements worth making and publishes a brief to Slack. This guide walks you through the setup and configuration process, so the assessment runs end to end in your Port platform.
Most engineering organizations have more metrics than they can act on. Dashboards show what changed, but not which problem to fix first or who should fix it. The Engineering Intelligence Pulse puts an AI agent in front of that data. The agent reads your catalog and applies the domain expertise you have approved. It returns a ranked list of engineering improvements, each tied to its evidence and to the team that owns the affected service.
By the end, we will have the blueprints, the AI agent, the domain skill, and the workflow in place. The assessment will run on a schedule, record every engineering improvement in the catalog, and publish the top three to Slack.
The solution is made of three parts that share a common data model:
- Engineering Intelligence Agent: the AI agent that runs the assessment. It holds the output contract and the rules about what it may and may not claim, but no domain knowledge of its own.
- Domain skills:
skillentities markedeiApproved. Each one covers a single engineering domain and supplies the metrics, comparison bases, and judgment for it. - Engineering Intelligence Pulse workflow: the node graph that triggers the agent, records the result, and publishes the brief.
Common use casesโ
- Prioritize what matters: rank engineering improvements using your own data instead of a generic industry benchmark.
- Know what to do next: every recommendation comes with the team that owns it, the affected service, and a suggested next step.
- Customize it to your organization: the domains the agent assesses are simply the skills you enable, so you can shape the assessment around what your teams care about.
Prerequisitesโ
This guide assumes the following:
- A Port account with the onboarding process completed.
- Admin permissions in your Port organization, since you will create blueprints, an AI agent, a secret, and a workflow.
- A Git integration ingesting pull request data, such as GitHub or GitLab. The Delivery Performance skill reads cycle time, merged volume, and reviewer coverage, so an empty catalog produces an
Insufficient datarun. - Service-to-team ownership in the catalog, so each opportunity can name the team that owns it.
- A Slack channel for the weekly brief, with a Slack bot that can post to it.
Scorecards are optional. The agent uses them as one source of governed thresholds when they exist, and falls back to historical baselines when they do not.
Step 1: Create the blueprintsโ
The workflow reads and writes three blueprints. Create them in the order below, since each one relates to the blueprints above it.
To create a blueprint:
- Go to the Data model page in Port.
- Click
+ Blueprint, then{...} Edit JSON. - Paste the JSON for the blueprint, then click
Create.
Skill blueprintโ
If you don't have a skill blueprint yet, create it using the JSON below. If you already have one, just add these two properties to it instead:
-
eiApproved: a boolean that marks the skill as available to the Engineering Intelligence Pulse. The agent only loads skills where this istrue. -
eiDomain: the engineering domain the skill covers, such asDelivery Performance. The agent reports coverage and groups its findings by this value.Skill blueprint (click to expand)
{"identifier": "skill","title": "Skill","schema": {"properties": {"description": {"title": "Description","type": "string","description": "What the skill does and when the model should use it"},"instructions": {"title": "Instructions","type": "string","format": "markdown","description": "Step-by-step instructions for the AI to follow"},"references": {"title": "References","type": "array","description": "Reference documents for the skill","items": {"type": "object","properties": {"path": {"type": "string"},"content": {"type": "string"},"description": {"type": "string"}},"required": ["path","content"]}},"assets": {"title": "Assets","type": "array","description": "Asset files (templates, configs) for the skill","items": {"type": "object","properties": {"path": {"type": "string"},"content": {"type": "string"},"description": {"type": "string"}},"required": ["path","content"]}},"location": {"type": "string","title": "Location","default": "global","enum": ["global","project"]},"eiApproved": {"title": "EI Approved","description": "Approved for selection in the Engineering Intelligence Pulse workflow. Set true to make this skill available without changing the workflow.","type": "boolean"},"eiDomain": {"title": "EI Domain","description": "The engineering domain this skill covers, e.g. Delivery Performance, Incident Recovery, Pipeline Reliability.","type": "string"}},"required": ["description","instructions","location"]},"mirrorProperties": {},"calculationProperties": {},"aggregationProperties": {},"relations": {}}
Upserting a blueprint merges into what is already there. Once a property exists, no later update can remove it.
Engineering Intelligence Pulse Run blueprintโ
Holds one record per assessment run, including the executive summary, the domains that were assessed, and any limitations. The Engineering Opportunity blueprint mirrors two of its properties.
Engineering Intelligence Pulse Run blueprint (click to expand)
{
"identifier": "engineeringIntelligencePulse",
"title": "Engineering Intelligence Pulse Run",
"schema": {
"properties": {
"assessmentPeriod": {
"title": "Assessment Period",
"description": "The time window covered by this assessment, as reported by the workflow.",
"type": "string"
},
"assessmentStatus": {
"title": "Assessment Status",
"description": "The overall result of the assessment. Insufficient data never means that performance is healthy.",
"type": "string",
"enum": [
"Recommendation ready",
"No action needed",
"Insufficient data"
],
"enumColors": {
"Recommendation ready": "blue",
"No action needed": "green",
"Insufficient data": "orange"
}
},
"executiveSummary": {
"title": "Executive Summary",
"description": "A concise summary of what changed or matters across the assessed engineering domains during this period.",
"type": "string"
},
"opportunityCount": {
"type": "number",
"title": "Opportunities Identified",
"description": "Number of validated, confidence-filtered opportunities actually persisted for this run."
},
"runId": {
"title": "Workflow Run ID",
"description": "The Port workflow run identifier for this execution.",
"type": "string"
},
"assessedDomains": {
"title": "Assessed Domains",
"description": "The engineering domains successfully assessed during this run.",
"type": "array"
},
"limitations": {
"title": "Limitations",
"description": "Coverage gaps, connector failures, truncated candidates and normalization notes recorded by this run. Never empty because the assessment went well - read it alongside Assessment Status.",
"type": "array"
}
},
"required": [
"assessmentPeriod",
"assessmentStatus",
"executiveSummary",
"assessedDomains",
"opportunityCount",
"runId"
]
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"assessedSkills": {
"title": "Skills Used",
"description": "The approved domain skills used during this Engineering Intelligence Pulse assessment.",
"target": "skill",
"required": false,
"many": true
}
}
}
Engineering Opportunity blueprintโ
Holds each ranked engineering improvement, along with the evidence behind it, the measurement it is based on, and the team that owns the affected scope. This is the main output of every assessment run.
Engineering Opportunity blueprint (click to expand)
{
"identifier": "engineeringOpportunity",
"title": "Engineering Opportunity",
"ownership": {
"type": "Direct",
"title": "Owner"
},
"schema": {
"properties": {
"status": {
"title": "Status",
"description": "The overall lifecycle stage of the opportunity. Decision records what a manager decided, while Verification Verdict records the measured result.",
"type": "string",
"enum": [
"Identified",
"Awaiting decision",
"Accepted",
"Ready for action",
"Action initiated",
"In progress",
"Awaiting verification",
"Verified",
"Verification complete",
"Deferred",
"Dismissed"
],
"enumColors": {
"Identified": "lightGray",
"Awaiting decision": "yellow",
"Ready for action": "blue",
"In progress": "purple",
"Awaiting verification": "turquoise",
"Verification complete": "green",
"Deferred": "orange",
"Dismissed": "darkGray",
"Accepted": "blue",
"Action initiated": "purple",
"Verified": "green"
}
},
"decision": {
"title": "Decision",
"description": "What the responsible manager decided. Empty until the opportunity is reviewed.",
"type": "string",
"enum": [
"Approved",
"Deferred",
"Rejected"
],
"enumColors": {
"Approved": "green",
"Deferred": "orange",
"Rejected": "red"
}
},
"decidedBy": {
"title": "Decided By",
"description": "The person who made the decision.",
"type": "string",
"format": "email"
},
"decisionReason": {
"title": "Decision Reason",
"description": "Optional rationale supplied by the decision maker.",
"type": "string"
},
"domain": {
"title": "Domain",
"description": "The engineering domain covered by the source skill.",
"type": "string"
},
"scopeType": {
"title": "Scope Type",
"description": "The kind of catalog scope affected, such as organization, team or service.",
"type": "string"
},
"scopeIdentifier": {
"title": "Scope Identifier",
"description": "The stable identifier of the affected catalog scope.",
"type": "string"
},
"scopeTitle": {
"title": "Scope",
"description": "The human-readable title of the affected catalog scope.",
"type": "string"
},
"primaryMetric": {
"title": "Primary Metric",
"description": "The metric used to substantiate and later verify this opportunity. Free text allows each domain skill to use organization-specific metrics.",
"type": "string"
},
"metricUnit": {
"title": "Metric Unit",
"description": "The unit used by baseline, target and current values.",
"type": "string"
},
"baselineValue": {
"title": "Baseline Value",
"description": "The measured value used as the baseline for this improvement cycle. Freeze this value once an action is approved.",
"type": "number"
},
"targetValue": {
"title": "Target Value",
"description": "The organization-defined target for the primary metric. Empty when no meaningful target exists.",
"type": "number"
},
"priority": {
"title": "Priority",
"description": "How much the opportunity matters. This is distinct from confidence in the evidence. Critical is a human designation. The assessment agent emits only High, Medium or Low.",
"type": "string",
"enum": [
"Critical",
"High",
"Medium",
"Low"
],
"enumColors": {
"High": "orange",
"Medium": "yellow",
"Low": "green",
"Critical": "red"
}
},
"summary": {
"title": "Summary",
"description": "A concise statement of the engineering opportunity.",
"type": "string"
},
"evidence": {
"title": "Evidence",
"description": "Evidence items supplied by the source skill. The workflow must not fabricate missing evidence.",
"type": "array"
},
"successMeasure": {
"title": "Success Measure",
"description": "The measurable condition used to determine whether the opportunity improved.",
"type": "string"
},
"actionReference": {
"title": "Improvement Item",
"description": "A link to the governed ticket, workflow result or other improvement item created after approval.",
"type": "string",
"format": "url"
},
"verificationVerdict": {
"title": "Verification Verdict",
"description": "The outcome of re-measuring the primary metric after action was initiated.",
"type": "string",
"enum": [
"Improved",
"No improvement",
"Inconclusive"
],
"enumColors": {
"Improved": "green",
"No improvement": "red",
"Inconclusive": "lightGray"
}
},
"currentValue": {
"title": "Verified Value",
"description": "The primary metric value measured during verification, using Metric Unit.",
"type": "number"
},
"verifiedAt": {
"title": "Verified At",
"description": "When the primary metric was re-measured and the verdict recorded.",
"type": "string",
"format": "date-time"
},
"verificationNotes": {
"title": "Verification Notes",
"description": "Why the verification verdict was reached, including evidence limitations and caveats.",
"type": "string"
},
"confidence": {
"title": "Confidence",
"description": "How reliable the assessment is. Importance does not make the supporting evidence stronger.",
"type": "string",
"enum": [
"High",
"Medium",
"Low"
],
"enumColors": {
"High": "green",
"Medium": "yellow",
"Low": "orange"
}
},
"rankingRationale": {
"title": "Ranking Rationale",
"description": "Why this opportunity ranked ahead of other qualified opportunities in the originating Engineering Intelligence Pulse run.",
"type": "string"
},
"opportunityRank": {
"title": "Initial Rank",
"description": "The opportunity's position among actionable opportunities in the originating Engineering Intelligence Pulse run.",
"type": "number"
},
"evidenceSummary": {
"title": "Evidence Summary",
"description": "A concise statement of the evidence supporting this opportunity.",
"type": "string"
},
"recommendedAction": {
"title": "Recommended workflow",
"description": "The workflow that should act on this opportunity. Whether that workflow exists today is recorded separately in Available Workflow.",
"type": "string"
},
"targetOperator": {
"title": "Target Operator",
"description": "How the target should be compared. Empty when no organization-defined target exists.",
"type": "string",
"enum": [
"<",
"<=",
">",
">=",
"="
]
},
"availableWorkflow": {
"title": "Available Workflow",
"description": "The governed Port workflow that can act on this opportunity. Empty when no governed workflow is available.",
"type": "string"
},
"decidedAt": {
"title": "Decided At",
"description": "When the decision was recorded.",
"type": "string",
"format": "date-time"
},
"opportunityKey": {
"title": "Opportunity Key",
"description": "Stable key used to find the same unresolved opportunity across Pulse runs, typically derived from domain, scope and opportunity or metric type.",
"type": "string"
},
"firstObservedAt": {
"title": "First Observed At",
"description": "When this improvement cycle was first identified.",
"type": "string",
"format": "date-time"
},
"lastObservedAt": {
"title": "Last Observed At",
"description": "The most recent time this unresolved opportunity was observed by a Pulse run.",
"type": "string",
"format": "date-time"
},
"whyItMatters": {
"title": "Impact",
"description": "Who is affected and the operational consequence. Stated as 'Who: consequence' so it stays scannable in a table.",
"type": "string"
},
"actionInitiatedAt": {
"title": "Action Initiated At",
"description": "When governed action was initiated for this opportunity.",
"type": "string",
"format": "date-time"
},
"recoverableHours": {
"title": "Recoverable Hours",
"description": "Delay removable if this opportunity reaches its target, in hours: (baseline - target) multiplied by the recorded volume for the measurement window. Populate only where a real volume figure exists, and only with comparable units - do not mix incident downtime with change latency.",
"type": "number"
},
"hoursSaved": {
"title": "Hours Saved",
"description": "Time saved that has actually been realized, in hours. Populate only after a recommendation has been applied and the metric re-read. Where the measured improvement is a per-unit saving with no recorded volume, this is a supplied estimate rather than a figure derived from the catalog - record the basis in Verification Notes.",
"type": "number"
}
},
"required": [
"status",
"domain",
"priority",
"summary"
]
},
"mirrorProperties": {
"assessmentPeriod": {
"title": "Assessment Period",
"path": "pulse.assessmentPeriod"
},
"actionableOpportunityCount": {
"title": "Opportunities Identified",
"path": "pulse.opportunityCount"
}
},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"pulse": {
"title": "Originating Pulse Run",
"description": "The Engineering Intelligence Pulse run that first created this improvement cycle.",
"target": "engineeringIntelligencePulse",
"required": false,
"many": false
},
"service": {
"title": "Service",
"description": "The catalog service this opportunity affects. Empty for team- or organization-scoped findings, where Scope carries the context instead.",
"target": "service",
"required": false,
"many": false
},
"sourceSkill": {
"title": "Source Skill",
"description": "The approved engineering-domain skill that produced the opportunity.",
"target": "skill",
"required": false,
"many": false
}
}
}
After this step you should have skill, engineeringIntelligencePulse, and engineeringOpportunity in your data model. The workflow cannot run until all three exist.
Step 2: Create the AI agentโ
The agent runs the assessment. It carries the output contract and the rules about what it may and may not claim, while the domain knowledge comes from the skills you publish in Step 3.
-
Go to the AI agents page in Port.
-
Click
+ AI Agent, then toggleJSON Modeon. -
Paste the configuration below, then click
Create.Engineering Intelligence Agent (click to expand)
{"identifier": "engineering_intelligence_agent","title": "Engineering Intelligence Agent","properties": {"description": "Assesses engineering performance across approved domains and ranks where improvement would have the greatest impact. Read-only: it reports, it never remediates.","status": "active","prompt": "You are the Engineering Intelligence Agent. You assess engineering performance across the domains your organization has approved, and you report what you found.\n\nYou are read-only. You never create tickets, invoke remediation, approve actions, or promise that an intervention will improve a metric. You never assess an individual person.\n\nYour domain expertise comes from skills, not from this prompt. List `skill` entities where `eiApproved` is true, load every one with the `load_skill` tool, and apply each skill's judgment to its own domain. Do not assume which domains exist.\n\nPort is the system of record. Query Port first. When reading scorecards, call `list_scorecards` and pass the identifiers, because without them you get rule titles and levels but not the numeric conditions, and a rule title can contradict its own condition.\n\nHonesty rules that override everything else:\n- Never invent a metric, target, owner, trend, cause or source.\n- Never substitute an industry benchmark for a threshold you could not read.\n- Never use 0 as a stand-in for a missing value. Zero is a valid reading.\n- Report what you could not measure as a limitation, never as a healthy result.\n- Keep priority and confidence separate. Importance does not strengthen evidence.\n- Describe co-occurring facts without implying causality.\n\nWhen a workflow supplies a structured output contract, that contract and the workflow's instructions are authoritative over this prompt.","execution_mode": "Automatic","tools": ["^(list|search|track|describe|load)_.*"]},"relations": {"mcp_servers": []}}
The tools pattern includes load_ so that the agent can call load_skill.
The AI agents page should now list Engineering Intelligence Agent with a status of Active. It has no domain knowledge yet, so leave it alone until Step 3 is done.
Step 3: Publish a domain skillโ
This is where the domain knowledge lives. The example below covers Delivery Performance, defining which metrics to read, how to pick a comparison basis, and when to hold a recommendation back.
-
Go to the Skill page, or open the
skillblueprint's entities from the catalog. -
Click
+ Skill, then toggleJSON Modeon. -
Paste the JSON below, then click
Create.Delivery Performance skill (click to expand)
{"identifier": "delivery-performance-skill","title": "Assess Delivery Performance","properties": {"description": "Supplies Delivery Performance domain expertise to the Engineering Intelligence Agent: discovers, interprets and ranks material opportunities for leadership review. Read-only. Never creates tickets, invokes remediation, approves actions, or promises an intervention will improve a metric. Never assesses individual people.","instructions": "# Assess Delivery Performance\n\n## Objective\n\nSupply Delivery Performance domain expertise to the Engineering Intelligence Agent. Discover, interpret, and\nrank material opportunities for leadership review without replacing the agent's workflow instructions or\nstructured-output contract.\n\nOperate read-only. Do not create tickets, invoke remediation, approve actions, or promise that an\nintervention will improve a metric.\n\n## Decision model\n\nApply domain judgment rather than reproducing a rules engine:\n\n- Establish trustworthy facts and comparisons.\n- Interpret what those facts mean using Delivery Performance expertise.\n- Recommend the opportunities that most warrant attention.\n- Explain the evidence and uncertainty so a leader can review and decide.\n\nTreat scorecards as one optional source of governed thresholds. Do not limit discovery to scorecard failures.\n\n## Guardrails\n\n- Use Port catalog data as the primary source of engineering context.\n- Use approved read-only MCP connectors only when additional evidence would materially improve the\n assessment.\n- Never invent a metric, target, owner, trend, cause, or source.\n- Keep organization, team, and service metrics clearly separated.\n- Label every time window and preserve the sample size behind each ratio, median, or trend.\n- Compare only equivalent scopes, definitions, and periods.\n- Treat priority and confidence separately: importance does not strengthen evidence.\n- Describe co-occurring facts without implying causality. Name a contributor only when direct evidence\n supports it.\n- Return fewer than three recommendations when additional candidates are not material or credible. Never pad\n the list.\n\n## Assessment sequence\n\n### 1. Establish scope and coverage\n\nUse the period and scope supplied by the workflow. Determine:\n\n- The organization being assessed.\n- The services and teams in scope.\n- Service-to-team ownership relations when available.\n- Service criticality or tier when explicitly available.\n- The current and comparison periods for each metric.\n\nTrack separately:\n\n- Scopes considered.\n- Scopes with usable data.\n- Scopes excluded and the reason.\n- Sources unavailable or materially incomplete.\n\nDo not describe results as organization-wide when coverage is partial. Prefer wording such as \"among\nassessed services\" or \"among services with sufficient data.\"\n\nExclude scopes owned only by `default_team` or `default_group`. Never assess an individual person.\n\n### 2. Resolve the comparison basis\n\nResolve the best available comparison in this order:\n\n1. An explicit target supplied by the workflow or organization configuration.\n2. A scope-specific target stored in Port.\n3. A relevant scorecard rule at an explicitly agreed maturity level.\n4. A comparable historical baseline for the same scope.\n5. An approved peer range for genuinely comparable scopes.\n\nUse `list_scorecards` when scorecards may contain a relevant threshold. Retrieve the complete rule condition\nby exact identifier. **Read the condition rather than trusting the rule title.**\n\nNever select Bronze, Silver, or Gold as the organization's target unless the workflow or organization\nexplicitly defines that level. If the assessment intentionally uses the next failed level, label it **next\nunmet scorecard threshold**, not target.\n\nWhen no configured target exists, continue assessing material deterioration or deviation from a valid\nbaseline. Label the comparison as a baseline, not a target, and record the absence of a configured target as\na limitation.\n\nNever substitute an external industry benchmark unless the organization explicitly approves it as a\ncomparison source. Label an approved benchmark as a benchmark, not an organization target.\n\n### 3. Build the organization KPI snapshot\n\nRead no more than three available, precomputed organization KPIs. Prefer:\n\n- Median MR or PR cycle time.\n- Merged MR or PR count for the stated period.\n- Stale open MR or PR share.\n\nUse reviewer coverage or time to first review instead only when configured as an executive KPI and more\nrelevant to the assessment.\n\nFor every KPI, retain:\n\n- Metric title, value, and unit.\n- Scope and time window.\n- Comparison value or trend percentage.\n- Target or other comparison basis when available.\n- Availability and source reference.\n\nReturn missing data as unavailable. **Never represent it as zero.**\n\n### 4. Screen service and team performance\n\nInspect the following when available:\n\n- Median cycle time for the current and comparable periods.\n- Merged volume and comparable throughput history.\n- Open MR or PR count.\n- Stale count and stale share using the configured age definition.\n- Reviewer assignment coverage.\n- Time to first review or review-wait time.\n- Persistence across comparable periods.\n\nPreserve the numerator, denominator, or sample size supporting every candidate.\n\n### 5. Interpret candidate opportunities\n\nUse the following patterns as domain guidance. Select the most specific framing supported by the evidence;\ndo not discard a material condition merely because a more specific pattern cannot be proven.\n\n**Reduce MR or PR cycle time**\n\nConsider a recommendation when cycle time materially breaches a configured threshold, deteriorates across\ncomparable periods, or deviates meaningfully from a valid historical baseline.\n\nDo not attribute the condition to review delay without reviewer-specific evidence.\n\n**Reduce reviewer delays**\n\nRequire direct reviewer evidence before using this framing, such as:\n\n- MRs or PRs without an assigned reviewer.\n- Excessive time to first review.\n- Review-wait time representing a material share of cycle time.\n- A persistent queue awaiting review.\n\nCycle time alone can support a cycle-time recommendation but not a reviewer-delay conclusion.\n\n**Clear a stale MR or PR backlog**\n\nRequire both a stale count and denominator. Treat a high percentage based on a small denominator cautiously,\nbut allow a material finding when scope criticality, persistence, or corroborating evidence justifies it.\n\n**Improve low throughput**\n\nUse this framing when throughput is materially below a configured threshold or valid baseline but available\nhistory does not establish a sustained decline.\n\n**Reverse declining throughput**\n\nReserve this framing for a decline across at least three comparable periods or another explicitly configured\npersistence rule. Check for known scope, staffing, or measurement changes before interpreting the decline as\na performance opportunity.\n\nDo not turn ordinary week-to-week variation into a trend claim.\n\n**Recognize other material patterns**\n\nAllow a recommendation outside the named patterns when the evidence reveals another material Delivery\nPerformance condition. Explain the reasoning, use a precise title, and avoid causal claims that the data does\nnot support.\n\n### 6. Assess materiality and confidence\n\nEvaluate each candidate holistically using:\n\n- Magnitude relative to its target, threshold, or valid baseline.\n- Direction and persistence across comparable periods.\n- Service criticality and affected scope.\n- Sample size, completeness, and recency.\n- Directness and consistency of supporting evidence.\n- Actionability and ownership context.\n\nA candidate may be recommended when evidence supports a material condition requiring leadership attention. A\nconfigured target breach is strong evidence but is not the only basis for a recommendation.\n\nTreat a missing target, unresolved owner, modest sample, or limited history as a reason to reduce confidence\nor actionability, not as an automatic exclusion.\n\nExclude a candidate only when:\n\n- The underlying metric is unavailable or unreliable.\n- Sources materially conflict and cannot be reconciled.\n- The proposed wording would require an unsupported causal, trend, or scope claim.\n- Known limitations make the conclusion misleading.\n- The evidence is too weak to justify leadership attention.\n\nAssign confidence as follows:\n\n- **High**: Use direct, current, consistent evidence with adequate volume or persistence and no material\n unresolved limitation.\n- **Medium**: Use valid primary evidence when the sample is modest, persistence is not established, ownership\n is unresolved, or secondary context is incomplete.\n- **Low**: Use when the finding depends materially on inference, sparse data, or conflicting sources. Retain\n it for investigation in Port, but do not publish it in the weekly Slack brief.\n\nDo not assign High confidence to a percentage based on fewer than five items unless repeated-period or\nindependent evidence corroborates it.\n\n### 7. Rank domain recommendations\n\nRank candidates using materiality, deterioration, criticality, affected scope, confidence, coverage, and\nactionability. Explain why a higher-ranked recommendation deserves attention before a lower-ranked one.\n\nAvoid duplicates. When related findings concern the same scope, keep the framing that best represents the\ndirectly evidenced problem and use the other metrics as supporting evidence.\n\nReturn up to three High- or Medium-confidence Delivery Performance recommendations for cross-domain\nconsideration. Let the Engineering Intelligence Agent perform the final cross-domain ranking.\n\n### 8. Return findings\n\nFollow the Engineering Intelligence Agent's output schema. Return:\n\n- Domain: Delivery Performance.\n- Source skill identifier: `delivery-performance-skill`.\n- Assessment status and coverage.\n- Limitations and excluded scopes.\n- Up to three domain recommendations.\n- Low-confidence investigation candidates separately when the schema supports them.\n\nFor every recommendation, provide:\n\n- A concise, outcome-oriented title.\n- Scope identifier and title.\n- Owning team identifier when available.\n- Primary metric, current value, unit, and period.\n- Comparison type and comparison label.\n- Target or comparison operator and value when available.\n- Priority and confidence.\n- One evidence summary sentence.\n- Supporting source references.\n\nUse one of these comparison types:\n\n- `configured_target`\n- `scorecard_threshold`\n- `historical_baseline`\n- `peer_baseline`\n- `none`\n\nPopulate `targetOperator` and `targetValue` only for `configured_target` or `scorecard_threshold`. For other\ncomparison types, use optional comparison fields rather than inventing a target.\n\nMap assessment status to `coverageStatus` as follows:\n\n- Complete assessment with or without recommendations: `complete`.\n- Some scopes or material sources unavailable: `partial`.\n- Insufficient evidence for a reliable domain assessment: `unavailable`.\n\nKeep source references separate from limitations. References establish provenance; limitations describe\nmissing, weak, or conflicting context.\n\n## Evidence-writing rules\n\n- State only the opportunity's `primaryMetric`, its value, and its measurement window. Do not add a second metric's figures to the same sentence, even when both are true for the scope.\n- Keep each summary to one short sentence suitable for a leadership Slack brief.\n- Use exact arithmetic and consistent units.\n- Distinguish service-level findings from organization KPIs.\n- Describe observed relationships directly. Do not use \"likely contributor\" or equivalent causal language\n without direct evidence.\n- Distinguish low throughput from declining throughput.\n- Do not use vague claims such as \"performance is bad\" or promises such as \"this will improve delivery.\"\n\nFor example, describe 5 MRs/month against `>=8` as **low throughput**. Describe it as **declining\nthroughput** only when comparable history supports a sustained decline.\n\n## Partial coverage and failure behavior\n\n- Continue with valid evidence when one secondary source is unavailable; lower confidence and record the\n limitation when material.\n- Continue without a configured target when a valid baseline or sustained deterioration supports assessment.\n- Return valid recommendations alongside explicit partial coverage when only some scopes are assessable.\n- Return `complete` with no recommendations only when the assessed evidence reveals no material opportunity.\n- Return `unavailable` when insufficient or contradictory evidence prevents a reliable domain assessment.\n\n## Output contract bindings\n\nThese bind the guidance above to the live output schema. Where the two differ, this section wins, because the\nschema is what the workflow validates against.\n\n- **No field can be truly optional.** Port's AI node fails unless every property in the output schema also\n appears in `required`. So \"absent target fields\" are expressed as placeholders, never omission: for\n `historical_baseline`, `peer_baseline` or `none`, set `targetOperator` to `\"\"` and `targetValue` to `0`,\n and put the real comparison in `comparisonLabel` (for example `\"vs 30-day baseline of 12 MRs\"`). The Slack\n template suppresses the target line for those comparison types, so a placeholder is never displayed.\n **A placeholder must never appear in `evidenceSummary`, `summary` or any published prose.**\n- **`comparisonType`** carries one of the five values above. **`comparisonLabel`** is the short human label\n for the comparison, such as `\"Silver scorecard threshold\"` or `\"next unmet scorecard threshold\"`.\n- **`metricPeriod`** is the window behind `currentValue`, such as `\"last 30 days\"` or `\"last 7 days\"`.\n- **`sourceReferences`** is provenance only, one short string per source. Run-level gaps stay in the\n top-level `limitations` array. Do not mix the two.\n- **`trendPercent`** is the signed percentage change of the metric's **own value** between the comparison\n period and the current period. If the value rose, `trendPercent` is positive. **Never invert the sign to\n express whether the change is good or bad**: a rising cycle time is a positive `trendPercent`.\n- **`title` must not name the scope.** The scope is rendered beside it, so \"Reduce MR cycle time\", never\n \"Reduce MR cycle time: Checkout Service\".\n- **Units are short symbols**: `h`, `%`, `MRs`. Not `hours`, not `MRs/week equivalent`.\n- **`opportunities` carries only High- and Medium-confidence recommendations.** The schema has no separate\n channel for Low-confidence investigation candidates; record those in `limitations` instead, naming the\n scope and why they were held back.\n- **`domains` must contain one entry per skill loaded and must never be empty.** An empty array suppresses\n the coverage warning entirely, which would publish a gap as though it were clean coverage.\n- **Any assessed scope that breaches a comparison but is not recommended must be named in `limitations`**\n with the reason. A dropped candidate must never be silently invisible.","location": "global","eiApproved": true,"eiDomain": "Delivery Performance"},"relations": {}}
Open the new Assess Delivery Performance entity and confirm that EI Approved is true and EI Domain reads Delivery Performance. The agent discovers skills by those two properties, so a skill with eiApproved unset is invisible to the assessment.
To cover another domain later, publish one more skill entity with eiApproved set to true and its own eiDomain. The agent picks it up on the next run without any change to the workflow, the agent configuration, or the blueprints.
Step 4: Add the Slack secretโ
The workflow reads your Slack bot token from a Port secret, so the token never appears in the workflow body.
- Open the Credentials modal in Port, then move to the
Secretstab. - Add a secret named
slack_ei_integration, holding a Slack bot token with thechat:writescope. - Invite the bot to the channel you want the brief posted in, and note the channel ID.
Step 5: Create the workflowโ
-
Go to the Workflows page in Port.
-
Click + Workflow.
-
Fill out the Create new workflow form, then click Confirm.
-
Click
{...}, then paste the workflow below, replacing<YOUR_SLACK_CHANNEL_ID>with the channel ID from Step 4.Engineering Intelligence Pulse workflow (click to expand)
{"identifier": "engineering_intelligence_pulse","title": "Engineering Intelligence Pulse","description": "Assess engineering data across approved domains to identify and rank where improvement can have the greatest impact. Each priority is connected to its evidence, affected service, owning team and recommended workflow.","category": "Engineering Intelligence","allowAnyoneToViewRuns": true,"nodes": [{"identifier": "trigger","title": "Identify improvement priorities","config": {"type": "SELF_SERVE_TRIGGER","userInputs": {"properties": {}},"executeActionButtonText": "Run assessment","published": true,"permissions": {"roles": ["Admin","Member"]}},"verbose": false},{"identifier": "weekly_trigger","title": "Every Monday 09:00","config": {"type": "SCHEDULE_TRIGGER","cron": "0 9 * * 1","published": true},"verbose": false},{"identifier": "assess","title": "Engineering Intelligence Agent","description": "Loads approved domain skills to assess engineering performance and prioritize cross-domain opportunities. Queries Port first; approved read-only connectors are used only where a loaded skill requires evidence Port does not hold.","config": {"type": "AI_AGENT","userPrompt": "Produce this week's Engineering Intelligence Pulse for the whole organization.\n\nBEFORE YOU FINISH: your output is persisted to the Port catalog and published to managers. An object of the right shape with invented data or placeholder prose is a FAILED assessment, not a completed one. Never emit \"todo\", \"TBD\", \"N/A\" or any placeholder in `executiveSummary` or any other prose field. `domains` must contain one entry for every loaded skill. An empty `opportunities` array is valid only for `no_action_needed` or `insufficient_data`. If you could not carry out the assessment, say so honestly: set `assessmentStatus` to `insufficient_data`, write a real one-sentence `executiveSummary` describing what blocked you, and record the cause in `limitations`. Never set `recommendation_ready` unless `opportunities` actually contains at least one qualified finding.\n\n1. DISCOVER - list `skill` entities where `eiApproved` is true. Do not assume which domains exist.\n\n2. LOAD - load every one with the load_skill tool. Each supplies expertise for its own area; this prompt and the structured-output contract remain authoritative.\n\n3. RETRIEVE - for each domain read the metrics and comparison bases that skill requires. When reading scorecards, call list_scorecards AND PASS THE IDENTIFIERS; without them you get rule titles and levels but not the numeric conditions. Rule titles can contradict their own conditions, so always evaluate the condition.\n\n4. EVIDENCE SOURCES - Port is the system of record, so query Port first. You also have approved read-only connectors. Use one ONLY when a skill you loaded says additional evidence would materially improve the assessment - never speculatively, and never to second-guess a value Port already gave you. Put provenance in each finding's `sourceReferences`. Put connector failures and missing context in the top-level `limitations`, and degrade that domain's coverage. Never substitute an estimate for evidence you could not retrieve.\n\n5. ASSESS EACH DOMAIN INDEPENDENTLY - apply each skill's own judgment to its own domain. A weak finding does not qualify because another domain produced nothing. Within a domain, consider every metric that skill defines before concluding a scope has no finding. A scope can be healthy on one metric and failing on another. Never treat clearing an evidence gate as though the scope had met a standard.\n\n6. KPIs - return at most three readable headline metrics in `kpis`, each with the domain it belongs to. These are concise context for the Slack brief only; they are not persisted as catalog entities. Omit an unreadable KPI entirely and record the gap in `limitations` when material. NEVER use 0 as a stand-in for a missing value; zero is a valid reading. A KPI with no meaningful comparison has an empty `targetOperator`. `trendPercent` is the signed change of the metric's own value: if the value rose, it is positive. Never invert the sign to express good or bad.\n\n7. RANK - rank qualified findings ACROSS all domains, returning at most TEN in `opportunities`, High or Medium confidence only. Return one, two or none rather than padding - ten is a ceiling, not a target. Ranks 1-3 are the Engineering Intelligence Pulse priorities: they are published to Slack and lead the dashboard. Ranks 4-10 are additional qualified opportunities retained in Port for review and later promotion - they are NOT lower-quality findings, they simply were not selected as the three immediate priorities. If more than ten qualify, keep the top ten by rank and DISCLOSE the truncation in `limitations` with the number dropped. Prefer breadth: do not return two findings on the same scope while another scope with a material breach goes unreported. Each entry carries its own `domain`, `skillIdentifier`, scope, `comparisonType`, `comparisonLabel` and `metricPeriod`. Populate `targetOperator` and `targetValue` only for `configured_target` or `scorecard_threshold`; for the other comparison types set them to \"\" and 0 and describe the comparison in `comparisonLabel` - an empty operator causes the target to be discarded at persistence rather than shown as a benchmark. A placeholder must never appear in published prose. `title` must NOT name the scope, which is rendered beside it. `primaryMetric` is a human label such as `Stale PR share`, never a raw property identifier. Units are short symbols: h, %, MRs. A scope that currently MEETS a threshold is not an opportunity.\n\n7b. DISTINCT PROSE FIELDS PER OPPORTUNITY - managers read these together, so they must not repeat each other:\n - `summary` - WHAT THE OPPORTUNITY IS. One concise sentence naming the problem.\n - `whyItMatters` - WHY THE OPPORTUNITY MATTERS. One sentence describing the engineering or business consequence without inventing impact.\n - `evidenceSummary` - WHAT WAS OBSERVED. One short sentence citing only the opportunity's primary metric, its value, and its measurement window. Do not stack a second metric's figures into this sentence, even when both are true for the scope.\n - `rankingRationale` - WHY IT DESERVES ATTENTION NOW, relative to the other qualified findings. One sentence naming the factors that moved it up or down: size of the gap, criticality of the scope, whether it is worsening, strength of evidence and breadth of impact. Never restate the numbers already in `evidenceSummary`.\n - `recommendedAction` - THE NEXT STEP A HUMAN SHOULD TAKE. A short imperative phrase, five to ten words. It must be an investigative or corrective step the owning team can actually start. Do NOT promise that a Port workflow, automation or agent exists; governed workflow availability is determined at persistence.\n\n8. COVERAGE - `domains` MUST contain one entry per skill loaded and must never be empty. Give each a `coverageStatus` of `complete`, `partial` or `unavailable`, plus a short evidence-based note. Put material gaps, connector failures and omitted qualified candidates in top-level `limitations`. Do not fabricate coverage counts. Any assessed scope that breaches a comparison but is not recommended MUST be named in `limitations` with the reason; a dropped candidate must never be silently invisible.\n\nSet `assessmentStatus` to `recommendation_ready` when at least one qualified opportunity exists. Use `no_action_needed` ONLY when every enabled domain was assessed successfully and revealed no material opportunity. If nothing qualified but coverage was incomplete, use `insufficient_data` - never report a coverage gap as healthy.\n\n`executiveSummary` is ONE sentence on what moved this week across the assessed domains, with no service or team identifiers. Each opportunity's three prose fields must follow the separation defined in 7b, and none of them may claim causality the data does not establish. Distinguish low throughput from declining throughput.","agentIdentifier": "engineering_intelligence_agent","outputSchema": {"type": "object","properties": {"kpis": {"type": "array","items": {"type": "object","required": ["title","domain","currentValue","unit","metricPeriod","trendPercent","targetOperator","targetValue"],"properties": {"unit": {"type": "string"},"title": {"type": "string"},"domain": {"type": "string"},"targetValue": {"type": "number"},"currentValue": {"type": "number"},"metricPeriod": {"type": "string"},"trendPercent": {"type": "number"},"targetOperator": {"type": "string"}}}},"domains": {"type": "array","items": {"type": "object","required": ["domain","skillIdentifier","coverageStatus","note"],"properties": {"note": {"type": "string"},"domain": {"type": "string"},"coverageStatus": {"enum": ["complete","partial","unavailable"],"type": "string"},"skillIdentifier": {"type": "string"}}},"minItems": 1},"limitations": {"type": "array","items": {"type": "string"}},"opportunities": {"type": "array","items": {"type": "object","required": ["rank","title","domain","skillIdentifier","scopeType","scopeTitle","scopeIdentifier","owningTeamIdentifier","priority","confidence","primaryMetric","currentValue","metricUnit","metricPeriod","comparisonType","comparisonLabel","targetOperator","targetValue","evidenceSummary","rankingRationale","recommendedAction","summary","successMeasure","sourceReferences","whyItMatters"],"properties": {"rank": {"type": "number"},"title": {"type": "string"},"domain": {"type": "string"},"summary": {"type": "string"},"priority": {"enum": ["High","Medium","Low"],"type": "string"},"scopeType": {"type": "string"},"confidence": {"enum": ["High","Medium","Low"],"type": "string"},"metricUnit": {"type": "string"},"scopeTitle": {"type": "string"},"targetValue": {"type": "number"},"currentValue": {"type": "number"},"metricPeriod": {"type": "string"},"whyItMatters": {"type": "string"},"primaryMetric": {"type": "string"},"comparisonType": {"enum": ["configured_target","scorecard_threshold","historical_baseline","peer_baseline","none"],"type": "string"},"successMeasure": {"type": "string"},"targetOperator": {"type": "string"},"comparisonLabel": {"type": "string"},"evidenceSummary": {"type": "string"},"scopeIdentifier": {"type": "string"},"skillIdentifier": {"type": "string"},"rankingRationale": {"type": "string"},"sourceReferences": {"type": "array","items": {"type": "string"}},"recommendedAction": {"type": "string"},"owningTeamIdentifier": {"type": "string"}}}},"assessmentPeriod": {"type": "string"},"assessmentStatus": {"enum": ["recommendation_ready","no_action_needed","insufficient_data"],"type": "string"},"executiveSummary": {"type": "string"}},"required": ["assessmentStatus","assessmentPeriod","executiveSummary","limitations","kpis","domains","opportunities"]}},"variables": {"brief": "{{ .result.response | if type == \"string\" then fromjson else . end }}"},"verbose": true},{"identifier": "persist_pulse","title": "Persist Pulse run","description": "One entity per workflow run, written for every outcome so healthy and inconclusive assessments remain visible. The workflow calculates the persisted opportunity count, records the domains actually assessed, relates every loaded skill and normalizes incoherent assessment outcomes.","config": {"type": "WEBHOOK","url": "https://api.port.io/v1/blueprints/engineeringIntelligencePulse/entities?upsert=true&merge=true","agent": false,"synchronized": true,"method": "POST","headers": {"Content-Type": "application/json"},"body": {"title": "{{ \"Engineering Intelligence Pulse: \" + ((.outputs[\"assess\"].brief.assessmentPeriod // \"\") | if . == \"\" then \"unscheduled run\" else . end) }}","relations": {"assessedSkills": "{{ (.outputs[\"assess\"].brief.domains // []) | map(.skillIdentifier) | unique }}"},"identifier": "{{ \"pulse-\" + .workflowRun.identifier }}","properties": {"runId": "{{ .workflowRun.identifier }}","limitations": "{{ (.outputs[\"assess\"].brief) as $b | (($b.opportunities // []) | map(select(.confidence != \"Low\"))) as $q | (($b.limitations // []) + (if ($q | length) > 10 then [\"Truncated: \\($q | length) opportunities qualified, only the top 10 by rank were persisted.\"] else [] end) + (if $b.assessmentStatus == \"recommendation_ready\" and ($q | length) == 0 then [\"Agent reported recommendation_ready but returned no qualified opportunity; status was normalized to insufficient_data at persistence. Treat this run as a failed assessment, not as a healthy result.\"] else [] end)) }}","assessedDomains": "{{ (.outputs[\"assess\"].brief.domains // []) | map(select(.coverageStatus != \"unavailable\") | .domain) | unique }}","assessmentPeriod": "{{ .outputs[\"assess\"].brief.assessmentPeriod }}","assessmentStatus": "{{ (.outputs[\"assess\"].brief) as $b | (($b.opportunities // []) | map(select(.confidence != \"Low\")) | length) as $n | (if $b.assessmentStatus == \"recommendation_ready\" and $n > 0 then \"Recommendation ready\" elif $b.assessmentStatus == \"no_action_needed\" then \"No action needed\" else \"Insufficient data\" end) }}","executiveSummary": "{{ .outputs[\"assess\"].brief.executiveSummary }}","opportunityCount": "{{ ((.outputs[\"assess\"].brief.opportunities // []) | map(select(.confidence != \"Low\")) | .[0:10] | length) }}"}},"onTimeout": "fail","onFailure": "terminate"},"variables": {"pulse_id": "{{ \"pulse-\" + .workflowRun.identifier }}"},"verbose": true},{"identifier": "assessment_outcome","title": "Assessment outcome","description": "The only business branch: what did the assessment actually find. recommendation_ready additionally requires at least one qualified opportunity, so an agent that claims priorities but returns none falls through to the fallback path instead of hitting the bulk endpoint with an empty array.","config": {"type": "CONDITION","outlets": [{"identifier": "recommendation_ready","title": "Priorities to publish","expression": ".outputs[\"assess\"].brief.assessmentStatus == \"recommendation_ready\" and ((.outputs[\"assess\"].brief.opportunities // []) | map(select(.confidence != \"Low\")) | length) > 0"},{"identifier": "no_action_needed","title": "No action needed","expression": ".outputs[\"assess\"].brief.assessmentStatus == \"no_action_needed\"","workflowStatusLabel": {"text": "No material opportunity found","variant": "success"}},{"identifier": "insufficient_data","title": "Assessment inconclusive","expression": ".outputs[\"assess\"].brief.assessmentStatus == \"insufficient_data\"","workflowStatusLabel": {"text": "Assessment inconclusive - insufficient data","variant": "alert"}}]},"verbose": false},{"identifier": "persist_priorities","title": "Persist opportunities","description": "One bulk upsert of every qualified opportunity, related to its originating Engineering Intelligence Pulse run and source skill. Ranks 1-3 start as 'Awaiting decision'; ranks 4-10 start as 'Identified'. The workflow records evidence, scope, priority, the next step and a stable opportunity key, but never claims that action or verification has occurred.","config": {"type": "WEBHOOK","url": "https://api.port.io/v1/blueprints/engineeringOpportunity/entities/bulk?upsert=true&merge=true","agent": false,"synchronized": true,"method": "POST","headers": {"Content-Type": "application/json"},"body": {"entities": "{{ (.outputs[\"assess\"].brief) as $b | (.workflowRun.identifier) as $run | ($run | sub(\"^wfr_\"; \"\")) as $rid | (($b.opportunities // []) | map(select(.confidence != \"Low\")) | sort_by(.rank) | .[0:10]) as $persisted | $persisted | map({ identifier: (\"eo-\" + (.scopeIdentifier | ascii_downcase | gsub(\"[^a-z0-9]+\"; \"-\")) + \"-\" + (.primaryMetric | ascii_downcase | gsub(\"[^a-z0-9]+\"; \"-\")) + \"-\" + $rid), title: (.title + \": \" + .scopeTitle), team: [.owningTeamIdentifier], properties: { status: (if .rank <= 3 then \"Awaiting decision\" else \"Identified\" end), availableWorkflow: \"\", domain: .domain, opportunityRank: .rank, scopeType: .scopeType, scopeIdentifier: .scopeIdentifier, scopeTitle: .scopeTitle, primaryMetric: .primaryMetric, metricUnit: .metricUnit, baselineValue: .currentValue, targetOperator: (if ((.targetOperator // \"\") | length) == 0 then null else .targetOperator end), targetValue: (if ((.targetOperator // \"\") | length) == 0 then null else .targetValue end), priority: .priority, confidence: .confidence, summary: .summary, whyItMatters: .whyItMatters, evidenceSummary: .evidenceSummary, rankingRationale: .rankingRationale, recommendedAction: .recommendedAction, successMeasure: .successMeasure, evidence: (.sourceReferences // []), opportunityKey: ((.domain | ascii_downcase | gsub(\"[^a-z0-9]+\"; \"-\")) + \"-\" + (.scopeType | ascii_downcase | gsub(\"[^a-z0-9]+\"; \"-\")) + \"-\" + (.scopeIdentifier | ascii_downcase | gsub(\"[^a-z0-9]+\"; \"-\")) + \"-\" + (.primaryMetric | ascii_downcase | gsub(\"[^a-z0-9]+\"; \"-\"))), firstObservedAt: (now | todateiso8601), lastObservedAt: (now | todateiso8601) }, relations: { sourceSkill: .skillIdentifier, pulse: (\"pulse-\" + $run), service: (if .scopeType == \"service\" then .scopeIdentifier else null end) } }) }}"},"onTimeout": "fail","onFailure": "terminate"},"variables": {"persisted": "{{ (.result.response.data.entities // []) | length }}"},"verbose": true},{"identifier": "notify_brief","title": "Slack: pulse","description": "One publishing node for all outcomes. Only ranks 1-3 are published - ranks 4-10 stay in the Port catalog so Slack remains a decision surface rather than a backlog. slack_ok exposes Slack's ok flag, because Slack returns HTTP 200 even when it rejects the message.","config": {"type": "WEBHOOK","url": "https://slack.com/api/chat.postMessage","agent": false,"synchronized": true,"method": "POST","headers": {"Content-Type": "application/json; charset=utf-8","Authorization": "Bearer {{ .secrets[\"slack_ei_integration\"] }}"},"body": {"text": "๐ Engineering Intelligence Pulse","blocks": [{"text": {"text": "๐ Engineering Intelligence Pulse","type": "plain_text"},"type": "header"},{"type": "context","elements": [{"text": "{{ .outputs[\"assess\"].brief.assessmentPeriod }}","type": "mrkdwn"}]},{"text": {"text": "{{ (.outputs[\"assess\"].brief) as $b | (($b.opportunities // []) | map(select(.confidence != \"Low\")) | length) as $n | (if $b.assessmentStatus == \"no_action_needed\" then \"โ \" elif ($b.assessmentStatus == \"recommendation_ready\" and $n == 0) then \"โ \" else \"โ ๏ธ \" end) + (if ($b.assessmentStatus == \"recommendation_ready\" and $n == 0) then \"The assessment did not complete: no qualified opportunity was produced. This is not a statement that performance is healthy.\" else $b.executiveSummary end) }}","type": "mrkdwn"},"type": "section"},{"type": "divider"},{"text": {"text": "{{ (.outputs[\"assess\"].brief) as $b | ($b.kpis // []) as $k | (($b.domains // []) | map(select(.coverageStatus != \"complete\"))) as $gaps | (if ($k | length) == 0 then \"๐ *Headline metric context*\\nNo headline metric was measurable this period.\" else (\"๐ *Headline metric context*\\n\" + ($k | map(. as $m | ((if ($m.unit | length) > 1 then \" \" else \"\" end)) as $sp | \"โข \\($m.title): \\($m.currentValue)\\($sp)\\($m.unit)\" + (if ($m.metricPeriod | length) > 0 then \" (\\($m.metricPeriod))\" else \"\" end) + (if $m.trendPercent != 0 then ((if $m.trendPercent > 0 then \" โ\" else \" โ\" end) + ((if $m.trendPercent < 0 then (0 - $m.trendPercent) else $m.trendPercent end) | tostring) + \"%\") else \"\" end)) | join(\"\\n\"))) end) + (if ($gaps | length) > 0 then (\"\\n\\n_โ ๏ธ Coverage limitations: \" + ($gaps | map(\"\\(.domain): \\(.note)\") | join(\"; \")) + \"._\") elif (($b.limitations // []) | length) > 0 then (\"\\n\\n_โ ๏ธ \" + (($b.limitations // []) | length | tostring) + \" limitation(s) recorded. See the run in Port._\") else \"\" end) }}","type": "mrkdwn"},"type": "section"},{"type": "divider"},{"text": {"text": "{{ (.outputs[\"assess\"].brief) as $b | (($b.opportunities // []) | map(select(.confidence != \"Low\")) | sort_by(.rank)) as $q | ($q | map(select(.rank <= 3))) as $o | if ($o | length) > 0 then ((if ($o | length) == 1 then \"๐ฏ *Top priority*\\n\\n\" else \"๐ฏ *Top priorities*\\n\\n\" end) + ($o | map(. as $x | ((if ($x.metricUnit | length) > 1 then \" \" else \"\" end)) as $sp | \"*\\($x.rank). \\($x.title): \\($x.scopeTitle)*\\n\\($x.domain) ยท \\($x.priority) priority ยท \\($x.confidence) confidence\\nCurrent: \\($x.currentValue)\\($sp)\\($x.metricUnit)\" + \"\\n*Why now:* \\($x.rankingRationale)\\n*Evidence:* \\($x.evidenceSummary)\\n*Next step:* \\($x.recommendedAction)\") | join(\"\\n\\n\"))) + (if ($q | length) > ($o | length) then (\"\\n\\n_\" + (($q | length) - ($o | length) | tostring) + \" further qualified \" + (if (($q | length) - ($o | length)) == 1 then \"opportunity is\" else \"opportunities are\" end) + \" retained in Port for review._\") else \"\" end) elif $b.assessmentStatus == \"no_action_needed\" then \"๐ฏ *Top priorities*\\n\\nNo material opportunity was found. Every enabled domain was assessed successfully.\" else \"๐ฏ *Top priorities*\\n\\nNo priorities could be produced, and coverage was incomplete. This is *not* a statement that performance is healthy.\" end }}","type": "mrkdwn"},"type": "section"},{"type": "divider"},{"text": {"text": "{{ (.outputs[\"assess\"].brief) as $b | (($b.opportunities // []) | map(select(.confidence != \"Low\"))) as $o | if ($b.assessmentStatus == \"insufficient_data\" or ($o | length) == 0) then \"๐ <https://app.port.io/settings/data-sources|*Check data readiness in Port*>\" else \"๐ <https://app.port.io/engineeringOpportunities|*View full evidence in Port*>\" end }}","type": "mrkdwn"},"type": "section"},{"type": "context","elements": [{"text": "{{ (.outputs[\"assess\"].brief) as $b | (($b.opportunities // []) | map(select(.confidence != \"Low\")) | .[0:10] | length) as $n | (($b.domains // []) | length) as $s | \"๐ค Skills used: \\($s) ยท \\($n) \" + (if $n == 1 then \"opportunity identified\" else \"opportunities identified\" end) + (if $n > 3 then \" (top 3 published)\" else \"\" end) }}","type": "mrkdwn"}]}],"channel": "<YOUR_SLACK_CHANNEL_ID>"},"onTimeout": "continue","onFailure": "continue"},"variables": {"slack_ok": "{{ .result.response.data.ok }}","slack_error": "{{ .result.response.data.error // \"\" }}"},"verbose": true}],"connections": [{"sourceIdentifier": "weekly_trigger","targetIdentifier": "assess"},{"sourceIdentifier": "trigger","targetIdentifier": "assess"},{"sourceIdentifier": "assess","targetIdentifier": "persist_pulse"},{"sourceIdentifier": "persist_pulse","targetIdentifier": "assessment_outcome"},{"sourceIdentifier": "assessment_outcome","targetIdentifier": "persist_priorities","sourceOutletIdentifier": "recommendation_ready"},{"sourceIdentifier": "persist_priorities","targetIdentifier": "notify_brief"},{"sourceIdentifier": "assessment_outcome","targetIdentifier": "notify_brief","sourceOutletIdentifier": "no_action_needed"},{"sourceIdentifier": "assessment_outcome","targetIdentifier": "notify_brief","sourceOutletIdentifier": "insufficient_data"},{"sourceIdentifier": "assessment_outcome","targetIdentifier": "notify_brief","fallback": true}]} -
Click Apply changes
Two triggers feed the same assessment node: a schedule trigger on 0 9 * * 1 for the weekly run, and a self-service trigger for running the assessment on demand. To change the cadence, edit cron on the weekly_trigger node.
After publishing, the workflow canvas should show seven nodes and a Run assessment button on the self-service trigger.
Step 6: Run the assessmentโ
We trigger the first run manually, then check what it produced.
- Open the workflow and run the Run assessment trigger.
- Open the Engineering Intelligence Pulse Run entity it created.
- Review the Engineering Opportunity entities from the run, and confirm the brief arrived in Slack.
The brief in Slack should look like this, with the executive summary and headline metrics above the ranked priorities:
Each priority carries its domain, priority, and confidence, followed by why it ranked where it did, the evidence behind it, and the next step for the owning team. The coverage limitations line is expected on most runs and records what the agent could not read.
A status of Insufficient data means the agent could not gather enough evidence to judge, not that the workflow failed.
Once the output looks right, the schedule trigger takes over and the assessment runs every Monday.