The problem: commissioning reports are a multi-system coordination nightmare
A typical BESS commissioning workflow spans Procore for inspection records, punch lists, submittals, and RFIs; SharePoint for the project document library and report templates; protection relay configuration files exported from relay configuration software; and email or Teams for engineer review and sign-off.
For a 50MW BESS project, a single commissioning package might include 120+ individual inspection records logged in Procore, 40+ protection relay settings sheets, cross-references to 200+ design submittals, and sign-off requirements from 3-5 senior engineers. A commissioning engineer manually executing this workflow makes 400-600 discrete decisions. At 4-6 hours per package, this is the single largest source of non-billable engineering time on a typical capital project.
Why Procore is the right data source for this workflow
Procore is the system of record for construction-phase project data on most large capital projects: inspection records, quality checklists, punch list items, submittals, and RFIs all live inside it. For commissioning workflows, this means the source of truth for test completion status, NCR records, and outstanding items is Procore, not a spreadsheet or a document folder.
The Procore REST API provides structured, paginated access to all of these resources with project-scoped authentication via OAuth 2.0. Agento's Procore connector authenticates once per project context and holds a scoped token, no credentials are stored in agent memory, and all access is logged to the RBAC audit layer.
The Agento architecture for this workflow
The BESS commissioning automation runs on four coordinated agents within the Agento Kernel, orchestrated by a single Temporal workflow definition.
Agent 1: Retrieval Agent (Procore connector)
The retrieval agent authenticates to Procore via OAuth 2.0, scoped to the project context. It queries the Procore Inspections API for completed inspection templates tagged to the BESS commissioning scope, fetches associated checklist items and pass/fail results, retrieves linked submittals for the relevant equipment IDs, and pulls any open punch list items against the BESS scope to flag for the validation agent.
# Agento Procore Connector, retrieval activity
from agento.connectors.procore import ProcoreClient
@activity.defn
async def retrieve_procore_commissioning_data(input: RetrievalInput):
client = ProcoreClient(
project_id=input.project_id,
oauth_token=await vault.get_token("procore", input.project_id)
)
# Pull completed inspections for BESS scope
inspections = await client.inspections.list(
filters={
"status": "completed",
"inspection_type": "commissioning",
"trade": "BESS",
"completed_after": input.cutoff_date
}
)
# Fetch checklist items for each inspection
records = []
for insp in inspections:
items = await client.inspections.checklist_items(insp["id"])
records.append({
"inspection_id": insp["id"],
"equipment_tag": insp["custom_fields"]["equipment_tag"],
"completed_by": insp["completed_by"]["name"],
"witness": insp["custom_fields"]["witness_name"],
"items": items
})
# Pull open punch list items against BESS scope
punch_items = await client.punch_items.list(
filters={"status": "open", "trade": "BESS"}
)
return CommissioningPayload(records=records,
open_punch_items=punch_items)A typical retrieval for a 50MW BESS package returns 120-150 inspection records and 8-20 checklist items per inspection. The agent batches requests using Procore's pagination API and resolves all records in 45-90 seconds.
Agent 2: Validation Agent
The validation agent cross-references Procore inspection results against the protection settings schedule (from SharePoint, filtered by equipment ID and revision status = "current") and the project specification for acceptance criteria. Validation logic is defined in configuration, not hardcoded. Engineering teams update rules without a developer:
validation_rules:
overcurrent_pickup:
source: protection_settings_schedule
field: "OC Pickup (pu)"
tolerance: ±0.05
on_fail: flag_for_review
trip_time_50ms:
source: project_spec
section: "8.3.2 Protection Relay Acceptance Criteria"
max_value: 55
unit: ms
on_fail: block_and_notify
open_punch_items:
source: procore_punch_list
condition: count == 0
on_fail: block_and_notify
message: "Outstanding punch list items must be closed before commissioning report is issued"Failures are classified as flag_for_review (logged, included in report with engineer comment required, but doesn't block routing) or block_and_notify (workflow pauses, engineer notified via Teams webhook, resumes on engineer action). Open Procore punch list items always trigger block_and_notify: a commissioning report cannot be issued while punch items remain open.
Agent 3: Report Generation Agent
The report generation agent retrieves the current commissioning report template from SharePoint (version-locked to the project template revision), populates all structured data fields using an explicit template mapping sourced entirely from the Procore payload and validation results, generates a narrative summary section using the language model constrained to validated payload data only, and produces a draft DOCX with tracked-changes markup for any flagged fields.
template_mapping:
# Procore inspection data → report cells
- cell: "B12"
source: procore.inspection.overcurrent_pickup_result
format: "PASS/FAIL"
- cell: "C12"
source: protection_settings_schedule.OC_Pickup_pu
format: "0.00"
- cell: "D12"
source: procore.inspection.overcurrent_pickup_measured
format: "0.00"
- cell: "E8"
source: procore.inspection.completed_by
format: string
- cell: "E9"
source: procore.inspection.witness_name
format: string
- cell: "F3"
source: procore.inspection.completed_at
format: "DD MMM YYYY"
# Punch list status summary
- cell: "B45"
source: procore.punch_items.open_count
format: integer
highlight_if_nonzero: trueAgent 4: Approval Routing Agent
The approval routing agent checks the project approval matrix in SharePoint, creates a submittal in Procore (so the approved commissioning report lives inside the project's document control system alongside all other submittals), sends a structured Teams notification with a one-click approve/reject/comment action, and monitors for response via webhook. If no response in 48 hours, it escalates to the project manager per the escalation config.
Creating the approval as a Procore submittal, rather than just an email thread, means the approved report is automatically linked to the relevant inspection records, equipment tags, and the project's submittal log. This satisfies client and certifier requirements without any additional document control effort.
The Temporal workflow: how it all holds together
@workflow.defn
class BESSCommissioningWorkflow:
@workflow.run
async def run(self, input: CommissioningInput):
# Step 1: Retrieve from Procore
payload = await workflow.execute_activity(
retrieve_procore_commissioning_data,
args=[input.project_id, input.equipment_scope],
start_to_close_timeout=timedelta(minutes=5),
retry_policy=RetryPolicy(maximum_attempts=3)
)
# Step 2: Validate against specs
validation = await workflow.execute_activity(
validate_commissioning_data,
args=[payload, input.validation_rules],
start_to_close_timeout=timedelta(minutes=3)
)
# Step 3: Block if open punch items or spec failures
if validation.has_blocks:
await workflow.wait_condition(
lambda: self.engineer_reviewed,
timeout=timedelta(hours=48)
)
# Step 4: Generate commissioning report
report = await workflow.execute_activity(
generate_commissioning_report,
args=[payload, validation, input.template_id],
start_to_close_timeout=timedelta(minutes=10)
)
# Step 5: Create Procore submittal + route for approval
submittal_id = await workflow.execute_activity(
create_procore_submittal_and_route,
args=[report, input.project_id,
input.approval_matrix_id]
)
return CommissioningResult(
report_id=report.id,
procore_submittal_id=submittal_id,
audit_trail=workflow.info().workflow_id
)Every activity execution, including every Procore API call, is logged to the Temporal workflow history, providing an immutable audit trail that satisfies internal QA and external client and certifier requirements.
Results
| Metric | Before Agento | After Agento |
|---|---|---|
| Time per commissioning package | 4-6 hours | 8-12 minutes |
| Manual data entry errors | 3-7 per package | 0 |
| Procore submittal creation | Manual, post-approval | Automatic, at routing |
| Open punch item check | Manual review before issue | Automated gate that blocks if open |
| Audit trail completeness | Email threads + Procore comments | Full Temporal history + Procore submittal log |
| Engineer hours reclaimed per project | N/A | 40-60 hours |
What this is not
Not screen-scraping Procore. Every integration uses the Procore REST API with OAuth 2.0 authentication, proper pagination, and structured error handling.
Not a rigid pre-built integration. Validation rules, template mappings, and approval matrices are defined in configuration. Engineering teams modify them without a developer.
Not a one-way data pull. The workflow writes back to Procore, creating a submittal record, linking it to inspection records, and updating the submittal log. Procore remains the system of record.
This is AI orchestration: a governed, auditable, configurable system that coordinates multiple agents across Procore and your document stack to execute a complex commissioning workflow end-to-end, reading from Procore, validating, generating, and writing back.
