agentsclimarketplace

Tender comparison

Skill deva-ships/tender-tally/tender-comparison

Compare vendor tenders item by item and export a ranked Excel comparison. Claude skill + CLI.

Install
npx -y skills add deva-ships/tender-tally --skill tender-comparison

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 23 days oldThe repository was created 23 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Compare construction, civil, electrical, or interior fit-out tenders item by item and produce a clean Excel comparison. Use when the user has two or more vendor quotes, tenders, quotations, estimates, or BOQ bids (PDF, Excel, Word, or scanned images) for the same building or renovation job and wants to see the lowest rate per line item and the lowest overall vendor. Extracts every item and rate from each vendor, matches items that vendors name or group differently, flags anything a vendor left out, and ranks vendors L1 to Ln with the lowest highlighted.

SKILL.md

7.4 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it

Tender comparison

Turn a pile of vendor tenders for one job into a single Excel file that compares every line item side by side, highlights the lowest rate per item, and ranks the vendors from cheapest to dearest.

The vendors bid on the same work but format their tenders differently. They name items differently, group them differently, and quote in different orders. The job is to line them up item by item, honestly, with nothing dropped.

When to use this

Use this when someone gives you several vendor quotes for the same construction or fit-out job and asks which is cheapest, or asks for an item-by-item comparison, a rate comparison, or a tender analysis. It works for civil work, electrical work, interior furnishing, plumbing, and similar itemised bids.

If there is only one tender, there is nothing to compare. Say so.

What you produce

One .xlsx file. It has a Summary sheet and one comparison sheet per tender. Each comparison sheet has one row per item and, for each vendor, a Rate column and an Amount column. The lowest rate in each row is highlighted green. A totals row, a net payable row, and an L1 to Ln ranking sit at the bottom. This is the required default output.

Setup

The scripts need Python with openpyxl (for Excel) and pymupdf (for reading scanned PDFs).

pip install openpyxl pymupdf

Workflow

Do these steps in order. Do not skip the reading step and do not skip the self-check.

1. Identify the tenders

List the input files. Work out which files are separate tenders and which belong together. Two things to settle first:

  • Separate jobs. One folder can hold more than one job. For example an electrical tender and an interior tender for the same branch are two different item lists. Compare each job on its own sheet. Never mix items from different jobs into one table.
  • Duplicate scans. The same tender is sometimes scanned twice under two file names. Check the vendor name and the rates. If they match, count it once and note the duplicate.

2. Read every tender

Most bank and BOQ tenders are scanned images with no text layer, so text extractors return nothing. Render each page to an image and read it by eye.

python scripts/render_tender.py --indir "input" --outdir "pages" --dpi 200

Then read each page image. If a handwritten rate is hard to read, zoom into that one cell at higher DPI with the --crop option (see reference/extraction.md).

Read the full detail in reference/extraction.md. The short version:

  • Capture the rate for every item from every vendor. Nothing skipped.
  • After reading a tender, cross-check it: the sum of (rate x quantity) for all items should equal the grand total written on that tender. If it does not, find out why before moving on. A mismatch is either your misread or a slip in the vendor's own arithmetic. Both need to be understood, not guessed.

3. Build one canonical item list and match every vendor to it

Read reference/item-matching.md for how to match items that are named or grouped differently.

Build a single master list of items for each job. Then map each vendor's quoted rate onto the matching master item. Many public tenders are pre-printed, so every vendor bids on the same fixed item list in the same order, which makes matching a question of position. Free-form quotes need matching by description, size, and unit.

If a vendor did not quote an item, record it as not quoted. Do not treat a blank as zero and do not drop the item.

4. Write a tender JSON for each job

Put the master list and every vendor's rates into one JSON file per job, in the schema shown in examples/electrical.json and examples/interior.json. The schema is documented in reference/output-format.md.

5. Cross-check the JSON (stop gate)

python scripts/cross_check.py job1.json job2.json

This adds up rate times quantity for each vendor and compares it to the grand total that vendor wrote. It is the main guard against a misread rate.

