Files
will 25592fa6c2
ci / test (push) Successful in 6m14s
WillTools 2026-09-09 -- clean snapshot of the development repo for review
History-free snapshot of the private development repository at 77a82eb.
Code, docs and the public catalogue only: no plant or job knowledge
layers, no client, job or producer names (tools/scrub.py clean against
the widened term list; a second word-level grep clean). The intro deck is
left out because its slide images cannot be checked for job drawings.
2026-09-09 08:35:15 -05:00

16 KiB

Installing WillTools

Precast engineering tooling: buttons across four ribbon panels — three modelling/ticketing tools plus Snapshot behind Tools' Modeling pulldown, five set-up commands behind the Config pulldown, two finished and four unfinished analysis tools behind DesignHub, and GOD_MOD — plus a live bridge that lets Claude Code drive a running Revit session. README.md has the table of what each one does.

Developed and exercised on Revit 2025.4 · pyRevit 6.5.3 · IronPython 2.7.12. Everything else in this file is about what to check when one of those differs.


1. Prerequisites

Needed for Notes
Revit 2021 or newer everything see §6 before assuming a version works
pyRevit 4.8 or newer everything https://github.com/pyrevitlabs/pyRevit/releases
Python 3.9+ on the host tools/*.py, panellift not needed to use the ribbon buttons themselves
Claude Code CLI GOD_MOD button only optional — every engineering button runs without it

No button that does engineering work needs the CLI, the network or the bridge. Design Extract reads a design packet in-process with a regex/geometry parser and never leaves Revit. GOD_MOD is the only button that launches the CLI, and it is the developer button.

The Windows Store Python trap

If python at a terminal prints something like "Python was not found; run without arguments to install from the Microsoft Store" and then exits non-zero, that is not really Python — it is a stub Windows ships in WindowsApps that only exists to point you at the Store. Every command in this file, and tools/setup_machine.py itself, will fail in confusing ways if that stub is what python resolves to.

Fix: install Python from https://www.python.org/downloads/ (check "Add python.exe to PATH" during setup), then open a new terminal and confirm with python --version — it should print a real version number, not a Store prompt. If both a real install and the Store stub are on PATH, the Store one usually wins unless you reorder PATH or use the py launcher instead (py -3 tools/setup_machine.py).

2. Install

  1. Clone or unzip anywhere you can write to. A checkout under your user folder is easiest. The path is not hardcoded anywhere; the buttons find the folder relative to themselves.

    git clone https://github.com/will123song/pyrevit-dev.git
    cd pyrevit-dev
    
  2. Run the setup script. It installs the host-side Python dependencies (requirements.txt: PyYAML, pytest, pymupdf) and then proves the install rather than just reporting exit codes — it runs panellift against a published worked example and checks the computed stress against the number the article prints.

    python tools/setup_machine.py
    

    Read the output top to bottom. PASS and SKIP lines need nothing from you; a SKIP is a deliberate non-answer (this distribution ships no knowledge layers, so the checks that need one stand down cleanly — see knowledge/README.md), not a problem. A FAIL line names what broke and what to try — fix the first one and re-run; failures often cascade from one root cause. Re-run any time with --check to just re-verify without changing anything:

    python tools/setup_machine.py --check
    
  3. Register the folder with pyRevit. pyRevit tab → Settings → Custom Extension Directories → add the folder that contains WillTools.extension (the cloned folder itself, not the .extension folder inside it) → Save Settings.

    Equivalent to this in %APPDATA%\pyRevit\pyRevit_config.ini:

    [core]
    userextensions = ["C:\\path\\to\\pyrevit-dev"]
    
  4. Turn on the routes server — only if you want the Claude Code bridge (GOD_MOD). pyRevit → Settings → Routes → enable, port 48884. Or:

    [routes]
    enabled = true
    port = 48884
    host = "127.0.0.1"
    
  5. Restart Revit. Not "pyRevit → Reload" — see §7.

A WillTools tab appears with four panels, left to right:

Panel
Tools one button, Modeling, with a dropdown arrow (Reinforce Suggestion, Reinforcing QC, Ticket QC), plus Snapshot as a large button beside it.
Setup one button, Config, with a dropdown arrow: Project Config, Design Extract, Self Check, Job Recon, Takeoff.
Design one button, DesignHub, with a dropdown arrow: Panel Lift Check and Panel Analysis (finished), then Beam Analysis, Connection Analysis, Gravity and Lateral, marked (WIP).
Lab GOD_MOD, the CLI button.

3. Check the install

Open a model and press Self Check. It probes every assumption these tools make — Revit version, pyRevit version, Python engine, routes, library imports, unit conversion, whether the CLI is findable, where the data folder resolved to, whether a published checklist is available, and whether this model actually follows the naming conventions the checks depend on — and prints each as OK / WARN / FAIL.

Read the FAILs top-down; they cascade. A WARN never blocks a run, and on a knowledge-less install several rows are expected to read WARN — that is the "checks stand down" state, not a broken install.

4. Try it with no Revit at all

python -m panellift examples/example-panel.job.json -o report.html

That runs the PCI Chapter 8 handling check against a published worked example (the ASPIRE Winter 2019 article) and writes an HTML report. It needs no Revit, no model, and no knowledge layer — a good first thing to run right after tools/setup_machine.py to confirm the arithmetic reaches you intact.

5. Using it on a real job

Per model, in order:

  1. Extract Design — pick the design summaries, one extraction terminal opens per design, each writes specs/<DESIGN>.json.
  2. Read the spec. It is JSON on purpose. Fix anything wrong and fill in source.reviewed_by. Nothing downstream questions the spec again.
  3. Ticket QC — checks every piece of those designs against the spec. Needs a knowledge layer with the published checklist — see below; without one it refuses to open with a one-line reason.
  4. Edit the knowledge.yaml files as you learn the job — see the layers below for which one. They are re-read on every run — no restart needed for knowledge or spec edits.

Everything lands in _ticketqc/ beside the model file:

<model folder>/_ticketqc/
    evidence/<DESIGN>.json   raw scrape, no interpretation
    specs/<DESIGN>.json      the reviewable spec   <-- read this
    knowledge.yaml           your hand-written rules
    log/<DESIGN>.txt         what the extractor printed

If the model is not saved, or its folder is read-only, it falls back to %APPDATA%\pyrevit-ticketqc\<model title>\. Self Check tells you which.

The knowledge layers, and why this distribution has none of them

Knowledge is not one file. It is read in layers, each overriding the one before it key by key, and the split is by how long the fact stays true:

layer where what belongs there
defaults lib/vibe/knowledge.py — in this repo what the code assumes when nobody has said
catalogue knowledge/catalogue.yaml — not shipped published hardware ratings, plus the master shop-ticket checklist
plant %APPDATA%\WillTools\knowledge.yaml — not shipped naming conventions, casting-bed rails, parameter names, which catalogue item each part number is, rigging mode and dunnage position
job <model folder>/_ticketqc/knowledge.yaml — not shipped tolerances, and anything where this job departs from the plant
project config wherever you put it — see below the whole configuration, pinned to one job

This distribution ships none of the last four, deliberately — see knowledge/README.md and knowledge/catalogue.yaml.template for the shape of what a real layer looks like, with every value blanked out. Everything on Tools and Setup except Ticket QC runs without one, reading only knowledge.DEFAULTS; Self Check reports every plant-specific parameter role as unmapped until real layers are wired in. Ask the owner for real layers when you have a job to run for real — see the README's "What to ask the owner for."

Copying a job file forward to the next job should be nearly empty work — if you find yourself copying a lot, it belongs in the plant layer. Set WILLTOOLS_KNOWLEDGE to a full path to put the plant layer on a share so a whole office reads one file. (tools/setup_machine.py deliberately leaves this variable unset on a knowledge-less install — see its own comments if you are wiring one in by hand rather than through the script.)

Handling decisions are plant knowledge too: handling.stages[].rig_mode (rolling or static, blank inherits the global mode) and handling.dunnage.mode (lifter_rows or fraction, with fraction such as 0.2 for supports at 0.2L from each end). A plant that has not set dunnage still gets transportation as a lift, and the report labels it as approximate.

Self Check prints which layers it found, and lists any parameter role still unmapped.

Pinning a configuration to a job

The Project Config button writes every layer above, merged, into one file wherever you choose — the job folder on the share, usually, next to the rest of the job's paperwork. From then on the model runs on that file, and it is the last word: edit it and the next run uses what you wrote.

A one-line pointer at <model folder>/_ticketqc/active-config.txt records where the file went. Press the button again to refresh the file from the layers underneath, or to drop back to them.

Two things to know before you use it:

  • It freezes the plant layer. The merged copy in the file contains the plant's settings as values of its own, so while the file is live, fixing something in the plant file no longer reaches this job. That is the point of pinning, and it is also how a plant-wide correction quietly fails to arrive.
  • Do not move or delete the file without clearing the pointer. Every button refuses to run rather than falling back, because a run on the layered files when you meant the pinned ones looks entirely normal and is not the configuration you set.

A new model has no pointer, so it starts from the layered files and gets its own configuration the first time the button is pressed there.

Nothing is hard-coded, including public facts

The obvious things stay out of the code: client names, job names, parameter names. Less obviously, so do facts that are perfectly public. A lifting insert's rated working load is printed in the manufacturer's catalogue and is no secret — but written into a .py file it becomes a number nobody can correct without a release, and it will be wrong eventually.

So a rating is a lookup, and it takes two hops, because a plant models its own part number rather than the manufacturer's designation:

family name in the model
    -> lifters.catalogue_alias    plant layer:  P000 -> SAMPLE_ANCHOR_4T
    -> catalogue.inserts          product data: SAMPLE_ANCHOR_4T -> 8000 lb

Each hop fails differently and is fixed in a different place, so the check says which one is missing rather than reporting a bare "unknown". The same shape applies to anything else with a published number behind a local name.

6. A different Revit version

The code is written against the stable parts of the API and guards the two places Autodesk moved the floor:

  • UnitTypeId (Revit 2021+) with a DisplayUnitType fallback for 2020 and older, resolved once at import so an old host cannot break the whole library.
  • ElementId.IntegerValue → .Value (Revit 2024+), read defensively at every site.

Also version-proofed: the /exec snippet namespace skips API types that a given release does not have, rather than failing to register.

Not verified anywhere but 2025. If you move to 2023 or 2026, press Self Check first — it reports the host version as a WARN and exercises the imports and a unit round-trip, which is where a version problem shows up first.

A different Python engine

pyRevit chooses the interpreter. This extension is written in the intersection of Python 2 and 3 — no f-strings, no print statement, no implicit integer division, no pathlib, and unicode/basestring resolved in lib/vibe/compat.py — so IronPython 2.7, IronPython 3 and CPython 3 should all load it. Only IronPython 2.7 has actually been run in anger; Self Check warns on anything else.

7. The one rule

Never use pyRevit → Reload. Restart Revit.

pyRevit's routes handler is owned by the engine that first loaded it. A reload tears that engine down and leaves the handler pointing at the corpse; the next bridge request runs against a dead engine and takes Revit down with it — an unhandled exception off the main thread, which Revit cannot catch.

There is no reload endpoint, rvt.py refuses to run after it sees two loads in one Revit process, and a restart picks up new buttons just as well.

Restart Revit after: installing, adding or renaming a button, or adding an icon. No restart needed after: editing a script.py, a spec, or knowledge.yaml.

8. What is in this distribution

pyrevit-dev/
├── INSTALL.md                    this file
├── README.md                     what the tool is, what needs knowledge
├── CONTRIBUTING.md                tests, the no-client-data rule, PRs
├── examples/example-panel.job.json  a published worked example, try this first
├── docs/                         reference material and design docs
├── knowledge/README.md           why this folder is otherwise empty
├── knowledge/catalogue.yaml.template  the shape of the layer that isn't here
├── tools/setup_machine.py        run this first
├── tools/rvt.py                  bridge client (host CPython 3)
├── panellift/                    the handling-check engine, its own test suite
└── WillTools.extension/
    ├── startup.py                registers the bridge routes
    ├── lib/vibe/                 helpers, compat, designspec, knowledge,
    │                             ticketqc, ticketchecks, aiextract
    └── WillTools.tab/        the ribbon, four panels left to right:
        ├── Tools.panel/          Modeling.pulldown/ — Reinforce
        │                         Suggestion · Reinforcing QC · Ticket QC —
        │                         plus Snapshot as the one remaining large
        │                         button
        ├── Setup.panel/          Config.pulldown/ — Project Config ·
        │                         Design Extract · Self Check · Job Recon ·
        │                         Takeoff
        ├── Design.panel/         DesignHub.pulldown/ — Panel Lift Check ·
        │                         Panel Analysis (finished, grouped here on
        │                         the owner's own instruction), then Beam
        │                         Analysis (WIP) · Connection Analysis (WIP)
        │                         · Gravity (WIP) · Lateral (WIP)
        └── Lab.panel/            GOD_MOD

No model data or knowledge ships with it. _ticketqc/ folders stay with their models; knowledge layers come from the owner, on request — see the README's "What to ask the owner for."