Evaluate tabulated subcontractor bids against specs and drawings — scope gap analysis, exclusion risk scoring, award recommendation. Triggers: 'evaluate bids', 'bid evaluation', 'lowest responsible bidder'.
日本語の概要は準備中です。原文の説明を表示しています。
Extract tabular schedule data from construction drawings — door, window, finish, fixture, panel schedules — and output to Excel. Triggers: 'door schedule', 'extract schedule', 'schedule to Excel', 'panel schedule'.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Extracts tabular schedule data embedded in drawing sheets or spec pages and outputs structured Excel files. Schedules are typically one element among many on a sheet — or the entire sheet may be a schedule.
Extraction Progress:
- [ ] Step 1: Discover schedule locations
- [ ] Step 2: Isolate (crop) the schedule region
- [ ] Step 3: Extract structured data (pdfplumber + vision)
- [ ] Step 4: Validate and clean data
- [ ] Step 5: Output to Excel
- [ ] Step 6: Write graph entry
Use a multi-source discovery approach, checking all available sources:
Search .construction/index/sheet_index.yaml (or the sheet index you've built) for sheets with "SCHEDULE" in the title. Many important schedules occupy an entire sheet — the sheet title tells you exactly what it is:
For dedicated schedule sheets, the entire page is the extraction target — no need to crop.
If .construction/database.yaml exists, query known schedules through AgentCM's wrapper:
# project_id is in .construction/database.yaml
sh .construction/query.sh "SELECT id, schedule_type, title, sheet_id, bounding_region FROM schedules WHERE project_id = '{PROJECT_ID}'"
This returns all schedules already detected (including stubs from Group Review with bounding regions). For embedded schedules on non-schedule sheets, check the bounding_region column.
Note: Schedule bounding region detection is still being refined — treat these as hints, not definitive boundaries. Always verify with vision.
Schedules appear on specific sheet types:
If no index or graph is available:
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_PLUGIN_ROOT}/scripts/pdf/rasterize_page.py" "{pdf_path}" {page} --dpi 150 --output full_sheet.png
Use vision on the full sheet image: "Identify any tabular schedules on this drawing sheet. Report the approximate bounding box (top-left x,y and bottom-right x,y) as fractions of the image width and height between 0 and 1, the schedule type, and the column headers visible."
For dedicated schedule sheets (entire page is a schedule): Skip cropping — use the full page.
For embedded schedules (schedule is one element on a larger sheet):
Crop the identified region with padding. The box is the 0–1 fractions from
Step 1, so --normalized is required; without it the script reads the values
as pixels and returns an empty crop:
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_PLUGIN_ROOT}/scripts/pdf/crop_region.py" full_sheet.png \
--box {x1},{y1},{x2},{y2} --normalized \
--padding 20 \
--output schedule_crop.png
Re-rasterize at higher DPI (300) for the cropped region to improve text clarity.
rasterize_page.py --crop takes percentages, so multiply each fraction by 100
(0.62,0.08,0.98,0.45 becomes 62,8,98,45):
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_PLUGIN_ROOT}/scripts/pdf/rasterize_page.py" "{pdf_path}" {page} \
--dpi 300 \
--crop {x1_pct},{y1_pct},{x2_pct},{y2_pct} \
--output schedule_hires.png
Use a try → validate → fallback approach:
Use pdfplumber's extract_tables() method on the target page. If multiple tables are found, select the largest one (most rows with the most columns — schedules are wide). The first row of the selected table contains headers; subsequent rows are data. If no tables are found or results look garbled, fall back to vision (Method B).
Check these criteria before proceeding:
Decision:
QUALITY GATE:
extracted_rows >= 10? YES → check next | NO → use Method B
column_consistency >= 80%? YES → check next | NO → use Method B
non_empty_cells >= 50%? YES → check next | NO → use Method B
first_col_has_valid_ids? YES → use Method A | NO → use Method B
When pdfplumber fails (common with complex layouts, merged cells, non-standard table lines):
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_PLUGIN_ROOT}/scripts/pdf/rasterize_page.py" "{pdf_path}" {page} --dpi 150 --output full_sheet.png
"This is a construction drawing sheet containing a schedule (tabular data). Extract ALL rows from the schedule as a JSON array of objects. The first row of the table contains column headers — use those as object keys. Each subsequent row is one entry. Preserve exact values including dimensions, abbreviations, and codes. If a cell is empty, use null."
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_PLUGIN_ROOT}/scripts/pdf/rasterize_page.py" "{pdf_path}" {page} --dpi 300 --output schedule_hires.png
Run both methods and cross-validate:
After extraction (by either method):
3' - 0" → 3'-0" (remove spaces around dashes).construction/database.yaml exists, verify room numbers via sh .construction/query.sh "SELECT number FROM rooms WHERE project_id = '{PROJECT_ID}' AND number = '{room_number}'" and door numbers via sh .construction/query.sh "SELECT ge.tag_number FROM graph_elements ge JOIN sheets s ON s.id = ge.sheet_id WHERE s.project_id = '{PROJECT_ID}' AND ge.element_type = 'door' AND ge.tag_number = '{door_mark}'""${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_SKILL_DIR}/scripts/schedule_to_xlsx.py" \
--data schedule_data.json \
--type door_schedule \
--project "Project Name" \
--sheet "A-0.01" \
--output "Door_Schedule_A-0.01.xlsx"
The script creates a formatted Excel workbook with:
After Excel output, POST extracted data to the AgentCM schedule ingest API so it's stored in PostgreSQL, linked to rooms, and queryable by agents:
# Read api_url and project_id from .construction/database.yaml
curl -X POST "{api_url}/projects/{project_id}/schedules/ingest" \
-H "Content-Type: application/json" \
-d @schedule_ingest_payload.json
The ingest payload JSON follows this structure:
{
"sheetId": "<uuid of the source sheet>",
"scheduleType": "door",
"title": "DOOR SCHEDULE",
"rowEntityType": "door",
"columns": [
{"key": "MARK", "header": "MARK"},
{"key": "WIDTH", "header": "WIDTH"},
{"key": "HEIGHT", "header": "HEIGHT"},
{"key": "TYPE", "header": "TYPE"},
{"key": "FRAME", "header": "FRAME"},
{"key": "HARDWARE_SET", "header": "HARDWARE SET"},
{"key": "FIRE_RATING", "header": "FIRE RATING"}
],
"rows": [
{
"entityIdentifier": "2.101A",
"cells": {"MARK": "2.101A", "WIDTH": "3'-0\"", "HEIGHT": "7'-0\"", "TYPE": "A", "FRAME": "HM", "HARDWARE_SET": "HW-3", "FIRE_RATING": "1 HR"}
}
],
"sourceMethod": "pdfplumber",
"confidence": 0.95
}
Schedule types and their rowEntityType:
"door" (room derived from door number: "2.101A" → Room 2.101)"window" (room derived from window mark)"room" (entity identifier IS the room number)"equipment""fixture" (room linked spatially from plan tags)The ingest endpoint automatically:
Also write the graph finding entry (for backwards compatibility with existing skills):
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_PLUGIN_ROOT}/scripts/graph/write_finding.py" \
--type "schedule_extracted" \
--title "Door schedule extracted from A-0.01" \
--source-sheet "A-0.01" \
--output-file "Door_Schedule_A-0.01.xlsx" \
--data '{"schedule_type": "door", "row_count": 45, "columns": ["MARK","SIZE","TYPE","FRAME","HARDWARE SET"]}'
When a PE edits an exported Excel schedule and wants changes applied back to the database:
Reconciliation Progress:
- [ ] Step R1: Read metadata from edited Excel
- [ ] Step R2: Compute changeset (diff vs DB)
- [ ] Step R3: POST changeset to reconcile endpoint
- [ ] Step R4: Report summary to user
Exported Excel files contain reconciliation anchors:
_agentcm_meta sheet with schedule_id, schedule_type, sheet_id_row_key column A with entity identifiers (door numbers, room numbers, etc.)If the Excel lacks _agentcm_meta, it was not exported by AgentCM — treat as a fresh import (re-run the extraction workflow above).
Run the diff engine to compare the edited Excel against current DB state:
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_SKILL_DIR}/scripts/xlsx_to_changeset.py" \
--excel "edited_schedule.xlsx" \
--query-wrapper ".construction/query.sh" \
--output changeset.json
The script:
_agentcm_meta → extracts schedule_id_row_key column + all data columns.construction/query.sh# Read api_url and project_id from .construction/database.yaml
curl -X POST "{api_url}/projects/{project_id}/schedules/reconcile" \
-H "Content-Type: application/json" \
-d @changeset.json
The reconcile endpoint applies changes with:
isUserOverride=TRUE — future re-extractions will not overwrite themschedule_change_logThe endpoint returns an ExcelReconcileResult:
{
"rowsUpdated": 3,
"rowsAdded": 1,
"rowsSoftDeleted": 0,
"cellsChanged": 7,
"conflictsCreated": 0,
"columnsAdded": 0,
"columnsHidden": 0,
"errors": []
}
Report the summary to the user. If errors is non-empty, surface those for review.
When exporting schedules for PE review, always include reconciliation anchors:
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_SKILL_DIR}/scripts/schedule_to_xlsx.py" \
--data schedule_data.json \
--type door_schedule \
--project "Project Name" \
--sheet "A-0.01" \
--schedule-id "{schedule_uuid}" \
--sheet-id "{sheet_uuid}" \
--output "Door_Schedule_A-0.01.xlsx"
The --schedule-id and --sheet-id flags embed metadata in the hidden _agentcm_meta sheet, enabling the round-trip reconciliation workflow.
| Type | Common columns | Notes |
|---|---|---|
| Door | Mark, Width, Height, Type, Frame, Hardware Set, Fire Rating | Cross-ref hardware sets with spec 08 71 00 |
| Window | Mark, Width, Height, Type, Glazing, Frame Material | Check for energy code compliance |
| Room Finish | Room #, Name, Floor, Base, North/South/East/West Walls, Ceiling | Finish codes defined in legend |
| Panel | Circuit #, Description, Load (VA), Breaker Size, Phase | Verify total load vs panel capacity |
| Fixture (Plumbing) | Mark, Description, Manufacturer, Model, Connection | Cross-ref with spec Division 22 |
| Equipment (HVAC) | Tag, Description, CFM/BTU, Voltage, Weight | Cross-ref with spec Division 23 |
Never overwrite an existing schedule extraction. The export script uses safe_output_path() which appends _v2, _v3, etc. automatically.
Allowed scripts — exhaustive list. Only execute these scripts during this skill:
${CLAUDE_PLUGIN_ROOT}/scripts/pdf/rasterize_page.py — rasterize PDF pages for vision extraction${CLAUDE_PLUGIN_ROOT}/scripts/pdf/crop_region.py — crop schedule region from full sheet imagescripts/schedule_to_xlsx.py — Excel export with reconciliation anchorsscripts/xlsx_to_changeset.py — diff edited Excel against DB for reconciliation${CLAUDE_PLUGIN_ROOT}/scripts/graph/write_finding.py — graph entry (Step 6)まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Evaluate tabulated subcontractor bids against specs and drawings — scope gap analysis, exclusion risk scoring, award recommendation. Triggers: 'evaluate bids', 'bid evaluation', 'lowest responsible bidder'.
日本語の概要は準備中です。原文の説明を表示しています。
Extract data from subcontractor bid PDFs and produce a comparison spreadsheet. Feeds into /bid-evaluator. Triggers: 'tabulate bids', 'bid comparison', 'compare bids', 'buyout analysis', 'bid tab'.
日本語の概要は準備中です。原文の説明を表示しています。
Scope-specific code gap analysis — extracts referenced codes from project docs, researches what should apply, surfaces the delta. Triggers: 'code research', 'what codes apply', 'code check', 'ADA requirements', 'egress'.
日本語の概要は準備中です。原文の説明を表示しています。
Operating guide for construction project documents — load before reading drawings, specs, schedules, RFIs, submittals or bids. Data-access rules (never read PDFs directly; rasterize first), AgentCM graph-guided vision, drawing and cross-reference conventions, document precedence. Triggers: 'construction project', 'drawings', 'specs', 'sheet', 'RFI', 'submittal'.
日本語の概要は準備中です。原文の説明を表示しています。
Construction document review with PE judgment — RFI research, submittal analysis, coordination checking, scope gap detection. Use when reviewing drawings, specs, submittals, or RFIs. Triggers: 'review', 'coordination', 'what's missing'.
日本語の概要は準備中です。原文の説明を表示しています。
Set up a construction project — inventories files, classifies drawings/specs/schedules/registers, detects AgentCM mode, appends construction context to CLAUDE.md. Triggers: 'set up project', 'construction setup', 'classify documents'.
日本語の概要は準備中です。原文の説明を表示しています。