Stop gate: do not go to step 6 until it prints CROSS-CHECK PASSED. If it reports an UNEXPLAINED discrepancy, you misread a number. Re-read that tender, zoom into the suspect cell, and fix the JSON. If the difference is a genuine slip in the vendor's own arithmetic, confirm it by eye, then add a total_note to that vendor in the JSON to record the reason. See reference/edge-cases.md.

6. Build the Excel file

python scripts/build_comparison.py --out "Tender Comparison.xlsx" job1.json job2.json

7. Self-check before you hand it over (stop gate)

python scripts/self_check.py --xlsx "Tender Comparison.xlsx" job1.json job2.json

This re-reads the saved file and confirms: every item is present once, every amount equals rate times quantity, every green highlight is the true lowest, the net payable formulas are right, and the ranking is correct.

Stop gate: do not present the file until it prints ALL CHECKS PASSED. If it reports a vendor arithmetic slip as info, that is expected when a total_note is set. Add a matching note to the sheet.

8. Report the result

Tell the user, per job, who is L1 (lowest overall) and by how much they beat L2. Point out any items where the overall lowest vendor is not the cheapest, since a client may still split the award. Mention anything you flagged: missing items, discounts, credits, duplicate files, arithmetic slips.

Hard rules

  • Nothing is dropped and nothing is silently ignored. Every item from every vendor is on the sheet. A missing quote is flagged, not hidden.
  • Every number is traceable to a tender. Do not invent or round rates.
  • Cross-check each vendor's total against their own stated total. Explain any difference.
  • The quoted rate governs. If a vendor's own total is miscalculated, the rate is the truth and the corrected total is used, with a note.
  • Read the edge cases in reference/edge-cases.md: blanket discounts, buyback credits (negative amounts), duplicate scans, arithmetic slips, missing items, and quantities that differ between vendors.

Scripts

  • scripts/render_tender.py - render tender PDFs to page images, or zoom into one cell.
  • scripts/cross_check.py - step 5 gate. Ties each vendor's rates to their stated total. Run on the JSON before building.
  • scripts/build_comparison.py - step 6. Turns the tender JSON into the formatted Excel file.
  • scripts/self_check.py - step 7 gate. Validates the built workbook against the JSON.

Reference files

  • reference/extraction.md - reading scanned tenders, zooming into cells, the total cross-check.
  • reference/item-matching.md - matching items that vendors name or group differently.
  • reference/output-format.md - the JSON schema and the exact Excel layout.
  • reference/edge-cases.md - discounts, credits, duplicates, slips, missing items, mismatched quantities.
  • examples/ - a full worked pair of tender JSON files (electrical and interior) you can copy.

What ships with it: 12 files

90.2 KB alongside SKILL.md, 4 of them executable

scripts/

Gives 0 of the 12 instructions most pdf office docs skills give in ~1.6k tokens

Counted across 636 of the 690 authors here whose files we hold, read 2026-08-07

  • extract text using pdfplumberin 89 of 636, across 23 files
  • create PDFs using reportlabin 83 of 636, across 16 files
  • read forms.md to fill out pdf formsin 80 of 636, across 13 files
  • OCR scanned PDFs using pytesseractin 77 of 636, across 10 files
  • merge or split PDFs using qpdfin 70 of 636, across 3 files
  • use excel formulas instead of hardcoded calculated valuesin 68 of 636, across 13 files
  • unpack edit xml and repack existing documentsin 63 of 636, across 8 files
  • document sources for hardcoded valuesin 61 of 636, across 9 files
  • write minimal python code without unnecessary commentsin 59 of 636, across 7 files
  • run the recalculation script after adding or modifying formulasin 59 of 636, across 7 files
  • fix all identified formula errors and recalculatein 58 of 636, across 6 files
  • format years as text stringsin 57 of 636, across 5 files

Said here and by no other author read

  • produce one xlsx file with a summary sheet
  • highlight the lowest rate per item green
  • rank vendors from cheapest to dearest
  • render scanned tenders to images for reading
  • read every rate from every vendor
  • build one canonical item list per job

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.