Use the repo-root development launcher when you want to test the code in this checkout without starting the VibeCAD copy installed through the normal Windows installer.
Double-click the prominent one-click entry point:
RUN-VIBECAD-DEV.cmd
RUN-VIBECAD-DEV.cmd delegates to the canonical launcher:
Launch-VibeCAD-Dev.cmd
or run:
.\Launch-VibeCAD-Dev.ps1The launcher initializes the checkout's pinned Git submodules, reads
version.json, prints the current version/build, full Git commit, and full Git
tree, then installs
or rebuilds vibecad inside this checkout's
package\rattler-build\.pixi\envs\default environment. It launches only when
that environment contains both the repo-local GUI executable and a complete
Windows Qt platform runtime. If an interrupted first build left an incomplete
Pixi environment, the launcher recovers it instead of treating an executable or
an empty environment directory as a usable build.
Install and rebuild commands use Pixi's frozen mode. The committed multi-platform lockfile is therefore an input to the developer run, not a generated workspace change.
It never searches the Start menu or Program Files.
The first launch is a full native VibeCAD/FreeCAD build and can take a long time. Keep the visible PowerShell window open. Later launches reuse the repo-local environment and compiler cache, so normal source/test iterations are incremental.
The launcher also quarantines Python's per-user site-packages under the ignored
checkout directory .vibecad-dev\python-user. This is deliberate even though
PYTHONNOUSERSITE=1 is set: embedded FreeCAD Python can still add its computed
user site. Redirecting PYTHONUSERBASE prevents a user-wide VTK, NumPy, or
other wheel from shadowing the versions in the checkout's Pixi environment.
Finding VibeCAD.exe or freecad.exe is not sufficient. Before launch, the
script also requires a canonical qwindows.dll and matching Qt DLL directory
inside the same checkout Pixi environment. Supported Pixi/Conda layouts include:
Library\lib\qt6\plugins\platforms\qwindows.dll
Library\plugins\platforms\qwindows.dll
plugins\platforms\qwindows.dll
The selected layout must use the checkout's locked Qt 6 runtime and contain
Qt6Core.dll, Qt6Gui.dll, and Qt6Widgets.dll. The package recipe explicitly
uses PySide6/Qt 6 and excludes Qt 5, so the launcher does not accept a Qt 5
plugin as a substitute. Every resolved executable, plugin directory, platform
plugin, DLL directory, and required DLL must remain beneath the canonical Pixi
environment root. The launcher neither searches for nor accepts a system, user,
Program Files, or inherited-environment plugin as a fallback.
Immediately before Start-Process, the launcher revalidates and re-hashes that
runtime, places the exact repo-local Qt DLL directory first on PATH, and
overwrites these variables with one canonical repo-local path each:
QT_PLUGIN_PATH=<canonical plugins root>
QT_QPA_PLATFORM_PLUGIN_PATH=<canonical platforms directory>
External values are not appended. This prevents direct native launch from selecting a different Qt platform-plugin tree or producing the common “no Qt platform plugin could be initialized” failure because a partial environment was mistaken for a complete one.
When the application starts through this launcher, the status bar shows:
VibeCAD DEV • <commit>
and the main-window title receives the same development marker. This makes a development session visibly different from an installed release build.
For an ordinary launch (one without -SkipRebuild), that marker is taken from
the checkout-derived full commit and is cross-checked inside the running process
against the launch attestations before the marker is accepted. There is no
command-line argument for supplying a different release identity.
Every launch that rebuilds creates two collision-safe JSON receipts under the ignored checkout directory:
<repo>\.vibecad-dev\attestations\
The files use high-resolution UTC time plus a random GUID in their names and are opened with create-new semantics. An existing receipt is never overwritten.
The build receipt uses vibecad.dev-build-attestation.v1; the launch receipt
uses vibecad.dev-launch-attestation.v1. Together they bind:
- the canonical repository root;
- the full checkout commit and tree IDs;
- the exact repo-local GUI executable path and SHA-256;
- the canonical Qt plugin root, platforms directory,
qwindows.dllpath/hash, matching Qt DLL directory, and required Qt DLL paths/hashes; - a successful, repo-local PySide6
QApplicationload probe whose reported Qt platform is exactlywindowsand whose loadedqwindows.dllis the exact attested plugin path, including the loaded plugin path/hash, probe Python path/hash, and UTC check time; - source and installed paths and SHA-256 values for
InitGui.py,VibeCADAgentControl.py,VibeCADAgentCli.py, andVibeCADGui.py(the installed copies must be byte-for-byte equal to the checkout sources); - source paths and SHA-256 values for
Launch-VibeCAD-Dev.ps1andInvoke-VibeCAD-VisibleTour.ps1; and - the exact build-receipt path/hash carried forward by the launch receipt; and
- the
release_evidenceassertion and clean-check result described below.
The launcher passes only the resulting receipt paths and hashes to VibeCAD. The
running process independently reads the checkout's canonical Git root, full
HEAD, and HEAD^{tree}, then reopens and hashes the actual receipts,
executable, checkout sources, installed modules, Qt 6 plugin, probe Python, and
required Qt DLLs. It also asks Windows for the qwindows.dll loaded by the
actual visible VibeCAD process and requires that path/hash to equal the receipt
and helper-probe identity. It refuses control-channel startup if a receipt is
missing, partial, modified, internally inconsistent, if any installed module is
stale, or if the GUI process loaded a different platform plugin.
For release-evidence automation, use the explicit guard form:
.\Launch-VibeCAD-Dev.ps1 -ReleaseAttestationAll rebuilt launches produce actual-file attestations, but
-ReleaseAttestation adds both a stricter clean-checkout assertion and an exact
cold Pixi build. After pinned submodules are initialized and before any Pixi
build action, the launcher runs Git porcelain-v2 status with all untracked files and
--ignore-submodules=none. Any superproject change, untracked file, changed
submodule revision, modified submodule content, or untracked submodule content
fails closed. The same check runs again immediately before receipt creation so
the build cannot silently dirty the asserted checkout.
Release-attestation mode records whether the environment and complete launch
runtime existed before the build, removes the named checkout-local default
environment if present, proves it is absent, clears Pixi's build cache, and then
runs a frozen pixi install. Failure to remove the environment or clear the
build cache stops before receipt creation or GUI launch. Normal one-click use
remains incremental and continues to reinstall only the VibeCAD package when a
complete environment already exists.
Both receipts contain a release_evidence object. In release-attestation mode
it records asserted: true, clean_checkout: true,
submodule_dirt_checked: true, cold_build_asserted: true, the exact status
mode, the pre-build environment/runtime state, proof that the environment was
absent before install, and the clean/environment/build-cache/pre-receipt check
times. The running GUI requires this complete object to match in both receipts
and validates every claimed gate before publishing its runtime identity. For
an ordinary rebuilt launch it records asserted: false and does not claim a
clean checkout. Combining -ReleaseAttestation with -SkipRebuild remains
rejected before submodule, build, or launch work begins. The switch does not
allow a caller to choose a commit, tree, repository, executable, or release
label.
The launcher does not treat the presence of qwindows.dll as proof that Qt can
use it. It runs the checkout's own python.exe, imports PySide6, creates a
non-windowed QApplication, and requires QGuiApplication.platformName() to be
exactly windows. The probe is run before deciding whether recovery is needed,
again after the install or rebuild, and once more immediately before the visible
GUI process starts. It pins QT_PLUGIN_PATH,
QT_QPA_PLATFORM_PLUGIN_PATH, QT_QPA_PLATFORM=windows, the matching Qt DLL
directory, and the repo-local environment while probing. After Qt initializes,
the probe asks Windows for the loaded qwindows.dll module path and requires it
to equal the already resolved and hashed repo-local plugin exactly; loading a
different Qt plugin from another search path is a failure.
The probe creates no top-level window and does not send physical mouse or
keyboard input. QT_FORCE_STDERR_LOGGING=1 routes Qt diagnostics to the launcher
instead of relying on a broken GUI error dialog. A failed existing runtime is
cleanly rebuilt during a normal launch; -SkipRebuild refuses it. If the
post-build or final probe fails, VibeCAD is not started and no external Qt files
are substituted.
The development launcher gives this checkout its own ignored agent-control directory:
<repo>\.vibecad-dev\agent\
The bearer token and endpoint.json live there. In development mode, the agent
home must be exactly this checkout-derived path; an arbitrary
VIBECAD_AGENT_HOME is rejected before a directory is created. On Windows the
checkout-scoped directory, token, and endpoint receive a protected,
current-user-only ACL. Development-mode startup fails closed if that ACL cannot
be applied and read back exactly. Normal installed startup preserves its
best-effort file-permission behavior and does not replace an arbitrary existing
directory DACL. This prevents
a developer or desktop agent from accidentally discovering a separately
installed VibeCAD session through the normal per-user endpoint. The launcher
prints the visible GUI PID and endpoint path, then waits for an authenticated
/v1/status response whose channel is vibecad-agent-control and whose
gui_up value is true. It
also requires the endpoint and status to agree on the launched PID, a random
per-server-start instance ID, server start time, exact token path, and complete
runtime identity.
Success therefore means all of the following are true:
- the current checkout's visible GUI process started;
- that exact PID owns the authenticated, loopback-only control channel; and
- for rebuilt launches, the process-derived runtime identity exactly matches
this invocation's build and launch receipts, including the
qwindows.dllloaded by that same visible GUI process.
The token is read from its file and is never printed or requested from a human.
The HTTP service binds only to 127.0.0.1; this launcher does not expose a LAN
or Internet development server. See
vibecad-agent-control.md for the route schemas and
security contract.
That checkout separation is a credential-discovery boundary, not a filesystem
sandbox. Once authenticated, the tester can open and save files wherever the
VibeCAD process already has access, and the explicitly authorized /v1/run
compatibility route executes in that same process authority. Use bounded routes
where available and authorize file targets and compatibility scripts just as
you would for a local developer tool.
The launcher sets the literal opt-in VIBECAD_DEV_MODE=1. That makes this
checkout use the fail-closed server entry point: a callable Qt document-thread
dispatcher must exist before the endpoint starts, operations are serialized,
and restore-state checks happen before document access. Normal installed startup
and existing integrations keep the original compatibility entry point and
defaults; development-mode safety does not silently replace those behaviors.
Use this loop for every user-visible feature, regression fix, and development checkpoint:
- Start
RUN-VIBECAD-DEV.cmd(or the PowerShell launcher) from the exact checkout under test. - Confirm the visible
VibeCAD DEV • <commit>title/status marker and the repo-local executable path printed by the launcher. - Read this checkout's
endpoint.jsonand token, then require an authenticated ready status before issuing test actions. - Drive the real, visible application through the narrowest authoritative
surface:
/v1/open,/v1/save,/v1/save-as,/v1/close,/v1/preferences, and/v1/screenshotfor application workflows and evidence;/v1/ui/ribbon,/v1/ui/menus, and/v1/ui/clickfor exact semantic UI inspection and in-process activation that does not control the Windows cursor;/v1/aerofor Aero workflows;/v1/runonly for explicitly authorized local compatibility scripts;- the repo's Qt GUI harness when a test specifically requires widget-level interaction.
- Capture the visible window through
/v1/screenshotbefore and after the action. Keep the same GUI window visible so a person can watch the change as it happens. - Preserve route results, screenshots, file round-trip artifacts, tour receipts, and focused automated-test output as the checkpoint evidence.
- Do not call the checkpoint complete merely because a unit test passed. The visible application run and the relevant artifact/receipt checks must also pass. Leave the GUI running for human inspection unless a restart, crash, or shutdown path is itself under test.
The Python /v1/run route retains privileged local compatibility execution.
Its source-text checks are not a security sandbox or an authority boundary.
Only run source the developer has authorized, and use a bounded domain route
such as /v1/aero when one exists instead of bypassing that contract merely to
make a GUI demonstration pass.
After the launcher reports Agent control ready, run:
.\Invoke-VibeCAD-VisibleTour.ps1The script creates a small, click-through, non-activating overlay containing
only a plain cyan pointer. It moves that overlay between geometry reported by
the live QMenuBar and VibeCADRibbonTabs. Activation is sent to the exact Qt
object through authenticated /v1/ui/click; the script contains no
SetCursorPos, SendInput, or equivalent Windows pointer injection. There is
no label, sign, circle, or halo. The built-in operator path also contains no
physical keyboard injection, input blocking, cursor confinement, input-thread
attachment, or foreground-window activation. If the exact validated VibeCAD
window is minimized, it is shown with SW_SHOWNOACTIVATE so restoration does
not take keyboard focus.
Each top-level menu is shown only for a short, bounded Qt preview while the cyan pointer is visibly pressed. The popup is then closed before the route returns; the previous focus and menu-bar action are restored, and the active window and popup state are verified unchanged. If a human already has a popup open, the tester fails busy rather than closing or replacing it. Ribbon activation uses the same focus/window restoration contract.
With no -Targets argument, the script discovers the exact running checkout's
currently visible, enabled top-level menus and enabled ribbon tabs, then tours
that live semantic inventory. It does not assume that a feature-specific tab or
menu exists. To run a focused tour:
.\Invoke-VibeCAD-VisibleTour.ps1 -Targets @(
'menu:File',
'menu:Tools',
'menu:Macro',
'ribbon:Aero',
'ribbon:Model'
)Each successful run writes an ignored JSON receipt under
.vibecad-dev\tours. The receipt binds every target to the exact process ID,
semantic index, geometry, selected or visibly-observed menu activation,
restored interaction postcondition, Qt input method, and
physical_cursor_control: none. A person may continue to move their own
physical mouse during the tour; that independent movement is sampled but is
never blocked or redirected.
Receipts use the versioned vibecad.visible-operator-receipt.v1 schema. The
complete payload, including its absolute receipt_path, is finalized once; the
same serialized JSON is returned to the caller and preserved on disk. Default
names combine a high-resolution UTC timestamp with a random nonce.
Writes use create-new semantics, so a concurrent collision or an explicit
-ReceiptPath that already exists fails rather than replacing earlier evidence.
When the checkout has not changed and you only need to reopen the existing local development build:
.\Launch-VibeCAD-Dev.ps1 -SkipRebuild-SkipRebuild does not allow the script to fall back to an installed VibeCAD or
external Qt installation. If the repo-local environment, GUI executable,
qwindows.dll, matching Qt DLL directory, or required Qt DLLs are missing,
launch fails with the incomplete component named before Start-Process. It
still waits for the checkout-scoped authenticated control channel, so a
successful reopen remains directly controllable and observable.
-SkipRebuild deliberately does not create or export build/launch
attestations, and the endpoint/status runtime_identity must remain null for
that compatibility path. The visible marker still names the commit selected by
the launcher, but a skipped rebuild is not evidence that the existing binary or
installed modules were produced from that commit. Do not use it for release
acceptance. -SkipRebuild -ReleaseAttestation is refused.
- Windows
- Git
- Pixi
- the normal VibeCAD Windows build dependencies required by the Pixi package
The launcher looks for pixi.exe on PATH and then at
%USERPROFILE%\.pixi\bin\pixi.exe.
Git submodules do not have to be initialized by a separate manual step; the launcher initializes the revisions pinned by this checkout before invoking Pixi.
This is a developer/test entry point. It does not replace the packaged
root-level VibeCAD.exe or the Windows installer produced by the release
bundling pipeline.