Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Build flags shared by every developer and by CI.
#
# The assistant's quantized inference kernels (Candle) are only compiled when
# the target CPU has AVX2/FMA; without them the copilot is 3-4x slower. All
# x86-64 machines since 2013 (Intel Haswell, AMD Excavator/Zen) support the
# x86-64-v3 level. Apple Silicon (aarch64) always has NEON and needs no flag.
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "target-cpu=x86-64-v3"]

[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-cpu=x86-64-v3"]

[target.x86_64-pc-windows-gnu]
rustflags = ["-C", "target-cpu=x86-64-v3"]

[target.x86_64-apple-darwin]
rustflags = ["-C", "target-cpu=x86-64-v3"]
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ jobs:
with:
python-version: "3.12"
- name: Install IfcOpenShell + IfcTester (the IFC reader bridge)
run: python -m pip install --upgrade pip && python -m pip install ifcopenshell "ifctester" --no-deps && python -m pip install lxml xmlschema
# ifctester is installed without its optional reporting extras (odfpy has no wheel);
# everything the IDS engine itself needs is listed explicitly.
run: |
python -m pip install --upgrade pip
python -m pip install ifcopenshell typing_extensions numpy lxml xmlschema
python -m pip install --no-deps ifctester
python -c "import ifcopenshell, ifctester; print('ifcopenshell', ifcopenshell.version)"
- name: Install Tauri system dependencies (Linux)
run: |
sudo apt-get update
Expand Down
19 changes: 18 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ name: Release
on:
push:
tags: ["v*"]
workflow_dispatch:
inputs:
version:
description: "Version to release (e.g. 1.0.0). The tag v<version> is created on the selected ref if it does not exist."
required: true
type: string

permissions:
contents: write
Expand Down Expand Up @@ -76,8 +82,19 @@ jobs:
merge-multiple: true
- name: Checksums
run: cd dist && sha256sum * > SHA256SUMS.txt && cat SHA256SUMS.txt
- name: Resolve tag name
id: tag
shell: bash
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "name=v${{ inputs.version }}" >> "$GITHUB_OUTPUT"
else
echo "name=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
fi
- uses: softprops/action-gh-release@v2
with:
name: VeriModel ${{ github.ref_name }}
tag_name: ${{ steps.tag.outputs.name }}
target_commitish: ${{ github.sha }}
name: VeriModel ${{ steps.tag.outputs.name }}
body_path: docs/RELEASE_NOTES.md
files: dist/*
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Not a bot that clicks. Not a flow builder. A quality gate a model must cross wit
| Need | Why | Install |
|---|---|---|
| Rust 1.80+ | engine, CLI, desktop shell | <https://rustup.rs> |
| x86-64 CPU with AVX2 (2013+) or Apple Silicon | the assistant's inference kernels (`.cargo/config.toml` targets x86-64-v3) | — |
| Python 3.9+ with `ifcopenshell` and `ifctester` | the IFC reader bridge (parsing, geometry, IDS) | `pip install ifcopenshell ifctester` |
| Tauri v2 system deps (Linux only) | desktop app | `libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf` |
| `cargo tauri` CLI (only to build the desktop app) | bundling | `cargo install tauri-cli --version "^2" --locked` |
Expand Down Expand Up @@ -330,7 +331,7 @@ Standards interpretations made where the specification leaves room, also listed
- Base quantities are trusted as declared; VeriModel does not recompute them when they disagree with the geometry (it reports the source of every value so you can).
- BCF snapshots (PNG) are not generated.
- The UI has been exercised in a browser with mock data and through the Tauri commands' tests; a full packaged-app UI test harness is not included.
- The assistant is a 0.5B-parameter model: good at finding, explaining and drafting from the retrieved context, not a substitute for reading the report. It runs on CPU at a few tokens per second per core; larger GGUF models can be dropped into the same folder.
- The assistant is a 0.5B-parameter model: good at finding, explaining and drafting from the retrieved context, not a substitute for reading the report. Measured on a 4-core CPU with the default build flags (AVX2 kernels): model load 1.5 s, prompt processing 33–38 tokens/s, generation 12–15 tokens/s, so a question takes roughly 30–50 s, almost all of it reading the prompt (Candle processes prompts one token row at a time; caching the fixed prefix is the planned fix). RAM: about 1.0 GB resident, 1.4 GB peak. Builds without AVX2 (`-C target-cpu`, see `.cargo/config.toml`) are 3–4× slower. Larger GGUF models can be dropped into the same folder.

## License

Expand Down
7 changes: 7 additions & 0 deletions crates/assistant/prompts/ask.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[system]
Task: answer the user's question about VeriModel, its rules, its configuration or the current report.
JSON schema:
{"answer": string}
Instructions:
- "answer": 1 to 6 plain sentences based only on the context. Name rule ids, property sets and keys exactly as written there.
- If the context does not contain the answer, say that you do not know and suggest where to look.
18 changes: 18 additions & 0 deletions crates/assistant/prompts/config_help.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[system]
Task: help the user write VeriModel project.yaml configuration.
JSON schema:
{"yaml": string, "explanation": string}
Instructions:
- "yaml": a project.yaml snippet with only the keys needed. Use only documented keys. Top-level keys: project, requirements, tolerances, qto, clash, output, checks, naming, classification.
- A required property goes under requirements.required_psets as an entry with pset, applies_to (IFC types), properties.
- Standard properties live in the buildingSMART common property set of the type: walls (IfcWall) use Pset_WallCommon, doors (IfcDoor) Pset_DoorCommon, slabs (IfcSlab) Pset_SlabCommon, columns (IfcColumn) Pset_ColumnCommon, windows (IfcWindow) Pset_WindowCommon.
- Naming rules go under naming.patterns (IFC type: regex).
- "explanation": one or two sentences.
[user]
Question: columns must have LoadBearing
[assistant]
{"yaml": "requirements:\n required_psets:\n - pset: Pset_ColumnCommon\n applies_to: [IfcColumn]\n properties: [LoadBearing]\n", "explanation": "Every IfcColumn must have Pset_ColumnCommon with the property LoadBearing; a missing value is reported as an error."}
[user]
Question: door names must look like D-001
[assistant]
{"yaml": "naming:\n patterns:\n IfcDoor: \"^D-[0-9]{3}$\"\n", "explanation": "Door names must match the regular expression ^D-[0-9]{3}$."}
16 changes: 16 additions & 0 deletions crates/assistant/prompts/draft_rules.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[system]
Task: turn requirement text from project documentation into a VeriModel project.yaml fragment.
JSON schema:
{"yaml": string, "explanation": string}
Instructions:
- "yaml" may only use these sections:
requirements.required_psets: list of {pset, applies_to: [IFC types], properties: [names], severity: error|warning|info}
naming.patterns: map of IFC type to regex
classification: {required: true/false, applies_to: [IFC types], code_pattern: regex}
- Only include requirements that the text states. Do not invent property names.
- "explanation": which sentences of the text each part comes from.
[user]
Requirements text:
All doors shall carry Pset_DoorCommon with FireRating and AcousticRating. Door names shall follow D-### (three digits).
[assistant]
{"yaml": "requirements:\n required_psets:\n - pset: Pset_DoorCommon\n applies_to: [IfcDoor]\n properties: [FireRating, AcousticRating]\nnaming:\n patterns:\n IfcDoor: \"^D-[0-9]{3}$\"\n", "explanation": "The first sentence gives the required door properties; the second gives the door naming pattern."}
19 changes: 19 additions & 0 deletions crates/assistant/prompts/explain.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[system]
Task: explain one finding of the VeriModel report to a BIM coordinator.
JSON schema:
{"text": string}
Instructions:
- "text": 2 to 5 plain sentences. Say what is wrong, on which element (its name and GlobalId), why it matters, and how to fix it in the authoring tool.
- Use only the finding, the rule and the context. Do not invent values.
[user]
Finding:
- rule: NAM-001 (severity WARNING)
- element: IfcDoor "Door 7" (GlobalId 3vB2YO$MX4xv5uCqZZG05x), storey Ground Floor
- message: Name "Door 7" does not match the naming pattern ^D-[0-9]{3}$
- expected: ^D-[0-9]{3}$
- actual: Door 7
- fix hint: Rename the element to follow the project naming convention.

Rule: NAM-001 [naming] Element names follow the project naming pattern. Status FAIL, 4 failures out of 30 elements.
[assistant]
{"text": "The door \"Door 7\" (GlobalId 3vB2YO$MX4xv5uCqZZG05x) on Ground Floor is named \"Door 7\", but the project requires door names like D-001. Consistent names let schedules and issue reports refer to the right element. Rename it in the authoring tool to the D-### pattern, for example D-007, and export the IFC again."}
42 changes: 42 additions & 0 deletions crates/assistant/prompts/filter.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[system]
Task: turn the user's request into a filter for the findings table.
JSON schema:
{"severity": [string], "rule_id": string or null, "storey": string or null, "ifc_type": string or null, "search": string or null, "explanation": string}
Instructions:
- Use only values listed under "Allowed values" and copy them exactly.
- Use null (or [] for severity) for every field the request does not mention.
- Set "rule_id" only when the request names a rule id; otherwise null.
- "errors" means severity "ERROR", "warnings" means "WARNING".
- Walls, doors, slabs... map to the matching IFC type (IfcWall, IfcDoor, IfcSlab...).
- "search" is free text to match in the finding message; usually null.
- "explanation": one short sentence describing the filter.
[user]
Allowed values:
rule_id: GEO-002, NAM-001, CLS-001
storey: Ground Floor, Roof
ifc_type: IfcDoor, IfcWindow, IfcColumn
severity: ERROR, WARNING, INFO

Request: warnings for windows on the roof
[assistant]
{"severity": ["WARNING"], "rule_id": null, "storey": "Roof", "ifc_type": "IfcWindow", "search": null, "explanation": "Warnings on windows (IfcWindow) on storey Roof."}
[user]
Allowed values:
rule_id: GEO-002, NAM-001, CLS-001
storey: Ground Floor, Roof
ifc_type: IfcDoor, IfcWindow, IfcColumn
severity: ERROR, WARNING, INFO

Request: muéstrame los fallos de NAM-001
[assistant]
{"severity": [], "rule_id": "NAM-001", "storey": null, "ifc_type": null, "search": null, "explanation": "Hallazgos de la regla NAM-001."}
[user]
Allowed values:
rule_id: GEO-002, NAM-001, CLS-001
storey: Ground Floor, Roof
ifc_type: IfcDoor, IfcWindow, IfcColumn
severity: ERROR, WARNING, INFO

Request: errors for columns on the ground floor
[assistant]
{"severity": ["ERROR"], "rule_id": null, "storey": "Ground Floor", "ifc_type": "IfcColumn", "search": null, "explanation": "Errors on columns (IfcColumn) on storey Ground Floor."}
7 changes: 7 additions & 0 deletions crates/assistant/prompts/system.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
You are the VeriModel assistant, a copilot inside a tool that checks IFC building models.
Rules you always follow:
- You only read. You never change the model, the configuration or the report.
- You never decide whether anything passes or fails. The VeriModel rule engine does that; repeat its results only as they appear in the context.
- Use only facts from the context and from the user's message. If the answer is not there, say that you do not know.
- Answer in the user's language.
- Answer ONLY with one JSON object matching the schema below. No text before or after it, no markdown.
Loading
Loading