Bid Evaluator
Evaluate tabulated subcontractor bids against construction documents.
This skill does NOT make the award decision — it builds the analytical
foundation so the PE/PM can decide quickly and confidently.
Pipeline & Disambiguation
/bid-tabulator → THIS SKILL → user confirms → /subcontract-writer
This skill requires tabulated bids as input. If the user has raw bid PDFs that haven't been tabulated yet, stop and ask them to run /construction:bid-tabulator first; it is user-invoked only, so you cannot start it from here. It produces the per-bidder JSON files and comparison Excel that this skill consumes.
- User has bid PDFs → ask them to run
/construction:bid-tabulator (data capture), then /construction:bid-evaluator
- User has tabulated bids and wants analysis → this skill directly
- User says "compare bids" or "buyout" → check if bids are already tabulated; if not, ask them to run
/construction:bid-tabulator first
Tier System
- RIGID: Output schema, scoring tables, file naming
- GUIDED: Dialogue sequencing, scope assembly, scoring thresholds
- FLEXIBLE: Bid interpretation, scope coverage, risk assessment
Required Inputs
- Tabulated bids (from /bid-tabulator or equivalent)
- Relevant specification sections
- Relevant drawing sheets (Claude reviews via vision)
- Scope context (from user dialogue)
Optional: bid form/ITB, schedule, owner requirements, budget estimate,
past experience with bidders.
Step 1: Scope Assembly
Complete before analyzing any bids.
Mode Detection
Read .construction/project.yaml at the project root: present and readable means AgentCM mode (note its contract_version), absent means flat-file mode. A listing that shows the file does not decide it: read it.
- AgentCM mode: Read each spec section from
.construction/specs/<section>.txt (09 65 13 is 09-65-13.txt; each line starts with its page), listed in .construction/INDEX.md: it is the section's text, and a section's pages are never extracted again from the PDF. Never run pdf_text.py or rasterize_page.py on a section's pages: not to check them, and not inside a page range (--pages 1,2 where page 2 is a section is one). A read manual's pages in no section (INDEX.md lists them) are read in the PDF, those pages only (--pages). Only for a manual INDEX.md lists under "Spec manuals not read", read spec-splitter's .construction/skills/spec_text/ instead. Use sheet index from .construction/index/sheet_index.yaml for drawing identification. Follow ${CLAUDE_PLUGIN_ROOT}/reference/agentcm-mode.md: which source wins, what a missing file or an empty search means, which file answers what, drawings through crop.sh, sheet ids, and how to record a correction of AgentCM's data.
- Flat File mode: Discover spec PDFs via
CLAUDE.md paths or directory search (Specifications/, Specification Sections/). Read drawing sheets directly from PDF.
1a. Spec Review
Extract from each spec section: work included (Parts 1-3), work by
others (GC/NIC/Owner), related section cross-references, performance
requirements, coordination and temporary requirements.
This step is never skipped. The spec sections are the baseline that
SILENT is measured against; a scope sheet lists sections, not their
requirements, and "no drawing review" does not mean "no spec review".
In flat-file mode dump each section's text (TEXT pages in the dump are
read as text; rasterize VISION pages):
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_PLUGIN_ROOT}/scripts/pdf/pdf_text.py" "{section.pdf}"
Take the output directly, or, to search a dump more than once, save it with
--output ".construction/skills/bid-evaluator/text/<section>.txt", never in
/tmp or any other folder outside the project.
1b. Drawing Review
Load references/drawing-review.md for guidance on what to look for
per drawing type. Vision-read key sheets to identify scope items,
conditions, and quantities not apparent from specs. Track drawing-
derived items separately — they differentiate thorough bidders.
Offload reference after completing drawing review.
1c. User Dialogue
Ask targeted questions to fill gaps documents can't answer. Do not
dump a questionnaire — ask conversationally, skip what you already
know.
Always ask: package definition (which specs/drawings), GC-provided
items, bid count and format, drawing confirmation if provided.
Ask when relevant: multi-trade splits, alternates/allowances,
qualification requirements, budget reference, schedule constraints.
Confirm assembled scope with user before proceeding.
1d. Build Scope Baseline
Produce internal baseline document: items in sub scope (with source),
drawing-identified scope, GC/owner exclusions, allowances, alternates,
qualifications, schedule constraints.
Step 2: Bid Analysis
Load references/buyout-domain.md for domain knowledge on bid
language interpretation, common scope splits, red flags, trade-
specific evaluation notes, and non-price factors. Keep loaded
through Steps 2a-2d, then offload.
2a. Normalize Pricing
Adjusted Base = Submitted Base
+ Excluded spec-required items
- Included GC-provided items
+ Accepted alternates ± Allowance adjustments
Valuation order: other bidder's line item → budget estimate → professional
judgment (flagged) → qualitative risk if unknown.
Document every adjustment. No silent price changes.
Flag unit price outliers (>2x median). Calculate exposure ranges.
2b. Scope Coverage Mapping
Map each bidder against every scope baseline item using five statuses:
| Status | Meaning |
|---|
| INCLUDED | Explicitly includes |
| EXCLUDED | Explicitly excludes |
| SILENT | Not addressed — most dangerous |
| PARTIAL | Includes with limitations |
| DIFFERENT | Offers substitution |
Flag all SILENT items on spec-required scope. Drawing-derived SILENT
items suggest incomplete document review by that bidder.
2c. Exclusion Risk Scoring
| Level | Criteria |
|---|
| CRITICAL | Spec-required, uncarried, >1% bid or >$5K |
| SIGNIFICANT | Implied by spec/practice, $2K-$5K |
| MINOR | Common GC-provided, <$2K |
| INFO | Clarification only, no cost impact |
2d. Qualification & Responsibility
Assess per bidder: bonding, insurance, licensing, experience,
capacity, DBE/MBE, bid completeness.
Bust detection: >20-30% below field + scope gaps + incomplete
submission. Flag for verification, never call it a bust.
2e. Responsiveness and the Recommendation
- A curable defect (addenda not acknowledged; an illegible or missing
line that reconciles to the stated total; validity shorter than required;
bond not mentioned where one is required) keeps the bid in the ranking at
its stated price.
- Recommend the apparent low bidder conditionally: each cure is a named
award condition in
recommendation.conditions (written addenda
acknowledgment with no price change; a clean copy of the illegible line;
a validity extension; a bond commitment). Name the next fully responsive
bidder as the fallback and state the spread.
- A figure derived for an illegible line is allowed only when it reconciles
exactly to the stated total, and it is always labelled "derived, confirm",
never presented as read.
- A non-curable defect (budgetary-only pricing; a stale drawing basis the
bidder has not re-confirmed; SILENT spec-required scope the bidder will not
carry) makes the bid "not awardable as submitted"; it is ranked but never
recommended.
Step 3: Output
Build JSON per schema in scripts/sample_input.json with the Write tool
(not a shell heredoc, which fails here on an apostrophe, and not a helper
script) as .construction/skills/bid-evaluator/bid_evaluation.json: it is
working data, never in the project root. Then run:
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_SKILL_DIR}/scripts/export_bid_evaluation.py" .construction/skills/bid-evaluator/bid_evaluation.json "Bid_Evaluation_{package}.xlsx"
Run it from the project folder: the workbook is the deliverable and goes in the project root (or the folder the PE names), never under .construction/, which macOS and Linux hide.
The script produces 5 sheets: Bid Comparison, Price Summary,
Exclusion Detail, Qualification Summary, Recommendation.
Step 4: Handoff
- Lead with the recommendation — don't make them hunt for it
- Highlight items needing PE attention
- Ask for explicit confirmation: selected bidder, scope adjustments,
alternates, special conditions
Do NOT proceed to a subcontract without user confirmation. subcontract-writer is user-invoked only; once the user has confirmed the selected bidder, tell them the next step is /construction:subcontract-writer and stop.
Step 5: Write a Finding
Record the evaluation as a finding in .construction/skills/bid-evaluator/findings/ (both modes):
"${CLAUDE_PLUGIN_ROOT}/bin/construction-python" "${CLAUDE_PLUGIN_ROOT}/scripts/graph/write_finding.py" \
--skill "bid-evaluator" --type "bid_evaluation_complete" \
--title "Bid evaluation: {scope} — {N} bidders, recommended {company}" \
--output-file "Bid_Evaluation_{package}.xlsx" \
--data '{"scope": "...", "bidder_count": N, "recommended": "...", "adjusted_amount": ..., "pe_attention_items": [...]}'
Context Needs Chart
| Step | Resource | Load Trigger | Offload After |
|---|
| 1b | references/drawing-review.md | Drawing sheets provided | Step 1b complete |
| 2 | references/buyout-domain.md | Entering bid analysis | Step 2d complete |
| 3 | scripts/sample_input.json | Building output JSON | Step 3 complete |
| 5 | ${CLAUDE_PLUGIN_ROOT}/scripts/graph/write_finding.py | Step 5 | Step 5 complete |
Gotchas (measured in eval runs)
- Write JSON and YAML with the Write tool.
cat > file <<'EOF' failed with "unexpected EOF while looking for matching '" whenever the content held an apostrophe (3 of 15 runs, 2026-10-04), costing a turn each time.
- Do not write helper scripts or inline
python -c, even to assemble your own JSON or to read a PDF; the allowlisted scripts are the toolkit, and the exporters do the arithmetic checks. If the toolkit lacks something you need, say so in the handoff instead (bid-tabulator and subcontract-writer each wrote a helper script in their 2026-10-04 runs; the eval guard blocked both).
Error Handling
- Uneven formats: note difficulty, don't penalize lump-sum bids
- <3 bids: note limited field, suggest re-bid if appropriate
- Budget mixed with hard bids: segregate with caveat
- Math errors: flag discrepancy, don't correct
- Scope too complex: focus on highest cost-impact items
What This Skill Does NOT Do
- Contact subs, execute awards, or negotiate pricing
- Replace PE judgment on responsibility
- Produce subcontracts (use /subcontract-writer)
- Perform quantity takeoffs from drawings
File Safety
Never overwrite an existing bid evaluation. The export script uses safe_output_path() which appends _v2, _v3, etc. automatically.
Allowed Scripts
${CLAUDE_PLUGIN_ROOT}/bin/construction-python
${CLAUDE_PLUGIN_ROOT}/scripts/pdf/pdf_text.py — spec section and bid text (Step 1a)
${CLAUDE_PLUGIN_ROOT}/scripts/pdf/rasterize_page.py — drawing sheets and VISION pages
${CLAUDE_SKILL_DIR}/scripts/export_bid_evaluation.py
${CLAUDE_PLUGIN_ROOT}/scripts/graph/write_finding.py
${CLAUDE_PLUGIN_ROOT}/scripts/corrections_append.py — AgentCM mode: record a correction of AgentCM's data (reference/agentcm-mode.md)
No other code: no python -c, no helper script. If the toolkit lacks something
you need, say so in the handoff.