Repository navigation
v1.2.11 — Approve Before Keeping, Composite Profiles, Server Lockdown
·
50 commits
to development
since this release
Added — approve before keeping, preview, read-only runs (Settings → "Wijzigingen door de AI")
- Plan 15, after pyRevit 7.0's agent runtime (2026-10-06). Off by default:
autokeeps every
answer exactly as it was.askmakes deletions and edits (delete,exec,set,join,
unjoin,phase, and batches holding one) wait for the user: Revit isolates and selects what
changed and a window shows the question, the command and the counts by category; Behouden
keeps it as ONE undo step, Ongedaan maken (or Esc / closing) rolls everything back and tells
the AI not to retry. "Deze Revit-sessie niet meer vragen" switches it off until Revit closes.
New elements never ask.readonlyrefuses every change (READ_ONLY, with what it would have
changed) — for colleagues who only look. ?preview=1on any modifying command or batch: it runs, says what it would add/modify/delete,
and rolls everything back (an annotation it would re-host or remove is reported as-- preview:).
?readonly=1(meant forexec/batch) fails (QUERY_MODIFIED_MODEL) instead of changing the model.approvalslists this session's decisions; a decision a client missed (it waits up to 10 min,
thenAPPROVAL_PENDING) appears once in the next model-state stamp. Discarded runs are journaled.- The file-based fallback (only used when the HTTP port could not open) cannot ask or roll back, so
underaskorreadonlyit refuses changes instead of slipping past the setting. - IT can set it per machine:
ChangeApprovalin managed.json (locked in Settings); Diagnose names the
source;build.ps1 -Approval askfor testing. Measured in Revit 2023: a window in 0.3–1.1 s, Keep is
one Ctrl+Z (pile; floor + its spot elevation; an exec move), Discard leaves the edit counter as it was.
Added — apilookup: the Revit API of this Revit, for exec
- Plan 16, after pyRevit's
lookup_revit_api.apilookup Wall,apilookup Wall.Create,
apilookup FilteredElementCollector --filter Where: namespace (and the full name to write in exec
when exec does not import it), how to get one (the collector line goes through a base class for
Room, ModelLine and the other classes Revit's class filter refuses), properties, methods by overload, enum values and
[Obsolete]with Revit's own replacement advice — reflected from the RevitAPI of the running year.
Unknown names give the closest ones. 0.28 s the first time, then 0.01–0.03 s. - A failed exec compile now appends the matching lookup (
Hint: apilookup Wall.Widht … Closest: Wall.Width) — matched by error number, so the Dutch compiler messages work too.
Added — exec stops runaway loops
- Plan 17. An endless loop in an exec snippet froze Revit until it was killed. Every loop body
written with{ }now checks a deadline: after 25 s (?timeout=<s>, up to 300) the snippet stops,
its transaction is rolled back and exec answersEXEC_TIMEOUT— measured 25.1 s, Revit answered
the next command at once, no measurable overhead on normal loops. Brace-less loops, recursion and a
single long Revit call are still not interruptible (the timeout message says so).
Added — quay walls, capstones and curved runs as real families (profile, extrude, sweep, lwall)
- Plan 12 phase 1. A composite cross-section used to be an
execDirectShape: no family or type,
no Volume in a schedule,joinrefused. Four commands now generate a real Revit family on the
fly, load it and place it as ONE undo step (also insidebatch, atomic included):lwall x1 y1 x2 y2 --stem 600x4000 --foot 2500x800 [--toe] [--side left|right] [--slope]— an
L-shaped quay wall on one parametric line-based Generic Model (VM_L-wand, or… SFwith
--category foundation): stem and foot sizes are type parameters on locked reference planes, each
size combination becomes a type named from its sizes, an existing type is reused. The line is the
stem's front face, the heel lies left of the line unless--side right.profile <name> --points u,v …— a named section stored as a Revit Profile family (also usable in
Revit's own Wall Sweep / Slab Edge tools) with its points inVM_Profile;profile <name>prints
points, area, box and centroid;profilelists them.extrude <profile | --points …> --along <line/wall id | x1 y1 x2 y2>— line-based Generic Model
(--category foundation= point-based Structural Foundation with Wall length,framing= a beam);
extrude … --vertical <height> --at <x y>stands a plan profile up (Height is a type parameter).sweep <profile> --along <id,id,…>— along a chain of lines and arcs (any order) or a wall; the
path is fixed in the family and the response says so.
- Profiles are mm, u = left of the run direction (the side
sectionlooks to), v = up; outlines are
closed, cleaned and checked (a crossing outline names its segments). - Every generated family schedules by type with a correct Volume and a shared
VM_Length(fixed
GUID, so all of them share one schedule column);Materialis a type parameter (--material, or
the pack's default). The new element is joined with the walls, floors and generated elements it
overlaps (--no-jointo skip; library families such as piles are never joined), gets the office
phase (--phase), runs the post-command check and is journaled with the.rfait wrote. - Re-running updates instead of adding "(2)": the same profile reuses the loaded family, a changed one
is regenerated and reloaded keeping the project's type values; a family edited by hand in Revit
since (or one VibeModel did not make) is refused until--replace. Live-checked in Revit 2023
(docs/verify/plan12-live-2026-10-16.md): a reused family is not opened, so its hand edits show
up as aWARNwhen Revit's volume differs from profile area × length;--replaceregenerates
even with unchanged points. - The
.rfafiles go to<project folder>\VibeModel\families\(3 s deadline; offline → a local copy,
said in the response). Revit's shared-parameter file setting is swapped for the build and always
restored. - Office packs get an optional
profilesblock (prefix, category per kind, templates, folder,
shared parameters, materials, type-name pattern) and the example pack akadeconstructietopic
sheet: the questions an office answers about its quay walls, without values.
Security — the local server only answers the user's own tools
A brainstorm review (2026-10-15) found that any web page the user had open could drive Revit: the
server never looked at Host or Origin, and the token was off unless VIBEMODEL_TOKEN was set —
<img src="http://127.0.0.1:18884/exec?args=…"> ran C# inside Revit, and a domain resolving to
127.0.0.1 could also read readdoc/memory. See the new SECURITY.md.
- Browser requests are refused (403
forbidden, before/healthtoo): any request with an
Originheader, aSec-Fetch-Siteother thannone/same-origin, a cross-siteSec-Fetch-Mode,
or aHostthat is not127.0.0.1,localhostor[::1](bare or with the server's own port).
curl, the chat backends and the Claude Code CLI send none of these — nothing legitimate changes. - A token on every call, by default. Without
VIBEMODEL_TOKENthe server now generates a random
per-session token and publishes it in the per-user%LOCALAPPDATA%\VibeModel\servers\<port>.json
(tokenfield). The chat pane reads it in-process, the Claude Code CLI gets it asVIBEMODEL_TOKEN;
terminal one-liners for bash and PowerShell are in CLAUDE.md/README. An explicitVIBEMODEL_TOKEN
still wins."OpenServer": true(managed.json or settings.json) restores the open server for
scripts; Diagnose shows which mode is active, and a 401's hint names the servers file. - managed.json must be IT's.
%ProgramData%\VibeModel\managed.jsonis only trusted when file and
folder are owned by Administrators or SYSTEM and give ordinary users no write access (Windows lets
users create folders under ProgramData); otherwise it is ignored, logged once and named in Diagnose.
docs/deployment.md shows theicaclscommands.
Fixed
POST /batch: a multi-byte character (°,m²,ë) that straddled a 4 KB read boundary was
decoded as two broken characters and changed the body's byte count. The request is now read as
bytes against Content-Length and decoded once;Expect: 100-continue(curl, bodies over 1 KB) is
answered before the body is awaited.scripts/sign.ps1signed silently without a timestamp when the timestamp server was unreachable
(such a signature dies with the certificate). It is now an error unless-NoTimestampis passed.poll-health.ps1and the build summary use127.0.0.1instead oflocalhost(IPv6 stall).
Full Changelog: v1.2.10...v1.2.11