Skip to content
Automation
Skill

/tag-audit-and-takeoff

Count-based quantity takeoff and tag completeness auditing for construction drawings. Vision + OCR reconciliation, sheet markup, Excel QTO output. Triggers: 'tag audit', 'quantity takeoff', 'QTO', 'count fixtures'.

From plugin
claude-code-construction
3813 skills
Install
$ npx -y skills add dleerdefi/claude-code-construction --skill tag-audit-and-takeoff --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/tag-audit-and-takeoff

Context preview

The summary Claude sees to decide when to auto-load this skill.

Count-based quantity takeoff and tag completeness auditing for construction drawings. Vision + OCR reconciliation, sheet markup, Excel QTO output. Triggers: 'tag audit', 'quantity takeoff', 'QTO', 'count fixtures'.

SKILL.md

tag-audit-and-takeoff.SKILL.md
name: tag-audit-and-takeoff
description: >
  Count-based quantity takeoff and tag completeness auditing for construction
  drawings. Vision + OCR reconciliation, sheet markup, Excel QTO output.
  Triggers: 'tag audit', 'quantity takeoff', 'QTO', 'count fixtures'.
disable-model-invocation: true

Tag Audit & Quantity Takeoff

Purpose

Count-based QTO for tagged construction elements — fixtures, devices, doors, equipment, and any element identified by a tag/symbol on drawings. Does NOT do area (sqft) or linear (lf) takeoffs — only discrete counts.

The QTO is a byproduct of the audit. The real value: the completeness engine that finds what's tagged, what's missing, and produces a defensible count with full provenance for every number.

Does NOT: do area/linear takeoffs, create outbound documents autonomously, override user-approved groupings, or assume quantities without provenance.

---

Step 0: Detect Operating Mode

Check for `.construction/` directory at the project root.

**AgentCM mode** (`.construction/` exists):

  • Read `.construction/CLAUDE.md` for project context
  • Read `.construction/database.yaml` for `query_command` and `project_id`
  • Sheet images at `.construction/rasters/{sheet_number}.png`

**Verify raster images exist:** Check `.construction/rasters/` for PNG files. If empty, tell the user: "Raster images not found. Open this project in AgentCM to trigger the export, or run: `curl -s -X POST '{api_url}/projects/{project_id}/graph/export' -H 'Content-Type: application/json' -d '{\"rootPath\": \"'$(pwd)'\"}'`" You can also rasterize individual sheets on demand using the rasterize_page.py script.

  • OCR data queryable via `extracted_items` table in PostgreSQL
  • Write results back via API: `POST /api/projects/{id}/tag-detections/ingest`

**Flat File mode** (no `.construction/`):

  • Discover sheet images from CLAUDE.md or user-provided paths
  • Vision-only pipeline (Steps 2-3 skipped)
  • Write marked-up PNGs and QTO JSON to project directory

Step 1: User Scopes the Task

User provides: (1) tag type — e.g., "plumbing fixtures", "doors", "light fixtures" (see `references/tag-types.md` for full list), and (2) sheet scope — specific sheets, a discipline, or "all sheets". Confirm scope before proceeding.

**Custom tag types:** If the user requests a tag type not in `references/tag-types.md` (e.g., "keynote legends", "fire dampers", "seismic bracing"), treat it as a custom type. Use it in the `tag_type` field at ingest — the server auto-registers unknown types in the `tag_types` table with default styling. The normalized name will be `qto_{type}` (e.g., `qto_keynote_legend`). Custom types appear in the Group Review gallery and support the full accept/reject/promote workflow.

**REQUIRED: Tag type resolution.** Before using any `tag_type` value, you MUST resolve it against existing types:

1. Query `GET /api/projects/{id}/group-review/available-types` to see all active tag types for this project 2. Check if the user's requested type matches ANY existing type name 3. Apply alias resolution — these names are synonyms of existing types:

  • `detail_callout`, `section_callout`, `interior_elevation`,

`callout_single_ref`, `single_ref_callout` → `simple_callout`

  • `multi_callout`, `callout_multi_ref`, `multi_ref_callout`

→ `multi_detail_callout` 4. If the resolved type exists in available-types, USE THAT NAME 5. Report to user: "Resolved type: '{resolved_name}' (matched from '{user_input}')" — get confirmation before proceeding 6. **If there is ANY ambiguity** about whether a requested tag type maps to an existing type, **ASK THE USER** before proceeding. Do not guess or invent a new type name. 7. Only auto-register a truly new type if no existing type or alias matches after checking both the available-types list and the alias map above

NEVER invent a new type name for concepts that already have canonical types. When in doubt, ask.

Step 1.5: Check Existing Coverage [REQUIRED GATE] (AgentCM mode only)

**HARD GATE — you MUST complete this step before proceeding to Step 2.** Do not skip this step. If the API is unreachable, stop and tell the user.

Before scanning sheets, query what's already tagged per sheet:

curl -s "http://localhost:3001/api/projects/{project_id}/sheets/{sheet_id}/claimed-elements"

Response:

{
  "claimed_element_ids": ["el_001", "el_002", ...],
  "suggestion_count": 12,
  "by_type": { "qto_room_tag": 8, "room_tag": 4 },
  "existing_tags": [
    { "id": "...", "proposedType": "qto_room_tag", "proposedText": "KITCHEN",
      "status": "accepted", "constituentIds": [...], "combinedBbox": {...}, "confidence": 0.92 }
  ]
}

Report to user: "Sheet A-1.4: 12 tags already detected (8 accepted, 4 pending)."

**Reconciliation rules:**

  • **EXCLUDE** claimed element IDs from spatial queries (Steps 3-4) —

add `AND id NOT IN ('{id1}', '{id2}', ...)` to SQL WHERE clauses

  • **INCLUDE** `existing_tags` in the final QTO output — the QTO captures

ALL items (existing + newly detected), not just new ones

  • During vision (Step 2), note tags that match existing `proposedText`

values — these are "confirmed" not "new"

  • New detections that survive dedup → POST to ingest as usual
  • The server also deduplicates at ingest: detections with element IDs

overlapping existing suggestions are skipped (safety net)

  • Final QTO JSON must merge: `existing_tags` (from this endpoint) +

newly detected (from ingest response)

**The QTO is always a complete count.** Reconciliation avoids redundant detection *work*, not redundant *output*.

**Before proceeding to Step 2, report coverage and get confirmation:** "Existing coverage: {N} sheets have {M} accepted, {P} pending detections for this tag type. {Q} sheets have zero coverage. Proceed with vision scan on {Q} uncovered sheets?" Wait for explicit user confirmation before continuing.

Step 2: Vision Tag Identification

**CRITICAL — Vision is MANDATORY for this step.**

  • You MU
Read more
Ships withclaude-code-construction

Open-source skills that give Claude Code the working knowledge of a Project Engineer. Split drawings, parse specs, tabulate bids, generate subcontracts, and more — directly from your terminal or IDE.

Get the whole plugin
Stats
38
Stars
11
Forks
Maintained
Maintenance
Python
Language
MIT
License
5mo ago
Last commit
5mo ago
Created

Repo: dleerdefi/claude-code-construction

Other skills on claude-code-construction.