> ## Agent Instructions > These docs contain multiple Speckle product experiences. For Speckle 2026.9, prefer /next/ pages for the topics and changes they cover. The navigation label Current does not override this version-specific precedence. > Coverage under /next/ is incremental. Use Current documentation for unchanged topics and when a /next/ page says coverage is unavailable or explicitly refers you to Current. Do not infer a feature was removed from a missing page. > Read the page-specific documentation status, applicability, affected guidance and replacement links in agent-only content. Impacted, changed and superseded apply only to the stated scope; they do not mean the entire feature is deprecated. Historical connector guides apply only to the legacy connector described. > Match guidance to the customer's deployment version, model data format and connector. Respect plan, permission and compatibility restrictions. If an unknown version or data format changes the answer, ask a focused clarification; do not infer deployment version from the date alone. # 3D viewer in 2026.9 Source: https://docs.speckle.systems/next/3d-viewer/introduction What changed when you open a model in the 2026.9 web app — Selection, Filters, Views, section planes, and the new panel chrome. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Opening a model in the 2026.9 web app uses a new 3D viewer. Geometry starts appearing while the full file is still downloading. **Selection**, **Filters**, and **Views** sit in dockable panels, and sectioning uses cutting **planes** instead of a box. This page covers only what changed. For interface basics that still apply — sharing, federation from the project, and issue fields — see [Interface and navigation](/3d-viewer/interface-nav), [Exploration](/3d-viewer/exploration), [Saved views](/3d-viewer/saved-views), [Issues](/3d-viewer/issues), and [Share your models](/3d-viewer/sharing). Embedded models show only the 3D scene for now. The model tree, **Filters**, selection details, and the viewer toolbar do not appear inside an embed yet, whichever embed options you choose. This is a known limitation. Open the model in the web app to filter, select, or measure. To ask questions about the models loaded in this viewer, use the sparkle. That flow is on [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). The 2026.9 viewer requires WebGPU. There is no fallback. Firefox on macOS currently allows eight GPU storage buffer bindings, and the viewer needs nine, so models will not open there — use Chrome, Edge, or Safari. ## Open a model Large models use a hybrid load. A first overlay can show **Preparing 3D stream** or **Downloading model**. Once geometry starts painting, the overlay goes away and a progress stack in the top-right corner continues in the background. The downloaded copy is stored locally, so opening the same version again prefers that cache. You should see objects in the scene before the background download finishes. Point clouds do not render in this viewer yet. Everything else in the model loads normally, and your point cloud data is unchanged — the points are not drawn. Support is planned for a later release. Some colours and materials do not render in this viewer yet. Affected objects show as flat grey, even though the colour is in the published data. Known cases are coloured meshes and geometry with a **Color** input from Grasshopper, Civil 3D surfaces with materials, and models published before your project moved to the 2026.9 data format. Your data is unchanged, and connectors that load the model keep the colours. This is a known issue we are working on. ## Find your way around Panels are dockable. Drag a panel icon onto another panel to make a labelled tab group, split it into the bottom dock, collapse it, or resize it. On a first visit, **Selection** is open so the canvas is not empty. * **Models**, **Filters**, **Views**, and **Issues** sit in the left sidebar tab strip. * **Selection** sits under those tabs by default and shows properties for the current pick. * **Elements** sits in the bottom dock and lists every object in the loaded models. * The status bar at the bottom holds panel icons, undo, redo, screenshot, shortcuts, and **Settings**. * The navigation cube sits at the bottom-right of the canvas for canonical camera directions. The status bar **Settings** menu holds **Orthographic**, **Grid**, and **Reference points**. **Layout** in that menu lists every panel as a checkbox. **Models** stays on. **Lock layout** stops accidental drags. **Reset layout** restores the default arrangement after you unlock. Right-click a panel icon in the tab strip or status bar to move it. The menu lists only slots that panel can occupy: **Move to sidebar**, **Move to sidebar bottom**, **Move to bottom panel**, or **Move to bottom right**. **Remove panel** hides it; turn it back on from **Layout**. **Models** has no **Remove panel**. With **Lock layout** on, the move verbs are omitted. These panels start hidden. Turn them on from **Settings** → **Layout**: * **Materials** lists materials and colours in the loaded models. Select the usage count to pick the objects that use that material. * **Browse** pages through tables in the published data. * **SQL** runs a query against the attached models. **\$selected** inserts the current pick's application IDs. * **Inspector** shows envelope relations as a diagram or rows, plus a raw property table. When nothing is selected it reads **Select an object in the viewer to inspect its rows**. On narrower widths the left sidebar becomes a slide-over. Right-click the canvas for **Hide** or **Show**, **Isolate** or **Un-isolate**, **Fit to view**, **Copy application ID**, **Add to chat**, and **Clear selection**. With more than one object selected, **Hide** and **Isolate** (and their opposites) become **Hide selection** and **Isolate selection** (or **Show selection** and **Un-isolate selection**), and the chat verb reads **Add selection to chat**. Right-click a row in **Models** for the same verbs except **Copy application ID**. Right-click a scene-tree group to pin that group; the verb then reads **Add "" to chat**, using the group's name. Right-click a selected object keeps the whole selection. Right-click an unselected object replaces the selection with that pick. **Add to chat** pins the pick for Speckle Intelligence. If too many objects are selected to pin individually, a toast reads **Too many objects selected to add individually** and tells you to right-click a scene-tree group instead. ### Use the Models card Right-click the **Models** card header, or use **⋯**, for **Expand one level**, **Collapse one level**, **Group by…**, **Search this model**, and **Model placement**. When the grouping strip is already open, **Group by…** becomes **Hide grouping options**. These verbs apply to the whole card, not to a tree row. When several models are federated, the same menu also offers **Isolate model** (or **Un-isolate model**, or **Isolate model (partially isolated)**), **Hide model** or **Show model**, and **Remove from scene**. Header glyphs show isolate and hide at a glance; they toggle the same state. **Search this model** opens a field on the card with the placeholder **Search this model...**. **Model placement** opens the inspect dialog described in [Inspect model placement](#inspect-model-placement). ### Group objects in the tree **Group by…** opens the grouping strip and its editor in one click. A collapsed strip shows **Grouped by** plus the current levels joined with ›. Select that summary to reopen the editor. The editor lists one row per tree level. Helper text reads **Each row is a level of the tree — drag to renest.** Drag the grip to reorder. Each row is a searchable picker; search with **Search property or relationship…**. Options show a label, a coverage count, and the full property path. Relationships such as **Level**, **Collection**, **Model**, and **Network** appear first when those relations exist. Properties follow; labels come from the path, so **Family** or **Category** appear when those paths are in the catalog. The default grouping is a spatial relationship (**Collection** or **Level**) over the highest-coverage property. **Add grouping** appends a row. **Done** collapses the editor. While the catalog loads, the strip can show **Loading options…**. If grouping is too fine to precompute, it reads **Grouping too fine to precompute — the deepest level loads on expand.** **Keyboard shortcuts** opens from the status bar, or from `?`. That cheat sheet is the authoritative list, including fly keys (W A S D, E and Q) and Alt+1–5 for standard views. ## Select and inspect Click geometry, or click rows in **Models**. Selection highlights both ways: the 3D pick reveals the tree row, and the tree row highlights in 3D. Open **Selection** with Shift+O. **Selection** shows properties for the pick. The title uses the first non-blank of **name**, **type**, or **category**. Property groups auto-expand. A **Pinned** group stays at the top when you pin a path. Revit material quantity blocks are condensed into readable rows named like ** Area** or ** Volume**. A **Relations** group at the bottom lists related objects by relation kind. Search the list with **Filter properties**. When nothing is selected, **Selection** shows **No properties**. From a property you can: * **Add to filters** — open an empty **Filters** card for that property. The scene does not narrow until you set the condition. * **Filter to this value** — add a card already set to this value. The scene narrows immediately. Relation rows skip this action. * **Add as table column** — add the path to **Elements**. If it is already a column, the menu reads **Shown as a table column** and opens **Elements**. * **Pin property** or **Unpin property**. * **Copy value** — copies the raw value, not the rounded display string. * **Copy path**. * **Copy all properties** — one `path: value` line per row. * **Copy group path** — from a group header that has a real path. **Pinned** and **Relations** have no path to copy. * **Expand all groups** or **Collapse all groups** — on a single-object list. Multi-select cards fold from the toolbar instead. When you select several objects, **Selection** shows one card per object. Each card can zoom, isolate, or hide that element. In a wide dock the cards sit in columns. Fold or expand all cards from the toolbar. The count reads **N selected**. Selections larger than 1,000 objects start folded; you can still open one card at a time. Use **Show all** on the toolbar when objects are hidden or isolated. ### Browse objects in Elements **Elements** is a table of the objects in the loaded models. It follows the active **Filters** stack. Double-click a row to zoom to that object. When several models are loaded, a scope control can limit the table to one model or to the current selection. Select **Elements** in the bottom dock, or use Shift+T. You should see a table of objects and a count. Select a row. **Selection** shows that object's properties. Double-click the row to frame it in the scene. **Export view to Excel** downloads the current columns, filter scope, and sort. If grouping or search is too large, a warning reads **Showing the first … elements — narrow the scope (filters or selection) for a complete view**. **Update parameters** turns columns whose path starts with **properties.** into editors. Other columns stay read-only and show a lock icon in the header. Staged edits do not change the published version. **Submit change requests** creates an issue that carries those deltas, so teammates can review the proposed values. Creating that issue needs permission to create issues on the project. When **Update parameters** is on and the table has 15 or more elements, **Search rows…** appears and narrows the table. It is not on the browse toolbar. Only **properties.** columns become editors. Name, category, and similar columns stay read-only. ## Filter and color **Filters** is a stack of property cards, not a single search box. Each card has operators that match the property type. Applied filters stay in place when you change selection or close and reopen panels. Open **Filters** with Shift+F. When the stack is empty, **Filters** shows **No filters yet** and an **Add filter** control. If the catalog fails, it shows **Failed to load properties**. If a resolve fails, it shows **Failed to resolve filter matches**. While a model is still attaching, it shows **Attaching model…**. Operators by property type: * String: **is one of**, **is not one of**, **contains**, **does not contain**, **has value**, **is set**, **is not set**. * Number: **equals**, **is not equal**, **in range**, **has value**, **is set**, **is not set**. Numeric **equals** and **is not equal** accept more than one value. Equals tolerates small floating-point differences. * Boolean: **is** (**True** / **False**), **has value**, **is set**, **is not set**. * Relation (for example a level or network hop): **is one of**, **is set**, **is not set**. **Has value** matches objects where the property has a non-empty value. **Is set** matches objects where the property exists. **Is not set** matches objects where it is missing. Open **Filters** and select **Add filter**. Choose a property. An empty card appears in the stack. The scene does not change yet. Choose an operator and the values to include or exclude. The scene then narrows to matches. If nothing matches, **Filters** shows **No objects match — everything is hidden**. On a string or relation card, select **Color by values**. Matching objects take colors for those values. Only one card colors the scene at a time. Numeric and boolean cards do not color the scene. With two or more cards, **All** keeps objects that match every card. **Any** keeps objects that match at least one. With **All**, each card's value list is scoped to the enabled cards above it. With **Any**, the cards are independent. Drag the grip, or use Alt+↑ / Alt+↓, to reorder. Right-click a card for **Change property…**, **Collapse** or **Expand**, **Color by values** or **Stop coloring**, **Disable filter** or **Enable filter**, **Move up**, **Move down**, **Duplicate**, and **Remove filter**. A disabled card stays in the stack but does not hide objects. **Clear all filters** is in the panel header. **Reset filters** on the toolbar clears the same stack without undoing hide and isolate. Intelligence in this viewer can also color and isolate from Chat. That is documented on [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence), not here. ## Save and apply views **Views** lists two kinds of viewpoint in one panel. Open it with Shift+V. * **Model views** come from the source application when the connector published them. Select a row to fly the camera. These rows stay in **Model views**; converting one does not remove it. An orthographic published view can show a **Parallel / orthographic (isometric)** cue. * Saved views are viewpoints you (or a teammate) stored in Speckle. The panel only lists views whose models are currently loaded. A view saved on an older version of a loaded model still applies. When nothing is saved and there are no groups, **Views** shows **No views yet**. A search with no hits shows **No matching views**. An empty named group reads **Drop views here**. Saving a view needs permission to create saved views on the project. Creating saved views needs the Contributor project role or higher. Without that permission, **Save view** and **New group** are disabled. **Sketch** is also disabled; its tooltip reads **You don't have write access**. See [Saved views](/3d-viewer/saved-views) for grouping and sharing rules that have not changed. On a self-hosted server, saved views are available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Saved Views](/developers/server/deployment/enterprise-license#optional-saved-views). Frame the camera, set filters and visibility, and add section planes or sketches you want stored. In **Views**, select **Save view**, or use the bookmark control on the toolbar. Name it. The new view appears in the panel. To keep a connector-published viewpoint as a saved view, select **Save as view** on that **Model views** row, or drag the row into a saved-view group. Dragging into a group needs at least one named group and permission to create views. You cannot drop a model view into **Ungrouped**. **New group** creates an empty group as a drop target. Search with **Search views**. Cards show the author and a relative date. Private views show a lock with the tooltip **Only visible to you**. On a saved view the ⋯ menu is **Rename**, **Make private** or **Make public**, and **Delete…**. There is no **Set as home view**, **Replace view**, or **Copy link** on this menu. Use the eye control to show or hide that view's sketches and measurements. On a group the ⋯ menu is **Rename**, **Make all private** or **Make all public**, and **Delete group…**. **Ungrouped** is a tail for views that were saved before grouping. You can drag views out of it. You cannot drop views into it. Its menu is **Delete all views…**. Deleting a view also deletes its sketches and measurements. The confirm dialog says so. A view created in the previous viewer can show **Legacy view — not openable here yet**. Re-save the look in this viewer if you need a viewpoint you can apply. ## Cut, measure, and sketch The bottom toolbar holds **Section**, **Sketch**, and **Measure**. Shortcuts: Shift+B, Shift+K, and Shift+R. Press Esc to leave a tool. Cmd/Ctrl+Z undoes while sketching or measuring. ### Section planes Sectioning is no longer a six-sided box around the model. You add individual **section planes** and move each one. Select **Section** on the toolbar. The tool options appear above the toolbar. Select **Plane**, then click a surface, or select **XY**, **XZ**, or **YZ** to cut at the scene centre. The model is clipped on one side of the plane. Select a plane in the list to show its handle. Drag the handle, **Flip which side is cut away**, or **Stop cutting** without removing the plane. **Resume cutting** turns that plane back on. **Hide plane handles** keeps the cut for a cleaner screenshot. **Remove all planes** clears the list. If **Plane** is disabled, the tooltip reads that all plane slots are in use. ### Measure Types: **Point to point**, **Perpendicular**, **Angle**, and **Area**. Measurements stay on the canvas for the session. If you can save views, they are stored on the saved view with sketches. Without that permission they disappear when you leave the model. Measurements live on their saved views in the **Views** panel. Use the eye control on a view card to show or hide that view's sketches and measurements. The same eye on a group header toggles every view in that group. ### Sketch in 3D **Sketch** draws on the model in 3D. Ink stays with the geometry as you orbit, pan, and zoom. It is stored on a saved view: saving the view keeps the markup, and opening that view restores it in place. Sketches live on their saved views in the **Views** panel. Use the eye control on a view card to show or hide that view's sketches and measurements. The same eye on a group header toggles every view in that group. Tools: **Pen**, **Arrow**, **Revision cloud**, **Text**, and **Eraser**. Preset ink colours are **Red**, **Amber**, **Blue**, **Green**, and **White**. **Custom color** adds any colour and opacity. Brush sizes sit next to the colours. Sketch is disabled without permission to save views. ### Navigation cube The cube in the bottom-right of the canvas sets canonical directions. Alt+1–5 also move the camera to Top, Front, Left, Back, and Right. Fit and zoom still sit on the toolbar: **Fit view to everything**, or **Zoom to selection** when something is selected. Shift+Space does the same fit. Shift+P toggles orthographic projection. Explode, the older view-mode styles (Pen, Arctic, Shaded), and lighting controls are not on this toolbar. Projection and the grid are in **Settings**. ## Restore an issue's view **Issues** lists issues for the models in the scene. Open it with Shift+I. Opening an issue that was created in this viewer restores the camera, filters, visibility, and selection stored with it. Select a card to apply that stored look. Right-click the card, or use **⋯**, for **Open issue page** and **Delete…** when you can delete. **Open issue page** opens the full issue in a new tab. Create, assign, and field editing stay on [Issues](/3d-viewer/issues). To tie an issue to particular objects, select them in the scene before you select **New issue**. The selection is stored with the issue, along with the camera, filters, and visibility at the moment you select **Create issue**. Opening the issue selects those objects again. An issue raised with nothing selected stores the view only. The **Issues** tab is always in the strip. If the feature is not available on the project, the panel body shows that denial instead of a list. Empty states: **No issues for this scene** with **New issue**, **No matching issues** after search or chip filters, and **Select an issue** in the wide-dock detail pane. Issues are available when your workspace plan includes them. On a self-hosted server, they are available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Issues](/developers/server/deployment/enterprise-license#optional-issues). Issue fields, assignment, and permissions stay on [Issues](/3d-viewer/issues). An issue created in the previous viewer may show **Legacy issue — its view can't be applied here yet**. If the issue points at models that are not loaded, the tooltip reads **References models not loaded in this scene — opens details only**. ## Inspect model placement When several models are federated, **Models** can open **Model placement** for a model. That dialog shows the published placement, geometry storage, Project True North, and translation. **Inspect placement option** previews Internal Origin, Project Base Point, Survey Point origin, or Shared Coordinates. **Model placement** in this viewer is inspect-only. Switching placement is not enabled yet. How Revit stores placement on publish is on [Revit in 2026.9](/next/connectors/revit/introduction). Adding models to a scene from the project still follows [Model federation](/3d-viewer/federation). ## Keyboard shortcuts Open the cheat sheet from the status bar or `?`. Bindings use Cmd on macOS and Ctrl elsewhere. * Panels: Shift+M **Models**, Shift+F **Filters**, Shift+V **Views**, Shift+I **Issues**, Shift+T **Elements**, Shift+O **Selection**. * Tools: Shift+R **Measure**, Shift+B **Section**, Shift+K **Sketch**. * Camera: Shift+Space **Fit view / zoom to selection**, Shift+P **Orthographic projection**, Alt+1–5 standard views. * Display: Shift+G **Grid**, Shift+X **Reference points**. * History: Cmd/Ctrl+Z **Undo**, Cmd/Ctrl+Shift+Z **Redo**. * Fly around: W A S D or arrow keys to move. E or Page Up moves up. Q or Page Down moves down. Hold Shift for faster, Alt for slower. ## FAQ Point clouds are not drawn in the 2026.9 viewer yet — see [Open a model](#open-a-model). Re-publishing or re-uploading the model will not change what you see, and connectors that load the point cloud keep working. Uploading an `.e57` file is a separate case — see [File uploads in 2026.9](/next/connectors/file-uploads). Some colours and materials are not drawn in the 2026.9 viewer yet — see [Open a model](#open-a-model). Your data is unchanged. If the model was published before your project moved to the 2026.9 data format, publish it again from the source application to restore the colours. For Grasshopper colours and Civil 3D surface materials, publishing again does not help yet. There is no Shaded or Rendered view mode in this viewer, so switching modes is not a fix. If the colour stands for a property such as status or category, use **Color by values** on that property in **Filters** instead. There is no dedicated diff view in the Models **⋯** menu. Speckle Intelligence covers change detection, reporting, and impact assessment instead: ask Chat or the viewer sparkle to compare two versions and summarise what was added, removed, or changed, save that as a shareable Report, or turn a recurring comparison into a skill. See [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence#what-you-can-ask), [Compare versions in a Report](/next/analytics/reports#compare-versions), and [Assess model changes with Speckle Intelligence](/next/workflows/assess-model-changes-with-intelligence) for a full worked example. [Compare Versions](/3d-viewer/compare-versions) covers the deprecated Current-viewer flow. The 2026.9 viewer cuts with section planes, not a box. Add **XY**, **XZ**, or **YZ**, or place a plane on a surface, then flip or hide individual planes. Explode and the older view mode styles are not on this toolbar. Projection and the grid are in **Settings**. Sketch is stored on saved views, so it uses the same permission as **Save view**. Reviewers without that permission cannot sketch. Save a view after you draw if you need the ink later. On their saved view in the **Views** panel. Use the eye on the view card to show or hide that view's sketches and measurements. A group header eye toggles every view in the group. See [Sketch in 3D](#sketch-in-3d). Yes, if they were stored on that view. Measurements live on that view in the **Views** panel with sketches. Use the eye on the view card to show or hide them. A group header eye toggles every view in the group. Without permission to save views, measurements last only for the session. See [Measure](#measure). Some older views show **Legacy view — not openable here yet**. Re-save the look in this viewer if you need a viewpoint you can apply. When no objects match, **Filters** shows **No objects match — everything is hidden**. Change the values, switch **All** to **Any**, enable a disabled card, or use **Reset filters**. No. **Color by values** is on string and relation cards only. Use Chat if you want Intelligence to color by a property; that flow is on [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). They are not on the 2026.9 view-card menu. You can **Rename**, change public or private, show or hide ink, and **Delete**. Grouping and dragging still work. Home view and replace remain documented for the viewer before 2026.9 on [Saved views](/3d-viewer/saved-views). Not yet. **Model placement** lets you inspect the published datum. Changing placement on publish is documented for Revit on [Revit in 2026.9](/next/connectors/revit/introduction). No. Edits stay staged in **Elements** until you **Submit change requests**. That creates an issue with the proposed values. The published version is unchanged. Embeds do not show the model tree, **Filters**, selection details, or the toolbar in the 2026.9 viewer yet. Changing the embed options will not bring them back. Your model and its data are unchanged. Open the model in the web app to filter, select, or measure. Firefox on macOS supports WebGPU, but it currently allows only eight GPU storage buffer bindings. That is the WebGPU specification minimum. The 2026.9 viewer needs nine, so the model will not open. Other browsers on macOS allow ten or more, and Windows and Android browsers generally allow sixteen or more. This is a known, accepted limitation, not a bug. Firefox may raise the limit later; until then, use Chrome, Edge, or Safari. # Dashboards in 2026.9 Source: https://docs.speckle.systems/next/analytics/dashboards Dashboards load 2026.9-format models. Compatibility mode is optional, and Intelligence Reports remains a separate product. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. Dashboards read 2026.9-format models natively. Do not tell readers to enable compatibility mode so Dashboards can load those models. Compatibility mode stays optional for ACC sync and drag-and-drop consumers that still need the old format. The widget-availability page is the list of placeholders, not a launch blocker. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Dashboards load models in the 2026.9 data format. You do not need [compatibility mode](/next/it-admin/compatibility-mode) for that. Models published with 2026.9 connectors, ACC sync that writes the new format, and Rhino or IFC file uploads all appear in Dashboards. This includes older versions: Speckle Server has upgraded existing version history to the new format, so Dashboards load against your full model history, not just data published after the fix. A few widgets are not ported yet. Those saved instances stay on the grid as placeholders. They keep their configuration. They do not load 2026.9-format data until that widget is ported. See [Dashboard widgets not yet available](/next/analytics/dashboards-widget-availability). For building, sharing, and configuring dashboards, use the [current Dashboards documentation](/analytics/intelligence-dashboards). Compatibility mode is optional, and it ends on **1 November 2026**. Request it only when ACC sync or drag-and-drop still has to write the old format for another tool. See [Compatibility mode](/next/it-admin/compatibility-mode). ## New widgets, not just a compatibility port Reading 2026.9-format models is the baseline fix. Alongside it, a few widgets are new — they did not exist in Current Dashboards: * **Dual viewer** — two Model Viewer panes in one widget, cameras synced, for comparing two models side by side. * **Elements table** — a unified table replacing both Element table and Pivot table, built for the new data format. * **Ratio value** and **Ratio value by property** (Beta) — a live ratio between two numbers (or a number and a per-property breakdown), traced back through its property sources, calculated fields, and filters. * **Numeric range** (Beta) — a slider filter widget that publishes a range for other widgets to filter by. * **Property checker** — model validation rules surfaced as a dashboard widget, rather than only in the model checker tool. These ship alongside the format fix, not as a separate release. ## Dashboards remain the analytics product Dashboards stay available on every plan. Workspaces without Speckle Intelligence keep using them. Workspaces with Intelligence can use Dashboards and [Intelligence Reports](/next/analytics/reports) side by side. Our focus for Dashboards from here is stability and reliability: keeping the existing widgets and workflows working well, and responding to bug reports. We're not currently working on expanding what Dashboards can do — that effort is going into Intelligence Reports instead. If you have built a dashboard that solves a problem in a way we have not seen before, share it in the [forum](https://speckle.community) or email [feedback@speckle.systems](mailto:feedback@speckle.systems). ## Intelligence Reports For workspaces with Speckle Intelligence, **Intelligence Reports** start from an analysis you already ran in [Speckle Intelligence Chat](/next/analytics/intelligence). You ask a question about your model, the chat builds the analysis, and you save that as a Report. Reports can also draw on external data sources — Snowflake, Databricks, and others — so cost rates, programme data, or benchmarks sit next to model data. See [Create and share Intelligence Reports](/next/analytics/reports) for editing, sources, and sharing. Intelligence Reports require a workspace plan that includes Intelligence. Dashboards remain available on all plans. ## FAQ No. Dashboards already read the 2026.9 format. Request compatibility mode only when ACC sync or drag-and-drop must keep writing the old format for another tool. See [Compatibility mode](/next/it-admin/compatibility-mode). That widget is not ported yet. The saved configuration stays. The list of placeholders is on [Dashboard widgets not yet available](/next/analytics/dashboards-widget-availability). Other widgets on the same dashboard still load 2026.9-format data. Compatibility mode ends for every workspace. That date is for ACC sync and drag-and-drop format, not for Dashboards. Dashboards already read 2026.9-format models. All of them. Speckle Server has upgraded existing version history to the new data format, so Dashboards load against a model's full version history, not just versions published after the fix. # Dashboard widgets not yet available Source: https://docs.speckle.systems/next/analytics/dashboards-widget-availability Widgets that do not yet run against 2026.9-format models, and what happens to saved instances. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This page is the published not-yet-migrated widget list. A widget belongs here only while its Bashboards registry entry has no `nextCompatible` flag. When that flag is set, remove the widget from this page in the same change as the registry update. Atlas pointer and update rule: `atlas/specs/2026-09-bashboards-2026-9-widget-availability.md`. Deprecated widgets live only in the Deprecated in 2026.9 block. Do not mix them into the not-yet-migrated sections. Do not list hidden developer examples or widgets that already run through the compatibility projection. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Dashboards load 2026.9-format models. See [Dashboards in 2026.9](/next/analytics/dashboards). Compatibility mode is optional and is not required for Dashboards. For building and sharing dashboards, use the [current Dashboards documentation](/analytics/intelligence-dashboards). However, some dashboard widgets do not yet run against models in the 2026.9 data format. Saved widgets keep their configuration but appear as placeholders until support for the new format is available. Widgets that are **not** on this list either already run against 2026.9-format models, or they are presentation widgets that do not read model properties. For the launch limitation and compatibility mode, see [Dashboards in 2026.9](/next/analytics/dashboards). For building dashboards on pre-2026.9 data, use the [Dashboards documentation for 2026.8 and earlier](/analytics/intelligence-dashboards). ## How to read this list * A widget leaves the sections below when it can run against 2026.9-format models. * Pre-2026.9 data, and workspaces in [compatibility mode](/next/it-admin/compatibility-mode), still use the widget set prior to this change. * Widgets in Deprecated in 2026.9 are retired. They will not gain 2026.9-format support. ## Deprecated in 2026.9 These widgets are retired in 2026.9. A saved instance may still appear on a dashboard. That does not restore the widget. Use the replacement named for each widget. If no replacement is named, the widget has no successor. * **Element table** — replaced by the Elements table. * **Pivot table** (matrix table) — replaced by the Elements table. * **Context** (experimental, model on a map) — deprecated. This is not the same as marking a model as a [context model](/analytics/intelligence-dashboards#context-models) in the Model Viewer. * **Parameter Updater** — no longer a dashboard workflow in 2026.9. Use the [Elements panel in the model viewer](/next/analytics/data-conditioning). * **Revit-category Material quantities over time** — replaced by Time series Beta Material quantities over time. * **Cost Estimation for Tekla** — deprecated. No replacement. * **Render Genie** — no longer supported. No replacement. * **Model Validation** — retired from new dashboards. Saved widgets still run. The Model validation sidebar appears only on dashboards that already have a Model Validation widget. Use Property checker for new checks. ## Materials and carbon * Embodied Carbon * Carbon Assessment Speckle's carbon tools are not yet tested for production use. If carbon reporting is a hard requirement, [Speckle Intelligence](/next/analytics/intelligence) may be a better fit today. Let us know via [speckle.community/help](https://speckle.community/help) if you're relying on Embodied Carbon or Carbon Assessment so we can factor that into the rollout. ## CAD structure These widgets remain placeholders until they support CAD model structure in the 2026.9 data format. They may work minimally for some models. * Blocks * Layers * Nested Blocks * Nested Blocks Pivot Table ## Issues * Issues Overview * Issues list ## Other application-specific widgets * Model Properties # Update parameters from the model viewer Source: https://docs.speckle.systems/next/analytics/data-conditioning In 2026.9 you batch-edit parameters in the Elements panel, then apply them in the connector via Issues. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. In 2026.9 you review and batch-edit model parameters from the **Elements** panel in the model viewer, then apply those changes back in Revit, Rhino, or Civil3D. Each batch is still logged as an Issue. This page covers only what changed. For the dashboard-widget path from before 2026.9, editable types, connector apply steps, and known limitations, see [Parameter Updater](/beta/parameter-updater). Parameter updates in 2026.9 run against models in the new data format. If a model has not moved yet, follow [Speckle's data model is changing](/workspaces/data-model-migration). ## What changed Before 2026.9, Parameter Updater is a **Data Conditioning** widget that you add to a dashboard. In 2026.9 that widget is not the path: you work on the models already open in the viewer. * **Where you edit:** the **Elements** panel in the model viewer, not a dashboard widget. * **How you start:** open **Elements**, then choose **Update parameters**. You do not drag a widget from Data Conditioning. * **Which models you can edit:** models loaded in the viewer, not widget data sources you pick separately. * **New attributes:** open **Columns** and use **New attribute name…** while update mode is on. There is no **+** button on the column headers. * **What submit creates:** an Issue that stores the parameter changes. It does not attach a 3D screenshot or viewer state the way the widget does before 2026.9. Apply in the connector is unchanged: open the Issue on the model card and use **Apply changes**. Connector version, host support, and the limits in [Parameter Updater](/beta/parameter-updater) still apply. ## Example use cases Use Parameter Updater when you know the values that model elements should carry and want to set or standardise them in bulk. Common examples include: * **Review and approval:** update an element's **Status** as work progresses, or set an **Approval status** after a review. * **Responsibility and coordination:** assign elements to a discipline, team, owner, or coordination zone. * **Delivery planning:** add a project phase, work package, milestone, or installation sequence to selected elements. * **Asset information:** add or correct asset IDs, system references, locations, maintenance zones, or handover fields. * **Quality checks:** fill missing required parameters or correct values found during model review and validation. * **Data standardisation:** replace inconsistent names, codes, or allowed values with the agreed project terminology. * **Known classification values:** apply an agreed classification code to a selection when you already know which code is correct. These are data-conditioning workflows: you are maintaining parameter values on existing elements. Applying a known classification value is also data conditioning. It becomes autoclassification when the system infers which category or type an element belongs to. ## What you can change With Parameter Updater, you can: * add a new parameter; * insert a value where an existing parameter is empty; * overwrite an existing parameter value; or * clear a parameter value. You cannot delete a parameter. Clearing removes its value but leaves the parameter on the element. ## Update parameters in 2026.9 Open the project and model in the Speckle web app so the 3D view loads. You should see the model and the viewer panels, including **Elements** in the bottom dock. If **Elements** is not showing, open it from the viewer panel switcher, or press Shift+T. You should see a table of elements for the models in the scene. In the Elements toolbar, choose **Update parameters** (pencil). Columns under `properties` become editable, headers show a pencil or lock, and you can group rows. Turning the mode off does not discard staged edits. Scope the table to **All elements**, the current selection, or one loaded model. Edit cells, or with grouping on use **Set all…** and **Set selected…**. Cells that the object does not carry show **Missing parameter** and are skipped. To add a parameter that does not exist yet, open **Columns**, type a name in **New attribute name…**, and add it. You can insert, overwrite, or clear values, but you cannot delete a parameter. When you have unsaved edits, the footer shows the count with **Discard** and **Submit change requests**. Fill in the title and optional Issue fields, then submit. Speckle creates an Issue that stores the parameter changes. You should see a success confirmation, and the staged edits clear. After you submit, apply the Issue in the connector the same way as today. See the apply step on [Parameter Updater](/beta/parameter-updater). ## FAQ In 2026.9 you edit from **Elements** in the model viewer, not from a Data Conditioning widget. The widget path from before 2026.9 is documented on [Parameter Updater](/beta/parameter-updater). Open a model that is already in the new data format, then open **Elements**. **Update parameters** is hidden when the panel is very narrow; widen the dock until the pencil control appears. See [Speckle's data model is changing](/workspaces/data-model-migration) if the model has not moved yet. Yes. Submit still creates an Issue, and you still apply it from the connector Issues panel. Host support, connector version, and apply-time limits are unchanged. See [Parameter Updater](/beta/parameter-updater). # Data Validation in 2026.9 Source: https://docs.speckle.systems/next/analytics/data-validation/overview What changes for Data Validation after models move to the 2026.9 data format, including related objects, value mapping, calculated values, and the removal of project standards. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Use this page when your project is on the 2026.9 data format. Authoring, saving, and result review still work as in the current product. **Project standards** are not in 2026.9. For check and result flows that did not change, see [Data Validation](/analytics/data-validation/overview). This page covers only the differences that change how a check scopes objects, reads properties, binds a related object (direction, all versus any, multi-hop), maps labels before a comparison, and tests a calculated value, plus the Project standards change. ## What stays the same Checks, thresholds, plan caps, BCF export, and result history follow the current guides: * [Checks](/analytics/data-validation/checks) * [Viewing Results](/analytics/data-validation/viewing-results) Authoring still uses a scope and a check. In 2026.9 the editor shows those as short sentences. A rule can also include a related object. ## Project standards 2026.9 does not include **Project standards**. The Data Validation sidebar shows **Run check** and **Checks** only. You cannot create, import, or spawn checks from a project standard. Reuse across the workspace is planned later as a rollup from Checks into workspace standards. That flow is not available yet. Until it is, author and save checks. If your team spent time developing Project standards in the previous Data Validation flow, email [hello@speckle.systems](mailto:hello@speckle.systems). ## Default object scope In the current product, a new check starts with a global filter that keeps connector BIM objects and drops proxy and geometry noise. In 2026.9, a new check starts with an **empty** global scope. The version already contains user-facing objects only, so that starting filter is not needed. Do not follow the current [Default scope](/analytics/data-validation/checks#default-scope) guidance on a 2026.9 version. Leave the global scope empty, then narrow with category, type, or parameter filters in `WHERE` when you need a tighter rule. An existing check can return no objects on a 2026.9 version. Preview shows empty counts and an empty object table. The stored rule still uses the previous-format object filter. That filter is not shown as a control in the 2026.9 check editor, so you cannot clear it in place. Rebuild the check: create a new check, run preview, then save. Unsaved drafts that still carry the old default are cleared when you reopen the editor. Saved checks keep their stored rules. After save, you can edit name and description only. ## Checks against related objects In the current product, a rule looks at properties on one object. In 2026.9 you can also check that object against something it is related to, because those relationships are in the published version. Use **Add related object** on the rule. The editor adds a binding row. The name on the left (`@host`, `@room`, `@connected`) is how later conditions address that object. Pick a relationship from the list the version actually carries. Friendly labels include **Host element**, **Sub-elements**, **Room**, **Bounded room**, **Assembly**, and **Connected element**. Then choose a property on that related object from the path picker. Related paths show as `@host · Fire Rating` in the sentence pills. **Add condition** adds a scope filter above the check. It does not turn the existing check into a filter. Rules display as short sentences, for example **category is Doors**. Select a sentence to edit it. **Add related object** is disabled when the preview version has no relationship data. The tooltip reads **This model has no relationship data — re-publish with a current connector to use related-object rules.** Publish a new version after the project uses the 2026.9 data format. ### Direction, all versus any, and narrowing The arrow on the binding follows the relation **forward** (for example a door toward its host wall) or **backward** (a wall toward the elements hosted on it). Click the arrow to reverse it. **all** (default) means every related object must satisfy the check. **any** means one related object is enough. That setting applies to the check only. A scope filter on a related path still keeps a subject when at least one related object matches, regardless of **all** or **any**. Open **where** and select **Narrow related objects** to keep only some related objects, for example hosts whose category is Walls. Those filters run on the related object. They do not use `@` prefixes. ### When there is no related object A subject with no related object **fails** a check that reads that binding. If a door with no host should be not applicable instead of a fail, add a scope condition that the related path exists (for example `@host` is present) before the check. Examples you can author: * A door's fire rating must match the wall that hosts it * If the host wall is fire-rated, the door must be rated. Unrated walls are not applicable, not a fail (scope on the host rating, then check the door) * Every door must be hosted on a wall * Every wall that bounds a room carries a rating (**all**), or at least one of them does (**any**) * A door can be checked against a room reached through the host wall: add a second related object, set **of** to `@host` instead of **this element**, and pick **Bounded room** or **Room** You cannot remove a binding while a condition still uses `@name`, or while a later binding chains from it. Update those references first. ## Map labels before you compare When a check compares two properties (**Equals property**), 2026.9 can map each side's raw labels onto shared values before it compares them. This is how `60 MIN` and `1 HR` become the same rating, and how a `2 HR` wall can require a door of at least `90 MIN`. Select **Equals property**, pick the other path, then open the comparison control beside it. The control shows `=` until you add a mapping or change the comparison. Set **Compare** to **= equals**, **≥ at least**, or **≤ at most**. Under **This value maps** and **Other value maps**, select **Add mapping**, pick a raw value from the list, and set what it **maps to**. Unmapped values stay as they are. Map both sides to the same numbers when the labels should count as equal. Map the other side to a required minimum and use **≥ at least** when one side must be stricter than the other. The same mapping works when the other path is on a related object, such as a host wall. If preview already lists known values, **Seed N known values** on that mapping list fills it so you do not type every label. Seed one side at a time. The control is hidden when the list is empty or too large to seed in one step. ## Match a property wherever it sits A Fire Rating parameter is not always on the same path. Click the path-matching control next to the path to cycle modes: * **Exact** (`=`) — the full path from the picker * **Suffix** (`*.x`) — every property whose path ends with that segment, for example **Fire Rating**. Every matching value must pass * **Regex** (`.*`) — a regular expression over the full path That covers instance and type placements without a separate rule for each path. Path matching is not available on **Equals property** or **Equals template**. Those operators compare two specific paths. ## Check a calculated value Some rules test a number no single property holds, such as a beam's span-to-depth ratio: its length divided by the depth parsed from a section name like `300x600`. In 2026.9 a rule's scope or check can test a **computed value** calculated from each object's properties. The usual comparisons apply, so the threshold stays a value you can edit. Computed values are created with Speckle Intelligence, available when your workspace plan includes it. On a self-hosted server, it is available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Intelligence](/developers/server/deployment/enterprise-license#optional-intelligence). Describe the calculation to the assistant to create it. In the check editor, select **Generate rule**, or ask [Speckle Intelligence](/next/analytics/intelligence) in **Chat**. Name the inputs, how to combine them, their units, and the threshold. Before it offers the rule, the assistant states the range of values, the units, and how many objects have no value. Confirm the range fits what you asked for. Accept the rule the assistant proposes, then save the check. The rule shows the computed value as **Σ** followed by its name. An example ask: ```text theme={null} Add a rule: for structural framing, the span-to-depth ratio must be at most 20. Divide Length by the depth, which is the second number in the type name (300x600 is 300 mm wide and 600 mm deep). Length is in metres. ``` If you already coloured a model by a calculated value in the 3D viewer, ask the viewer sparkle **Make this a validation rule: the ratio must be at most 20** to reuse that calculation. Select the **Σ** subject in the editor to see the description, the unit, and the SQL behind it. The comparison and threshold stay editable like any other condition. ### Change the calculation Select the **Σ** subject, then **Edit with AI** to describe the change to the assistant, or **Edit SQL** to change it yourself. When you edit by hand, you can change the description, the unit, and the SQL. Select **Preview** to run the edited SQL in its rule. The preview shows the range of values, how many objects it checked, and how many have no value. **Apply** stays disabled until the preview has run on exactly the current SQL, no object has more than one value, and you confirm the description and unit still match. The preview checks the calculation runs and gives one value per object. It cannot tell whether the formula is right. Compare the range with what you expect before you apply. When you open a failing rule in results, the object table adds a first column with each failing object's value against the rule, for example `22.5, expected ≤ 20`. ### When there is no value or more than one An object whose inputs are missing, or do not parse (a type name like `Custom beam`), has **no value**. A scope condition on the computed value drops it, and the check fails it. The object table shows `no value, expected ≤ 20`. To treat those objects as not applicable, ask the assistant to check only objects where the value can be calculated. The calculation must give one value per object. When it gives more than one for any object the rule checks, the rule shows **ERROR** with a message such as `3 objects have more than one computed value`, instead of pass or fail. Ask the assistant to fix the calculation. Computed values work in a rule's scope and check only, not in the global scope or on a related object. Each one reads the properties of the model the check runs on. ## Property paths Always pick property paths from the path picker after a preview model loads. Paths in the current [Checks](/analytics/data-validation/checks#property-paths) examples, such as `parameters.Width.value` and `baseline.length`, come from the previous data format and may not exist on a 2026.9 version. Typical Revit parameters now sit under `properties.Parameters` (for example type Width under `properties.Parameters.Type Parameters.Dimensions.Width`). Use the picker for the paths that exist on your model. ## Versions you can run against Data Validation preview and saved-check runs need a version in the 2026.9 data format. If preview does not load, publish a new version after the project has moved to 2026.9. See [Speckle's data model is changing](/workspaces/data-model-migration). ## FAQ They are not in 2026.9. Author and save checks instead. A later step is a rollup from Checks into workspace standards. That is not available yet. If you already built Project standards, email [hello@speckle.systems](mailto:hello@speckle.systems). See [Project standards](#project-standards). The saved rule still uses the previous-format object filter. That filter is not shown in the 2026.9 check editor, and saved checks cannot change rules in place. Create a new check, run preview, then save. See [Default object scope](#default-object-scope). No. That step is for the current product. In 2026.9 the object set is already the user-facing elements. An empty global scope is the correct starting point. Narrow with category, type, or parameter filters in `WHERE` when you need a tighter rule. The preview version has no relationship data. The tooltip asks you to re-publish with a current connector. Publish a new version after the project uses the 2026.9 data format. See [Checks against related objects](#checks-against-related-objects). A subject with no related object fails a check that reads that binding. Add a scope condition that the related path exists if that case should be not applicable. See [When there is no related object](#when-there-is-no-related-object). **all** requires every related object to satisfy the check. **any** requires one. Scope filters on related paths still keep a subject when at least one related object matches. See [Direction, all versus any, and narrowing](#direction-all-versus-any-and-narrowing). On the door rule, select **Add related object**, choose **Host element**, then compare the door's fire rating to the host's fire rating with **Equals property**. Map labels if one side uses minutes and the other uses hours. See [Map labels before you compare](#map-labels-before-you-compare). On an **Equals property** comparison, open the comparison control beside the other path. Under **This value maps** and **Other value maps**, add a mapping so both labels map to the same number, such as `60`. Unmapped values stay as they are. See [Map labels before you compare](#map-labels-before-you-compare). Click the path-matching control until it shows **suffix** (`*.x`), and set the path to **Fire Rating**. Every matching value must pass. Click again for regex over the full path. Path matching is not available on **Equals property**. See [Match a property wherever it sits](#match-a-property-wherever-it-sits). The calculation could not read one of the inputs, for example a type name like `Custom beam` that does not match the expected pattern. Fix the source data, or ask the assistant to handle that format. See [When there is no value or more than one](#when-there-is-no-value-or-more-than-one). Only when a path no longer exists on the new version. Load preview, pick the replacement from the path picker, and save a new check. Saved checks cannot change rules in place. # Ask questions about your models with Speckle Intelligence Source: https://docs.speckle.systems/next/analytics/intelligence Ask project-scale questions from Chat, ask about the model from the 3D viewer sparkle, and reuse organisation playbooks as skills. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Speckle Intelligence is the assistant in the Speckle web app. You ask in plain language. It reads the models you have published and replies with answers, charts, and — in the 3D viewer — changes to what you are looking at. Use **Chat** in the project sidebar for project-scale questions. It is part of the default project navigation, so it is available from most screens in a project: the project, models, a model page, versions, issues, and similar. Use the sparkle in the main 3D viewer when you are looking at models and want to ask about those loaded models. Reuse organisation playbooks — colour legends, cost and carbon methods, formulas, house style — as [skills](/next/analytics/intelligence-skills). There is no equivalent for this Chat surface before 2026.9. For the before-and-after, see [Compare 2026.8 and 2026.9](/next/whats-new) and [Speckle's data model is changing](/workspaces/data-model-migration). Dashboards stay on [Intelligence Dashboards](/analytics/intelligence-dashboards); this page does not cover them. Speckle Intelligence Chat is available when your workspace plan includes it. On a self-hosted server, it is available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Intelligence](/developers/server/deployment/enterprise-license#optional-intelligence). ## How it works Speckle Intelligence does not upload a Revit, Rhino, Tekla, or other host file to an AI so the AI can rebuild the model in memory. You publish to Speckle as you do today. The assistant then runs read-only queries against the Speckle data already stored for those published versions. That small payload is deliberate. Speckle does not send the whole model into the AI as a giant blob of text, because that would spend your AI credit — and Speckle's — on tokens the assistant does not need. It asks for the facts it needs, keeps those results compact, and writes the reply from them. The goal is to answer from your data without burning budget on a full-model dump. For versions in the new data format, those queries can cover: * Object properties on published models * How parts relate to each other (containment, connectivity, levels, systems, materials) * Where a model was published from (the source application on the version, and types in the published data) * How the project has been updated (who published which version, and what changed between versions) * Files in the workspace library, and registered tables such as CSV or XLSX uploads and warehouse connections (Snowflake, Databricks, Microsoft Fabric), when those exist The assistant can still be wrong if it skips a query or misreads a result. If the data is not there, it is instructed to say so rather than invent structure from a host file. The assistant reads versions in Speckle's new data format. Versions in the old format cannot be queried, so the assistant says there is no queryable data rather than giving partial answers. Publish a new version after the project uses the new format, and questions about properties and about what connects to what or what contains what both work. See [Speckle's data model is changing](/workspaces/data-model-migration). This page does not cover how Speckle handles AI providers or data security. ## Where to ask On day one of 2026.9, Speckle Intelligence has two entry points. They are not the same job. * **Chat** is in the default project navigation, next to **Browse** at the top of the project sidebar. Use it from the project, models, a model page, versions, issues, or another project screen for project-scale questions: the project as a whole, not only the model you have open. * The sparkle at the top right of the main 3D viewer is for questions about the models loaded in that viewer. The **Intelligence** item in the project or workspace sidebar currently opens dashboards, not Chat. ### Ask about the project Open any screen in the project you want to ask about. You should see **Browse** and **Chat** at the top of the project sidebar when Chat is available for the workspace. Select **Chat**. The page title is **Chat**. The empty state reads **Ask about** your project name, with the prompt to ask in plain language. Type a question about the project, or pick a suggested starter if one is shown. You can attach a published model from the composer when the question needs a specific version. Wait for the reply. You should see a conversation in the Chat history, titled from your question, and an answer that uses that project's data. ### Ask about the model in the viewer Open the model in the main 3D viewer. You should see the sparkle control at the top right of the viewer window when Chat is available. Select the sparkle. Chat opens beside the model. The empty state reads **Chat with your model**. The description is **Ask about the models loaded in the viewer, or attach their data to query it.** The composer placeholder is **Ask about this model…** Type a question about the models in front of you, or pick a suggested starter. The reply can change what you see in the viewer as well as answering in the conversation. If **Chat** or the viewer sparkle is missing, your workspace may not include Speckle Intelligence, a workspace admin may have turned **AI features** off in workspace settings, or you may need to choose **Enable AI for this workspace** when the **Enable AI** dialog appears. For the admin switch, see [Turn AI features off for the workspace](/next/it-admin/introduction#turn-ai-features-off-for-the-workspace). ## What changes in 2026.9 Today, Speckle Intelligence looks at properties on each object. In 2026.9, Chat queries versions in the new data format. That is how it reads properties and how parts of a model relate to each other — what connects to what, and what contains what. Versions still in the old format cannot be queried. That is the same change summarised on [Compare 2026.8 and 2026.9](/next/whats-new). Follow [Speckle's data model is changing](/workspaces/data-model-migration) for dates and what to do next. ## What you can ask Ask in the same language you would use with a colleague. If you type a question in a given language, Speckle Intelligence usually keeps replying in that language for the conversation. Use a [skill](/next/analytics/intelligence-skills) or an [AI Rule](/next/analytics/intelligence-rules) when the language or dialect must stay fixed even if someone asks in another language. In **Chat**, ask at project scale: the project as a whole, not only one open model. Chat can build a **Report** from a conversation. The viewer sparkle does not create a saved Report. It answers beside the model with charts and changes to the view. After you save a report, edit sources, tabs, version comparison, and share links on [Create and share Intelligence Reports](/next/analytics/reports). You can share a chat with people on the project so they can view it. They cannot continue that conversation. In the **3D viewer**, ask about the model in front of you. Starters can include **What's in this model?**, **Give me a tour**, **What changed recently?**, and **Color it by category**. If you have an object selected, you may also see **What is this?** You can go further than a first overview. Try asks like: * What models are in this project, and who published recently? * Compare the two most recent versions and summarise what was added, removed, or changed * What sits on this level, and what contains those objects? * What connects to this system? * Give me a report of quantities by category and level (use **Chat**, not the viewer sparkle) * How do the models loaded in this viewer relate to each other? * What is the history of the object I have selected? * Make this a validation rule: the ratio must be at most 20 (after colouring the model by a calculated value) For a full worked example — asking what changed between two versions, then filtering and colouring the model by how significant each change is — see [Assess model changes with Speckle Intelligence](/next/workflows/assess-model-changes-with-intelligence). Model questions need a version in the new data format. Those asks use properties and the relational layer in the new format. These are starting asks, not full tutorials. More detailed walkthroughs for Intelligence Chat will be available soon. Data Validation has its own assistant in the check editor; that flow stays on the Data Validation guides. ## Skills A **skill** is a reusable playbook you invoke with `/skill-name`. Use one for model-aware methods (colour, cost, carbon, formulas) and for the same kinds of custom instructions you would save in a generic AI chat tool — tone of voice, meeting notes, non-AEC analysis. Tuned to how your company works, a skill also spends fewer AI tokens reinventing that wheel on every turn. Create skills in workspace **Settings**, then **Skills** — including **Draft with AI** when you want Speckle Intelligence to write the first draft. Arm them in Chat or in the viewer sparkle. See [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills) for how to create and share a skill, and a catalogue of playbooks teams put in them. ## AI Rules An **AI Rule** is a standing instruction workspace admins set for every conversation. It applies without a slash command — currency, language, disclosure, or any must-follow constraint. Members can read the rules; only admins change them. In Chat, **Workspace rules** shows which enabled rules apply. See [Set standing AI Rules for the workspace](/next/analytics/intelligence-rules). ## FAQ Use **Chat** in the project sidebar for project-scale questions, including building a saved **Report**. It stays in that navigation on most project screens. Use the sparkle when a model is open in the 3D viewer and you want to ask about the models loaded there. The sparkle does not create a saved Report. After you save one, see [Create and share Intelligence Reports](/next/analytics/reports). In the product today, **Intelligence** in the workspace and project sidebars opens dashboards. Speckle Intelligence Chat is a separate surface: **Chat** next to **Browse** in the project sidebar for project-scale questions, or the sparkle at the top right of the main 3D viewer for the model in front of you. Dashboards are documented on [Intelligence Dashboards](/analytics/intelligence-dashboards). No. You publish to Speckle as you do today, from Revit, Rhino, Tekla, or another supported host. Intelligence queries that Speckle data. It does not send the host file, or the whole model as a giant blob of text, to an AI so the AI can rebuild the model from scratch. Keeping what the AI sees compact is deliberate: it protects your workspace AI credit, and Speckle's cost, instead of spending tokens on a full-model dump. Versions in the old format cannot be queried, so the assistant says there is no queryable data rather than giving partial answers. After the project uses the new format, publish a new version. See [Speckle's data model is changing](/workspaces/data-model-migration). Use **New chat** in the Chat history. That starts an empty conversation so the next question is not mixed with an earlier thread. No. Viewing a saved report, or changing its interactive inputs, does not spend AI credit. Chat turns that create or edit the report do. See [Create and share Intelligence Reports](/next/analytics/reports). Actions that require **AI credit**, such as conversations, AI-based report editing, and document parsing, are blocked when the workspace credit has been used up. Stored conversations remain available. The composer shows that the workspace credit has been used up. To restore access, a workspace admin must update the workspace plan or contact us. Put that playbook in a **skill**, share it with **Workspace** visibility, and invoke it with `/skill-name`. See [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills). Use an **AI Rule** so the constraint applies on every turn without arming a skill. See [Set standing AI Rules for the workspace](/next/analytics/intelligence-rules). If you only need that language for one conversation, ask in that language — Speckle Intelligence usually keeps it. A workspace admin turns **AI features** off in workspace **Settings**, then **General**. Chat and the viewer sparkle then disappear for everyone in the workspace until an admin turns the switch back on. See [Turn AI features off for the workspace](/next/it-admin/introduction#turn-ai-features-off-for-the-workspace). # Set standing AI Rules for the workspace Source: https://docs.speckle.systems/next/analytics/intelligence-rules Workspace-admin governance for Speckle Intelligence — standing instructions applied to every conversation. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. An **AI Rule** is a standing instruction Speckle Intelligence follows in **every** conversation in the workspace. You do not type a slash command. Enabled rules shape Chat and the viewer sparkle on each turn until an admin disables or deletes them. Use rules for organisation governance: currency, language, safety, disclosure, or any constraint that must apply even when nobody arms a skill. For opt-in playbooks people invoke with `/skill-name`, see [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills). For where to ask questions, see [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). AI Rules appear when the workspace plan includes Speckle Intelligence Chat. On a self-hosted server, Chat is available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Intelligence](/developers/server/deployment/enterprise-license#optional-intelligence). ## When to use a rule Use a rule when the answer must always follow the same constraint — for example always report costs in EUR, always write Reports in Turkish, never invent missing quantities, or always name the version before a total. Do not use a rule for an optional playbook (colour theme, cost method, carbon factors someone chooses per ask). That is a **skill**. Do not use a rule for a one-off question. If you only need the assistant to match the language of your question for that conversation, ask in that language. Speckle Intelligence usually keeps replying in the same language without a rule. Use a rule when the language must stay fixed even if someone asks in another language. Rules are workspace governance. Only **workspace admins** create, edit, enable, disable, or delete them. Every member can open **Settings → AI Rules** and read the instructions. In Chat, a **Workspace rules** control shows which enabled rules apply to the conversation. ## Create a rule As a workspace admin: Open the workspace, select **Settings**, then **AI Rules**. You should see the heading **AI Rules** and **New rule** when you can manage rules. Select **New rule**. Set **Name** to a short label such as `Currency` or `Turkish reports`. Members see this name in Chat under **Workspace rules**. In **Instructions**, write what Intelligence must do on every turn — for example **Always report costs in EUR.** or **When creating or editing a Report, write all narrative in Turkish.** Select **Create**. You should see the rule on the list, enabled by default. ### Enable, disable, or delete On the AI Rules list, use the switch to **Enable** or **Disable** a rule without deleting it. A disabled rule shows a **Disabled** badge and stops applying on the next conversation turn. Use the row menu to edit or delete. Delete asks for confirmation: conversations stop following that rule on the next turn. Past replies stay as they were. A workspace can hold up to 25 rules. Enabled rules share a combined instructions budget, so keep standing text short. Prefer a focused skill for long playbooks. ## What members see in Chat When at least one rule is enabled, Chat shows a **Workspace rules** control. Open it to see the enabled rule names and the note that they are set by workspace admins and applied to every conversation. Admins also see **Manage**, which opens **Settings → AI Rules**. Rules apply whether or not a skill is armed. A skill adds an opt-in playbook on top; it does not turn rules off. ## What to put in a rule Keep rules short and absolute. Good standing constraints: * Always report costs in the organisation's currency (for example EUR or GBP). * When creating or editing a **Report**, write all narrative, titles, and labels in Turkish (or another language). Keep numbers and units from the data. * Never invent quantities, rates, or carbon factors. If the data is missing, say so. * Always name the version, the publisher, and the source application before any total. * Prefer the organisation's words for coordination issues, levels, and packages. * Do not give legal, safety, or compliance advice beyond what the published model states. * Keep replies suitable for external clients (no internal codenames, no unreleased rates). If the instruction is long, optional, or method-heavy (colour legends, factor tables, full cost methods), put it in a [skill](/next/analytics/intelligence-skills) and keep the rule as the short must-follow line. ## Rules and skills * Standing constraint on every conversation — use an **AI Rule**. * Opt-in playbook with `/skill-name` — use a **skill**. * Match the language of this conversation — ask in that language (no rule required). * One-off question — use Chat with no skill armed. Create rules in [workspace Settings](/next/workspaces/settings) under **AI Rules**. Create skills under **Skills**. ## FAQ Only workspace admins. Members and guests can read the rules list and see **Workspace rules** in Chat. They cannot create, edit, enable, disable, or delete rules. No. Rules constrain answers; they do not stop conversations. To make Chat and the viewer sparkle unavailable to the whole workspace, a workspace admin turns **AI features** off in **Settings**, then **General**. See [Turn AI features off for the workspace](/next/it-admin/introduction#turn-ai-features-off-for-the-workspace). Yes. Enabled rules still apply. The skill adds extra instructions for that message on top of the rules. No. Opening a saved report does not re-run Intelligence. Rules apply when Chat creates or edits content. Ask Chat to revise an existing report if you need it rewritten under a new rule. See [Create and share Intelligence Reports](/next/analytics/reports). The AI stops following it on the next conversation turn. The rule stays on the list with a **Disabled** badge so you can turn it back on later. A workspace can have at most 25 rules. Enabled rules also share a combined instructions length limit. Shorten or disable other rules, or move long playbooks into a skill. Use a **rule** when every Report (and every Chat turn you care about) must be in Turkish without anyone arming a slash command. Use a **skill** when people opt in with `/turkish-reports` for some asks only. If you only need Turkish for one conversation, ask in Turkish — Speckle Intelligence usually keeps that language. See [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills) and [Create and share Intelligence Reports](/next/analytics/reports). # Reuse organisation playbooks with Intelligence skills Source: https://docs.speckle.systems/next/analytics/intelligence-skills Save reusable instructions for Speckle Intelligence Chat, share them across the workspace, and invoke them with /skill-name. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. A **skill** is a reusable playbook for Speckle Intelligence. You write the instructions once — how your organisation colours a model, how it prices work, which carbon factors to use, which words to say, or how replies should sound — and anyone who can see that skill pulls it into a conversation with `/skill-name`. Speckle Intelligence can also **draft the skill for you**: describe the playbook in plain language, or save a chat that already works. Skills live on the workspace. They are how you exercise control at organisation scale without re-explaining the same rules in every chat. A skill tuned to the way your company does things also spends fewer AI tokens reinventing that method on every turn: the assistant follows the playbook instead of rediscovering colour legends, cost codes, carbon factors, house lingo, or tone of voice from scratch. Anything you would put in a generic AI chat tool as a custom instruction can be a skill here — brand voice, meeting notes format, translation rules, non-AEC analysis — as well as model-aware playbooks that use Speckle data. For where to ask questions, see [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). Skills appear when the workspace plan includes Speckle Intelligence Chat. On a self-hosted server, Chat is available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Intelligence](/developers/server/deployment/enterprise-license#optional-intelligence). ## When to use a skill Use a skill when the same behaviour should happen again: a colour theme, a cost or carbon method, a formula, a report shape, a glossary, a tone of voice, or any other repeated instruction you would save in a generic AI assistant. Share it as **Workspace** visibility when the whole organisation should be able to invoke it. The more the instructions match how your company already works, the less each conversation spends credit re-deriving that process. Do not use a skill for a one-off question. Do not use a skill for a standing constraint that must apply to **every** conversation without anyone typing `/skill-name`. That always-on layer is [AI Rules](/next/analytics/intelligence-rules). If you only need the assistant to match the language of your question, ask in that language — Speckle Intelligence usually keeps replying in the same language without a skill or a rule. ## Create a skill Workspace **members** can create skills. Guests can invoke a **Workspace** skill in Chat. They cannot author one, and they usually do not see **Settings → Skills** — they arm skills from the Chat **/** menu instead. Workspace admins can edit or delete any skill in the workspace, including someone else's **Private** skill. You can author a skill three ways. Use Speckle Intelligence when you want a strong first draft; you always review the form before anything is saved. ### Draft with AI Open the workspace, select **Settings**, then **Skills**, then **New skill**. You should see the **Draft with AI** card above the form. In **Draft with AI**, describe what the skill should do in plain language — for example **Audit models for missing fire ratings and report the gaps in a table**, or **Colour the model silver by classification type**. Select **Draft with AI**. Speckle fills **Name**, **Description**, **Instructions**, and related fields. Nothing is created until you save. Edit the draft, set **Visibility** to **Private** or **Workspace**, pin **Knowledge** if the playbook needs a rate card or factor table, then select **Create skill**. You should see the skill on the Skills list. Drafting with AI fills the whole form. If you already typed in the fields, Speckle asks **Replace your edits?** Choose **Draft anyway** only when you want the AI draft to replace what you entered. Drafting spends workspace AI credit the same way other Intelligence actions do. ### Save a chat as a skill In **Chat**, when a conversation already behaves the way you want, select **Save as skill**. Speckle drafts a skill from that thread and opens the create form. Tighten the instructions, set visibility, pin knowledge if needed, then save. Use this when you discovered the method in Chat and want the organisation to reuse it. ### Write the form yourself You can fill the form without a draft. Set **Name** to a slug such as `embodied-carbon` (Chat uses `/embodied-carbon`), write **Instructions** in the organisation's method and lingo, choose **Visibility**, then **Create skill**. ### What you can attach **Knowledge** pins workspace files and data warehouse tables (Snowflake, Databricks, Microsoft Fabric) to the skill. When the skill is active, Chat can draw on those sources — a rate card, an EPD library, a carbon factor sheet, a classification map — without you attaching them every time. A skill can pin up to 20 knowledge sources. Instructions can be up to 8,000 characters. ## Use a skill in Chat Skills work in project **Chat** and in the 3D viewer sparkle. Arming a skill applies its instructions to the **next message** you send. The armed chip clears after that send. It does not rewrite earlier replies, and it does not stay on for the rest of the thread unless you arm it again. Open **Chat** in the project sidebar, or select the sparkle in the main 3D viewer. You should see the composer. Select the **/** control (**Use a skill**), or type `/` and the skill name. Pick `/skill-name`. You should see that skill as a chip above the composer, or as `/skill-name` in the message. Type the question, or pick a conversation starter the skill provides. You should get a reply that follows those instructions — colour legend, cost codes, carbon method, tone of voice, or whatever the playbook defines. If the organisation needs the same playbook on every project, set the skill to **Workspace** visibility and tell people the slash name. Chat does not run workspace skills automatically. The **/** menu also links to **Manage skills** or **Create a skill** when you can author skills. ## What custom skills are for A skill is organisation control you opt into. The catalogue below mixes model-aware AEC playbooks with the same kinds of custom instructions people save in generic AI chat tools. It is not a limit on what you can write. If people keep repeating the same method, lingo, formula, visual rule, or voice, put it in a skill. ### Tone of voice and non-AEC playbooks * Write every reply in the company's brand voice: plain, formal, client-facing, or internal — and keep that voice stable across projects. * Prefer short bullets for directors, and longer technical prose for engineers, as two separate skills rather than one vague assistant. * Translate or localise answers into the workspace language, including how the firm spells product names and place names. * Structure meeting notes, action lists, or decision logs the way the PMO template already does. * Summarise chats for email or a board pack with the firm's subject-line and disclaimer rules. * Explain Speckle data to a non-technical stakeholder without host jargon, or the reverse for a specialist audience. * Apply general analysis habits that are not AEC-specific: always show assumptions, always cite sources, never invent numbers, always end with three next steps. * Turn a pinned company handbook, style guide, or FAQ workbook into **Knowledge** so Chat answers HR, IT, or process questions in the approved words. * Keep a private personal skill for how you like replies formatted, and a workspace skill for the organisation voice everyone should use with clients. ### Colour and view the model * Apply a house colour theme — for example a graduated silver or grey palette by classification type — with clear rules for which host property to read (category, `speckle_type`, type) when models come from different applications. * Colour the loaded model with the company's discipline legend, and keep those colours identical on every project. * Colour by coordination status using the organisation's red / amber / green meanings, not a one-off palette. * Colour by fire rating, acoustic rating, or accessibility category the way the fire engineer and the architect already talk about those values. * Isolate MEP systems with the firm's system names and colours, then restore a clean overview when the walkthrough is done. * Hide furniture, entourage, and site context for a coordination view that matches the BIM execution plan. * Frame typical elevations or a true-north camera so review screenshots look like the office standard, not a random orbit. * Colour by the parameter the firm always uses for phase, zone, or work package, even when the published property name differs between hosts. * Offer darker / lighter / reverse / revert adjustments in the instructions so reviewers can tune the theme without rewriting the skill. * Apply a client-facing colour theme for workshops, and a denser internal theme for design reviews, as two separate skills. ### Cost, carbon, and quantities * Price quantities with the company's unit rates, cost codes, and work breakdown structure, and say those codes out loud in the reply. * Turn room or space data into the organisation's area standard — NUA, NIA, NLA, GLA, GIA, GEA, GBA, or the chargeable area the lease uses — with the same definitions every time. * Apply the firm's measurement rules: wall centreline versus finished face, doors counted in the wall or excluded, and which voids count. * Convert published units into the units the commercial team invoices in, and round the way the cost plan rounds. * Estimate embodied carbon (for example A1–A3) by matching model quantities to a pinned factor table, with category fallbacks and an unmatched list instead of silent guesses. * Separate A1–A3 product carbon from A4 transport and A5 construction when the firm reports that way, and refuse to blend them. * Flag missing rates or missing carbon factors instead of inventing a number, and list the exclusions in the firm's language. * Pin a rate-card spreadsheet or a live warehouse table as **Knowledge** so the skill reads this year's prices, not last year's memory. * Produce a cost or carbon narrative that uses the commercial team's words: elemental, package, provisional sum, contingency — not generic AI phrasing. ### Language, classification, and house style * Use the organisation's names for levels, grids, and storeys, and never swap in a host application's synonym. * Map host categories and IFC types onto Uniclass, OmniClass, or the firm's own classification, and quote the code the document controller expects. * Call coordination issues what the BEP calls them. If the office says "coordination issue", do not say "clash". * Keep spelling, units, and date formats on the regional standard the workspace uses (UK millimetres and DD/MM/YYYY, or US feet-inches). * Address the client by the name in the appointment, and describe the scheme the way the bid did. * Prefer the firm's abbreviations (GA, NBS, RIBA stage, LOD) and expand them only when the audience is external. * Never rename parameters the way a general assistant might. Repeat the published Speckle property names the connectors actually sent. ### Formulas and conversions * Compute steel tonnage from volume and the firm's density, then apply the agreed section utilisation or connection allowance. * Derive door, window, and finish schedules with the takeoff formulas the interior package already uses. * Convert between host units, SI, and the commercial unit of measure in one place so every chat does the same conversion. * Apply percentage complete, earned value, or design maturity rules the project controls team already uses. * Include wastage, lapping, and cutting allowances the estimator uses, and show the allowance as a line, not a silent fudge. * Normalise type marks, family names, and type catalogues into the firm's type-naming pattern before totals. * Recalculate areas when the skill's measurement rule disagrees with a raw property, and say which rule won. ### Reports, tours, and output shape * Structure every commercial reply as executive summary, exclusions, then tables — the same skeleton the director reads on Friday. * Build a saved **Report** from Chat that already uses the firm's rate card and carbon method, then share that report rather than the raw thread. See [Create and share Intelligence Reports](/next/analytics/reports). * Lead a client workshop view sequence: site, envelope, typical floor, services, then risks. * Produce a quantity survey in the column order the cost plan template uses. * Write a change commentary between two versions using the firm's added / omitted / revised vocabulary. * Keep charts in the organisation's preferred breakdown (by level, by Uniclass, by package), not whatever the model tree happens to be. ### Knowledge files and live data * Pin the approved rate card, carbon factor workbook, or product library so Chat does not scrape a random file from the conversation. * Pin a warehouse table for live commercial data so the skill stays current when finance updates the sheet. * Pin a mapping table from host category to company cost code, and instruct the skill to fail closed when a row is missing. * Pin specification extracts or employer's information requirements so answers cite the appointment, not generic good practice. * Pin a legend image or colour dictionary if the visual standard is easier to describe from that file than from prose alone. ### Coordination, quality, and safety * Assess BIM and tabular data readiness for design review, analytics, cost or carbon joins, compliance, handover, or asset reuse — and report gaps in the firm's checklist order. * Turn readiness findings into a versioned conditioning **manifest**: proposed transformations that are explainable, testable, attributable, and reversible, without mutating source data from the skill itself. * Preserve an auditable path from every headline finding to the smallest set of calculations or comparisons needed for the decision (a BIM benchmark style skill). * Review a version the way the BIM manager reviews it: required parameters present, naming pattern held, dummy types called out. * List coordination risks in BEP order (structure vs services, then envelope, then interiors). * Call out fire-stopping, accessibility clearances, or maintenance access with the language the compliance lead uses. * Refuse to answer from versions still in the old data format, and tell the user to publish after the project uses the new format. See [Speckle's data model is changing](/workspaces/data-model-migration). * Always name the version, the publisher, and the source application before any total, so a forwarded answer is auditable. ### Role, region, and programme * Give the quantity surveyor package-based totals, and give the architect room-based totals, as two skills rather than one vague assistant. * Give the structural engineer utilisation and mass, and give MEP flow, load, and system membership, without mixing those audiences. * Switch UK Approved Document language, US code language, or another region's citations by workspace or by skill, not by hoping the model guesses. * Hold a RIBA stage, AIA phase, or in-house gate in the instructions so the assistant does not recommend deliverables that stage does not include. * Keep a private personal skill for how you like replies formatted, and a workspace skill for what the organisation allows everyone to use. If none of those headings fit, write the skill anyway. Model-aware AEC methods and generic chat habits both belong here. The test is repetition: the organisation wants the same control next week, on the next project, in the same words and the same voice. ## Skills and AI Rules * Opt-in playbook people invoke with `/skill-name` — use a **skill**. * Standing constraint on every conversation — use an [AI Rule](/next/analytics/intelligence-rules). * Match the language of this conversation — ask in that language (no skill required). * One-off question — use Chat with no skill armed. Skills do not replace [workspace Settings](/next/workspaces/settings). Create and share skills from **Settings**, then **Skills**. Create standing rules under **AI Rules**. Invoke skills from Chat; rules apply on every turn. ## FAQ A skill is opt-in. Someone must arm it with `/skill-name` or **Use a skill**. For a rule that must apply to every conversation in the workspace, use [AI Rules](/next/analytics/intelligence-rules). Yes, usually. If you ask in a given language, Speckle Intelligence keeps replying in that language for the conversation. Use a skill or an AI Rule when the language or dialect must stay fixed even if someone asks in another language. Only the owner, and workspace admins. Other members do not see it in the picker. A skill you want the organisation to use must be **Workspace** visibility. Guests can invoke a **Workspace** skill in Chat with `/skill-name`. They cannot create, edit, or delete skills, and they usually do not see **Settings → Skills**. Workspace members can create skills. Admins can edit or delete any skill in the workspace. **Skills** in the Settings sidebar appears when you can create skills (workspace member, Chat on the plan, and [**AI features** on](/next/it-admin/introduction#turn-ai-features-off-for-the-workspace) in workspace settings). Guests still arm shared skills from Chat. If Chat itself is missing, see [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). Those conversations continue without it. The history stays. Later messages no longer receive those instructions. On the skill, use **Knowledge**. Pin a workspace file or a warehouse table. When the skill is active, Chat can query that source. Do not rely on pasting the same sheet into every thread. Arming a skill does not spend credit by itself. Sending the next Chat message does, the same as any other turn. A company-tuned skill usually spends less on that turn than reinventing the method in free-form chat. **Draft with AI** and **Save as skill** spend credit when Speckle drafts the form. Viewing a saved report still does not spend credit — see [Create and share Intelligence Reports](/next/analytics/reports). Yes. On **New skill**, use **Draft with AI** and describe the playbook. Or in Chat, use **Save as skill** after a conversation that already works. You always review and edit before **Create skill** saves anything. # Create and share Intelligence Reports Source: https://docs.speckle.systems/next/analytics/reports Edit report layouts, change sources and knobs, use tabs, compare versions, and revoke share links. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. A **Report** is a saved artefact under **Reports** in the project sidebar. Speckle Intelligence **Chat** builds it from a conversation. The viewer sparkle does not create a Report. Open the report to edit the layout, change sources and knobs, add tabs, compare versions, and share a link. Viewing a report, or changing its interactive inputs, does not spend AI credit. Chat turns that create or edit the report do. For asking questions and building the first draft in Chat, see [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). This page covers the report after you save it. Speckle Intelligence Reports are available when your workspace plan includes Intelligence. On a self-hosted server, they are available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Intelligence](/developers/server/deployment/enterprise-license#optional-intelligence). Reports and [Dashboards](/next/analytics/dashboards) are currently distinct products. Dashboards are available on all plans and are built manually; Reports are generated from an Intelligence Chat conversation and require Intelligence. How the two develop alongside each other is something we're actively working out — if you have a Dashboards workflow that shapes what you'd want from Reports, [we'd like to hear it](https://speckle.community). ## Create a report In **Chat**, ask Speckle Intelligence to produce the analysis you want, then save the result as a **Report**. The sparkle in the 3D viewer cannot create a saved Report. Open **Reports** in the project sidebar to find saved reports. The breadcrumb reads **Reports**, then the report name. If the report is missing, the page reads **Report not found.** ## Open and edit Select a report to open it. Edits stay local until you save. There is no auto-save. Use **Add** to insert **Chart**, **KPI**, **Table**, **Viewer**, or **Text**. With a section selected, the widget lands in that section. Otherwise Speckle appends a new section. **Add** opens Chat and pins the new block so the next message can target it. The toolbar can show **Saving…**, **Unsaved changes**, **Saved**, or **Save failed**. Use **Save** to keep changes, or **Discard**. Leaving with unsaved edits prompts **Leave without saving?** The toolbar also offers **Undo** and **Redo** for layout edits made in the editor. Undo does not apply to AI turns — those changes land as a new edit state you can undo or discard. **Share** stays disabled while the report is unsaved. The tooltip reads **Save or discard your changes to share this report.** The **⋯** menu (**More actions**) offers **Open source chat** when you created the report from Chat and you are the creator, plus **Rename** and **Delete**. Delete cannot be undone. ### Properties panel Clicking any element in the editor opens the **Properties** panel on the right. What you see depends on what is selected. **Section** — Set **Title**, **Show title**, **Subtitle**, and **Show subtitle**. Drag the section using the grip in its menu. Convert a plain section to a tabbed section with **Add tabs**, or add another tab to an existing tabbed section with **Add tab**. **Row** — Set **Height** (in pixels) to control how tall the row renders. A row can contain multiple cells side by side. **Widget** — Set a **Title** (required) and optional **Description**. For charts, you can also switch the **Chart type** between bar, line, and scatter — available on AI-generated charts only, not hand-authored ones. Chart **Labels** lets you rename what the chart shows (axis labels, series names) without affecting the underlying values; leave a field empty to keep the original. Use Chat on the report page to ask the AI to create or rewrite content — those turns spend AI credit. Direct edits in the Properties panel do not. ## Change sources and knobs Reports have two **Inputs** surfaces. Name them both. ### Source chips The header strip reads **Inputs · N sources** (or **1 source**). Each chip shows a model, version, project, and alias, or a data source. When you can edit, open **⋯** on a chip for **Change version…** (dialog title **Change version — **), **Swap model…**, and **Revert to saved** when the working copy differs from the last save. ### Section knobs A section can show **Inputs (n)** with knobs such as a rate or occupancy. **Reset** restores each knob to its saved default. A knob in one section can drive widgets in another. Changing knobs does not spend AI credit. Ask Chat to create or rewrite the report if you need new structure. ## Use tabs A section can be **tabbed**. Each tab has its own row stack of widgets. In **Properties** for that section, use **Add tab** or **Add tabs**. Those controls are not in the widget **Add** menu. Rename a tab by editing its label inline. ## Compare versions There is no separate **Version diff** button. Bind two source aliases — two versions of one model, or two models — from the **Inputs** strip. Widgets and Chat can compare those aliases. You cannot remove a source that a comparison widget still uses. Change the version on a chip to retarget the comparison. ## Share and revoke a link Select **Share** to open **Share report**. Access uses the same three rungs as Chat sharing: * **Private** — only the owner * **Project** — anyone in the project can open and view. The description reads **Anyone in can open and view this report.** * **Public** — a link anyone can open without signing in Public links warn that anyone with the link can view the report — including the model data behind its sections. Edits to the report update what the link shows and can read. No sign-in is required. The public token is scoped to the versions the report's sources bind. Speckle shows the raw token **once** when you create the link. Optional password and expiry apply at create time. Turning project sharing off does **not** revoke public links. Those links are independent. Revoke a public link from **Share report**, or from **Project settings** → **Tokens**. If you are not the owner, the dialog reads **You're viewing a report someone shared. Only its owner can change sharing.** Save before you share. Unsaved edits block **Share**. Do not rely on switching the report to private to kill a public URL. Revoke the public link. ## FAQ No. Viewing a saved report, or changing its interactive inputs, does not spend AI credit. Chat turns that create or edit the report do. No. Only **Chat** in the project sidebar can build a saved **Report**. The sparkle answers beside the model. See [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). Project visibility and public links are independent. Turning project sharing off does not revoke public links. Revoke the link from **Share report** or **Project settings** → **Tokens**. Save or discard unsaved changes first. The tooltip reads **Save or discard your changes to share this report.** You also need permission to share. Editors with permission see **Add**, **Save**, **Discard**, and source **⋯** actions. Viewers can open the report and change knobs when inputs exist. Only the owner changes sharing. Non-owners see **You're viewing a report someone shared. Only its owner can change sharing.** # Sync models from Trimble Connect Source: https://docs.speckle.systems/next/connectors/cloud-integrations/trimble-connect Connect Trimble Connect to Speckle for automatic model synchronization. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Beta Connect Trimble Connect to Speckle for automatic model synchronization. Pick files from your Trimble Connect projects, and every new version uploaded to Trimble Connect becomes a new version of a Speckle model — no manual re-uploads. The Trimble Connect integration is available on the **Enterprise** plan. To use it on another plan, [talk to sales](mailto:sales@speckle.systems?subject=Trimble%20Connect%20Integration%20request). ## How it works * **Browsing is personal.** You sign in to Trimble Connect with your own Trimble ID to browse projects, folders, and files. Your Trimble login stays in your browser — Speckle never stores it. * **Background sync uses a service account.** Trimble Connect does not offer application-level (machine-to-machine) access, so each Speckle workspace connects one Trimble account as its **service account**. Speckle encrypts that account's credentials, refreshes them automatically, and uses them to download new file versions in the background. * **Changes are detected by polling.** Trimble Connect has no webhooks, so Speckle checks your synced files for new versions every 5 minutes. ## Prerequisites * A Speckle workspace on the **Enterprise** plan, and **workspace admin** rights to set up the service account (any workspace member can browse and create syncs afterwards) * A Trimble Connect account with access to the projects you want to sync * A Trimble account to act as the **service account** — use a dedicated account (for example `speckle-sync@yourcompany.com`) rather than a personal one, so background sync does not break when someone leaves the team * The service account must be **invited to every Trimble Connect project** you plan to sync (any role that can view and download files) ## Connect the service account Workspace admin only. Do this once per workspace. Open any project in your workspace. In the project sidebar, go to **Integrations** → **Trimble Connect**. In the header, select **Connect service account**. Trimble's sign-in page opens. Sign in with the **service account** (not your personal account) and approve access. You return to Speckle. The header shows **Background sync:** with the service account email and a green indicator. Speckle encrypts the service account's credentials before storing them. They are used only for server-side file downloads and background synchronization, and are refreshed automatically so they never expire from inactivity. Trimble may skip the login screen if you are already signed in to Trimble in that browser. When connecting the service account, Speckle always forces the sign-in screen so you can pick the right account. ## Connect and sync files Any workspace member can do this after the service account is connected. Go to **Integrations** → **Trimble Connect** and select **Connect to Trimble**. Sign in with your own Trimble ID. Choose a **Trimble Connect project** from the selector in the header. Projects from all Trimble Connect regions are listed; the region appears next to each project name. Browse the folder tree and select the files you want to sync. Use search and the source filter to narrow the list. For Revit files, optionally set a **view name** and **reference point** in the selected-files panel. See [Revit options](#revit-options). Select **Create sync**. Each synced file gets its own Speckle model, named after the file and its folder path. The first version imports immediately. After that, every new version uploaded to Trimble Connect is picked up automatically. ## Keep models in sync * Speckle polls your synced folders **every 5 minutes**. A new file version in Trimble Connect typically appears as a new Speckle version within 5 minutes plus conversion time. * The **Syncs** panel on the Trimble Connect page shows every sync in the project, its latest status, and links to the Speckle model. * You can **pause** and **resume** a sync from the Syncs panel. Paused syncs keep their existing versions; they stop watching for changes. * If a synced file is moved or deleted in Trimble Connect, Speckle pauses the sync after a few failed checks and emails the sync's creator. ## Revit options ### View name By default, all elements of a Revit model are imported. To import only the elements visible in a specific 3D view, enter the view's exact name (case-sensitive) when creating the sync. ### Reference point Choose which Revit coordinate origin the model is aligned to: **Internal Origin** (default), **Project Base Point**, or **Survey Point and Shared Coordinates**. Use the same setting across models that need to align in Speckle. ## Supported file formats In default 2026.9 mode, cloud sync supports the same file formats as file uploads. For available formats and compatibility-mode restrictions, see [Supported formats by upload mode](/next/connectors/file-uploads#supported-formats-by-upload-mode). ## FAQ Yes. Speckle only reads and downloads files from Trimble Connect. It never writes to, modifies, or deletes anything in your Trimble Connect projects. Speckle checks for changes every 5 minutes, so expect the new version within 5 minutes plus the time it takes to convert the file. Speckle syncs the file version current at each check; versions superseded between checks, or whose sync fails, are not synced later. See [Sync guarantees](/it-admin/integrations/introduction#sync-guarantees). Autodesk lets an application access files with its own credentials. Trimble Connect currently only supports user-level access, so background downloads run as a real Trimble account. Speckle stores that account's credentials encrypted and rotates them automatically. Trimble has application-level access on its roadmap; once available, the service account step will go away. Workspace admins only. Browsing and creating syncs is open to all workspace members. Yes. Background downloads run as the service account, so it needs access to each project you sync. Files in projects it cannot access fail to download. Existing Speckle versions are unaffected, but background sync stops: syncs pause on their next check and their creators are emailed. Reconnecting a service account resumes them automatically. Two common causes: the file was moved, renamed, or deleted in Trimble Connect (Speckle pauses after several failed checks), or the service account's access was revoked or its login expired. Check the file in Trimble Connect, then reconnect the service account if needed and resume the sync. Make sure the Trimble account you signed in with is a member of that project. Projects from every Trimble Connect region are listed, so region is not the issue. Yes — create a sync for the file in each Speckle project. Each is tracked independently. Yes. Deleting the model removes its sync. The file in Trimble Connect is untouched. ## Getting help Having trouble with the setup? Contact support or ask in the [Speckle Community forum](https://speckle.community/). # File uploads in 2026.9 Source: https://docs.speckle.systems/next/connectors/file-uploads Changes to file uploads in 2026.9, including supported formats, Tekla Structures, Solibri and Vectorworks support, and legacy/compatibility mode, which ends on 1 November 2026. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Check your workspace’s upload mode before uploading a file in 2026.9. Some formats require legacy/compatibility mode, which ends on **1 November 2026**. Tekla Structures uploads are available where enabled. ## Breaking change: supported file formats In 2026.9, the default file upload path no longer accepts **STL**, **3MF**, **3DS**, **AMF**, **DXF**, **X**, **E57**, **IGS/IGES**, **FBX**, **PLY**, or **SLDPRT**. Earlier upload-format lists do not apply to this path. **These formats remain supported for direct uploads in legacy/compatibility mode only until it ends on 1 November 2026.** Move affected workflows to a supported format before then. This affects both drag-and-drop uploads in the web app and uploads through the API. Existing models stay readable; the change affects importing new files and uploading new versions. ## Supported formats by upload mode Availability depends on the conversion services enabled for your workspace. In default 2026.9 mode, cloud file sync supports the same file formats as file uploads. | Format | Extensions | Default 2026.9 mode | Legacy/compatibility mode | | - | - | - | - | | IFC | .ifc | Supported | Supported | | Revit | .rvt | Supported | Supported | | Navisworks | .nwc, .nwd | Supported | Supported | | AutoCAD | .dwg | Supported | Supported | | Rhino | .3dm | Supported | Supported | | Wavefront | .obj | Supported | Supported | | SketchUp | .skp | Supported | Supported | | STEP | .step, .stp | Supported | Supported | | MicroStation | .dgn | Supported | Not supported | | Vectorworks | .vwx | Supported | Not supported | | Solibri | .smc | Supported | Not supported | | Tekla Structures | .tekla, .db1 | Where enabled | Not supported | | Other retained formats | .stl, .3mf, .3ds, .amf, .dxf, .x, .e57, .igs, .iges, .fbx, .ply, .sldprt | Not supported | Supported | In legacy/compatibility mode, cloud sync supports only Revit, Navisworks, AutoCAD and IFC files. ## Additional format: Tekla Structures 2026.9 adds support for Tekla Structures model packages (`.tekla`) and model databases (`.db1`) on deployments where Tekla uploads are enabled. This is not enabled by default; confirm availability with Speckle before relying on it for your workflow. Use the complete model folder when uploading a Tekla model to preserve profiles, shapes, and materials. A `.tekla` package contains the model folder and its supporting catalogs. A `.db1` file alone can be converted, but missing catalogs can reduce profile, shape, and material fidelity. ## Upload a Vectorworks file If your design lives in Vectorworks, you can upload the `.vwx` file to publish it without opening Vectorworks or installing its connector. For the steps, see [Upload a file](/connectors/direct-uploads/introduction#upload-a-file). The [Vectorworks connector](/connectors/third-party/vectorworks) publishes the objects you select; an upload publishes the 3D content of every design layer. ### Files that convert Speckle reads files last saved in Vectorworks 2021 through 2027. Files from other releases are not supported yet. ### What is published * 3D objects on every design layer, including design layers hidden in the document, grouped by story, layer, and type. * Each object's name, type, object properties, and IFC properties. An object whose 3D geometry Speckle cannot read arrives with its properties and no geometry. These parts of the document are not published: * Objects in a class that is hidden in the document. * Sheet layers. * 2D-only objects, such as callouts, data tags, and section lines. Speckle follows the class visibility saved in the file. To include a hidden class, make it visible and save the file before you upload it. ### If a Vectorworks upload fails | Message | What to do | | - | - | | Vectorworks file version *number* is not supported | Contact Speckle support. | | This is not a supported Vectorworks document | Check that the file is a Vectorworks document, not another file renamed to `.vwx`. | | This Vectorworks document uses an unsupported byte order | Contact Speckle support. | ## Upload a Solibri file Upload a Solibri `.smc` file to publish the whole federation saved in it, without opening Solibri or installing a connector. You do not need the original IFC files alongside it. For the steps, see [Upload a file](/connectors/direct-uploads/introduction#upload-a-file). After conversion, open the model in Speckle to view its geometry and inspect its properties. ### Files that convert Files saved in Solibri 9.12 and 26.6 have been verified. Speckle attempts to read `.smc` files from other releases, but their compatibility has not been verified. `.smv` and `.smct` files are not supported. ### What is published * The saved federation, grouped by source model and its spatial hierarchy. * Component geometry with original colours and transparency. * Source properties, Solibri-derived properties, and saved classification results, including group, zone and system memberships. These parts of the document are not published: * Rule sets and checking results. * Presentations. * Issues and BCF data. An upload reads the data saved in the file; it does not run Solibri checks or re-evaluate classifications. Solibri uploads require the default 2026.9 upload mode. Workspaces using legacy/compatibility mode cannot upload `.smc` files. ### Recover missing Solibri geometry For the closest match to Solibri's 3D view, save the file with **Save 3D Representations with Model** enabled under **Settings > 3D** in Solibri. Let the 3D view finish drawing before saving. When the file has no saved 3D representation for a component, Speckle tries to rebuild its geometry. This takes longer and can produce approximate geometry. Components that cannot be rebuilt retain their properties but have no geometry. Open the file in Solibri, enable the setting, let the 3D view draw, save and upload it again. ### Recover a missing Federated Floor property A component's **Federated Floor** property is included only if Solibri computed and saved it. To populate it, open the file in Solibri, group the model tree by **Locations**, and use **Save As** before uploading again. Some components may still have no federated floor. ### If a Solibri upload fails If the upload fails, check that the file opens in Solibri and save it again before retrying. Contact Speckle support if it still fails. ## Update an affected workflow If your workspace uses legacy/compatibility mode, you can continue uploading the affected formats until compatibility mode ends on **1 November 2026**. Before moving to the default 2026.9 mode, export to a supported format or publish through a supported desktop connector. Check the resulting model before switching your workflow: uploads and connector publishing can produce different geometry and properties. See [Uploads and connectors produce different datasets](/connectors/direct-uploads/introduction#uploads-and-connectors-produce-different-datasets). For the upload steps, see [Upload a file](/connectors/direct-uploads/introduction#upload-a-file). For programmatic uploads, see [Uploading IFC and other files](/developers/api/guides/file-uploads). Use the supported formats on this page for 2026.9. ## Temporary compatibility option Legacy mode, also called compatibility mode, retains direct upload support for the affected formats when the older conversion service is enabled. Ask Speckle to confirm availability for your workspace. It ends for every workspace on **1 November 2026**. This exception applies to direct uploads, not cloud sync. Compatibility mode affects the entire workspace's upload and sync routing; it is not a per-file fallback. **DGN uploads are not supported in compatibility mode.** For availability, the **1 November 2026** end date, and how to request it, see [Compatibility mode for ACC sync and uploads](/next/it-admin/compatibility-mode). # Explore what an object is connected to Source: https://docs.speckle.systems/next/connectors/grasshopper/explore Use the Explore node to find the level, room, host, or definition behind a Speckle Object in Grasshopper. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. When you load a model you get the objects themselves: geometry, properties, materials. The model also records how those objects relate to each other. Which level a wall sits on, which room it is in, which block definition an instance uses, what it is hosted on. The **Explore** node surfaces those connections. Plug in any Speckle Object and it works out which relationships exist for that object, then creates an output for each one. Explore supports versions published with 2026.9 onwards, loaded with the current **Load** node. Versions published before then do not record these connections, so there is nothing for Explore to show. See [Grasshopper in 2026.9](/next/connectors/grasshopper/introduction#load). ## Use Explore Inputs: 1. Add a **Speckle Object** input of the thing you want to explore. Speckle Objects, Speckle Geometry, Block Instances, and Collections are all accepted. Outputs: 1. An output is created for each relationship the model records for that object. The set of outputs changes with what you plug in, so a Revit object and a Rhino object produce different ones. ## What you can expect to find The outputs depend on the source application, because different applications record different things. Some examples: * A wall gives you its level, the rooms it bounds, its type properties, and its sub-elements. * A block instance gives you its definition, and the other placements using that same definition. * A whole-model Collection gives you every level and its elevation. * A structural member from ETABS gives you its analysis results. Explore does not repeat what the object already carries. Material, colour, and Collection path are already set on the object when it loads, so they are not shown again here. ## Work with analysis results Structural results come out as several outputs of the same length, one per column of the results: result type, load case, component, station, step, and value. Each row lines up across all of them. Use the normal list tools to group them. **Sift Pattern** or **Member Index** on the load case output pulls out just the results for one case. Outputs only appear for the columns your model actually uses, so a result type without a station does not produce a station output. ## Objects Explore cannot read Some objects have no connections to show: * Objects from a version published before 2026.9. This is by far the most common reason, because older versions do not record connections. * Objects loaded with a **Load (legacy)** node. See [Upgrade Grasshopper to 2026.9](/next/connectors/grasshopper/upgrading). * Objects from inside a block definition, rather than a placed instance. * Objects that were never loaded from Speckle. In these cases Explore shows a remark on the canvas explaining why, and produces no outputs. Republish the model with the current **Publish** node to create a version Explore can read. ## FAQ Explore reads a local copy of the model that your machine may have cleared. Reload the model and Explore picks up its connections again. The usual cause is a version published before 2026.9, or a **Load (legacy)** node. Republish with the current Publish node, then load with the current Load node. # Grasshopper in 2026.9 Source: https://docs.speckle.systems/next/connectors/grasshopper/introduction Node names, Explore, and extra objects in the 2026.9 Grasshopper connector. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. In 2026.9 the Grasshopper connector keeps existing scripts working. Nodes already on your canvas are renamed and hidden from the ribbon. They are not deleted, and no wires break. This page covers only what changed. For publish and load today, see [How to use Speckle for Grasshopper](/connectors/grasshopper/grasshopper). For the step-by-step script upgrade, see [Upgrade Grasshopper to 2026.9](/next/connectors/grasshopper/upgrading). ## What changed * **Load** and **Publish** in the ribbon are the current nodes. Nodes you already placed are renamed **Load (legacy)** and **Publish (legacy)**. They still run. The same rename applies to **(Sync) Load** and **(Sync) Publish**. * **Speckle Data Object** is renamed **Speckle Object**. It is the same node with the same ports. Existing scripts keep working. Its **Geometries** input does not accept Block Instances, because a Block Instance is already its own object. * The current **Speckle Geometry** node has no Name or Properties inputs. Name and properties live on the **Speckle Object** that contains the geometry. Geometry nodes already on your canvas keep those inputs and are renamed **Speckle Geometry (legacy)**. Existing scripts keep working on the renamed nodes. You only need the current Load node if you want Explore, or if you are loading a version a teammate published with the current Publish node. ## Publish Versions from the current **Publish** node need an upgraded connector to read. **Publish (legacy)** can still be read by older connectors. Confirm collaborators have upgraded before you switch. The two nodes are independent of Load. ## Load The current Load node can return more objects than before, including property-only elements such as Revit rooms, levels, and areas. Materials and colours arrive on each object. The **Proxies** output is not on the current Load node. Model-wide properties such as project information arrive on a **Properties** output. The current Publish node has a matching optional **Properties** input. Name and properties live on the **Speckle Object**, not on geometry. A wall is one thing with one name and one set of properties, even when it has three meshes. If each mesh carried its own copy, summing a volume across the model would count that wall three times. To set a name or properties, wire geometry into a **Speckle Object**. **Explore** is a new node. After you load a 2026.9 version with the current Load node, it surfaces relationships such as level, room, host, and block definition. See [Explore what an object is connected to](/next/connectors/grasshopper/explore). Plug in a Speckle Object, Speckle Geometry, Block Instance, or Collection. Explore creates an output for each relationship the model records for that object. The set of outputs changes with what you plug in. Explore does not repeat what the object already carries. Material, colour, and Collection path are already set on the object when it loads. Explore supports versions published with 2026.9 onwards, loaded with the current Load node. Versions published before then do not record these connections, so there is nothing for Explore to show. Objects loaded with **Load (legacy)** also produce no Explore outputs. If Explore reports that nothing is cached for a model that loaded correctly earlier, reload the model. ## FAQ Wrap your geometry in a **Speckle Object** and set the properties there. If you assign a **builtInCategory** property, Revit loads it as a generic model with that category. There is currently no way to create elements that load as native walls or beams in BIM or structural applications. No. Nodes are matched by identity, not by name, so renaming them has no effect on your files. No node turns into a placeholder and no wire is dropped. The usual cause is a version published before 2026.9, or a **Load (legacy)** node. Republish with the current Publish node, then load with the current Load node. It does not. The node in your script is **Speckle Geometry (legacy)** and keeps all of its inputs. The **Speckle Geometry** in the ribbon is a new node without Name and Properties. This is a known issue in the 2026.9 viewer. Mesh colours and colours set with the **Color** input are published correctly, but the viewer does not draw them yet. Loading the model back into Grasshopper or Rhino keeps the colours. See [3D viewer in 2026.9](/next/3d-viewer/introduction#open-a-model). # Upgrade Grasshopper to 2026.9 Source: https://docs.speckle.systems/next/connectors/grasshopper/upgrading What 2026.9 changes for Grasshopper, and how to move an existing script across. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Existing scripts keep working. Nothing on your canvas is deleted. This page is the mechanical path onto the current Load and Publish nodes. For publish and load today, see [How to use Speckle for Grasshopper](/connectors/grasshopper/grasshopper). For node names, Explore, and extra objects, see [Grasshopper in 2026.9](/next/connectors/grasshopper/introduction). To use Explore after you switch, see [Explore what an object is connected to](/next/connectors/grasshopper/explore). Nothing is removed from your canvas and no wires break. The nodes you already have are renamed and hidden from the ribbon, not deleted. ## When to switch | If you... | Then... | | - | - | | Have scripts that work and you are not changing them | Nothing to do. Leave them alone. | | Are building a new script | Use the current nodes. The ribbon only offers those. | | Want the Explore node | Upgrade the script's Load node. | | Load a version published by an upgraded teammate | Upgrade the script's Load node. | ## Before and after | On your canvas | After you switch | | - | - | | **Load** / **Publish** | Unchanged nodes. They support 2026.9 onwards. | | **Load (legacy)** / **Publish (legacy)** | Your existing nodes, renamed. They still work, and they are hidden from the ribbon. | | **Speckle Data Object** | Renamed **Speckle Object**. Same node, same ports. | | **Speckle Geometry (legacy)** | Your existing Speckle Geometry node. It still works, and it is hidden. | | **Speckle Geometry** | New. Geometry, colour, and material — no Name or Properties. | The same rename applies to **(Sync) Load** and **(Sync) Publish**. | Output | **Load (legacy)** | **Load** | | - | - | - | | **Collection** | Data Objects and geometry | Speckle Objects and geometry | | **Properties** | Model-wide properties | Model-wide properties | | **Proxies** | Materials, colours, levels, groups | Not available | ## How to switch Place a **Load** node from the ribbon and move your Speckle Model wire onto it. You should see the same **Collection** output as before. Check that nodes reading that Collection still resolve. Objects come through as **Speckle Objects** rather than Data Objects — the same shape under a new name — so most wires carry straight over. Remove the **Load (legacy)** node once nothing is wired to it. The definition should now load through the current node only. Confirm collaborators have upgraded first. Switching Publish affects people who load your model, not just you. If you are not sure, leave Publish on the legacy node and upgrade Load only. If your script publishes and then reloads in the same definition, use the current nodes for both. A version created by the current **Publish** node cannot be read by a **Load (legacy)** node. ## Messages you might see | Message | What it means | | - | - | | This Load component is deprecated | You are on a legacy node. Nothing is wrong. Upgrade when convenient. | | This version was published before Speckle 2026.9.0 | An older version loaded. Grouping and collection paths may differ. | | This version needs the current Load component | A legacy node hit a version it cannot fully read. Upgrade the node. | | Versions published by this component can be read by older connectors | A reminder from **Publish (legacy)**. Check collaborators before switching. | | The name or properties on the incoming geometry were replaced | The Speckle Object's name and properties win. Set them on the object. | | Replacing the geometry dropped its properties | Swapping a shape does not carry properties across. Use a Speckle Object. | ## FAQ No. Nodes are matched by identity, not by name, so renaming them has no effect on your files. No node turns into a placeholder and no wire is dropped. You can — it is in the same place it always was. The node named **Load (legacy)** is the hidden one, and the **Load** in the ribbon is the current node. It is now called **Speckle Object**. Same node, same ports, same behaviour. It no longer shows a deprecation message on every solve. Yes. Copy and paste still works. Replace it with the current node so the script does not carry the older behaviour forward. No. They are independent. Upgrading Load only is a good first step, because it affects nobody but you. # Navisworks in 2026.9 Source: https://docs.speckle.systems/next/connectors/navisworks/introduction 2026.8 is the last desktop connector. Use it for a 200 MB publish. Upload larger NWC and NWD files. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. There is no 2026.9 Navisworks desktop connector. **2026.8** is the last installer. The 2026.8 connector remains the advised path for a publish around **200 MB**. For larger files, upload an **NWC** or **NWD**. Speckle parses the file on the server, so you do not sit in Navisworks watching a publish progress bar. This page covers only that change. For install, sign-in, and publish in the 2026.8 connector, see [How to use Speckle for Navisworks](/connectors/navisworks). ## What to do * **About 200 MB.** Publish from the **2026.8** desktop connector. That is still the advised path for a publish of that size. Do not wait for a 2026.9 installer. * **Larger files.** Upload an NWC or NWD. Direct upload follows the general file-size limit of **2 GB**. ACC sync of Navisworks files has been tested to **6 GB**. See [Direct uploads](/connectors/direct-uploads/introduction) and [Autodesk Forma Data Management (ACC)](/connectors/cloud-integrations/acc). A file uploaded directly and the same model published from the desktop connector do not produce identical Speckle data. See [Uploads and connectors produce different datasets](/connectors/direct-uploads/introduction#uploads-and-connectors-produce-different-datasets). ## Data format if you stay on 2026.8 The 2026.8 connector publishes Speckle's current data model — the model in use before 2026.9. Speckle may convert that published version to the 2026.9 format on the server. Treat that conversion as best effort, not a guarantee. * In the web app, versions stay readable either way. * Speckle Intelligence can query only versions that are already in the 2026.9 format. See [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). * If you read this data in a script, notebook, Automate function, or other API consumer, follow [Data model migration for developers](/developers/migration/data-model-migration). Do not assume the version was converted, and do not assume it stayed on the old model. NWC and NWD uploads follow the upload path: new format by default, or the old format if the workspace is in [compatibility mode](/next/it-admin/compatibility-mode) until **1 November 2026**. Compatibility mode does not apply to desktop-connector publishes. ## Desktop-only workflows If a file is larger than the upload or ACC sizes above, or you have a workflow that only the desktop connector can do, tell Speckle in [speckle.community/help](https://speckle.community/help). Those cases will be noted for consideration. As of now there is no 2026.9 connector. ## FAQ Use the **2026.8** connector for a publish around **200 MB**, and when you need session filters such as a selection, saved search, or saved view. Upload an NWC or NWD when the file is larger, or when you do not want to leave Navisworks open on a publish progress bar. Yes, on **2026.8**. That is the last installer. There is no 2026.9 package. New publishes from that connector use the current data model. Server-side conversion to the 2026.9 format is not guaranteed. If you consume the data in code, see [Data model migration for developers](/developers/migration/data-model-migration). Not as of now. If a file above the upload or ACC sizes, or a desktop-only workflow, blocks you, post in [speckle.community/help](https://speckle.community/help) so it can be considered. The desktop connector cannot match the throughput of server-side NWC and NWD ingest on large files. Speckle takes that processing so you do not watch a progress bar in Navisworks. A 200 MB publish from the 2026.8 connector is still the advised desktop path. No. The Navisworks connector has always been publish-only. You still cannot load Speckle models back into Navisworks. # Connectors in 2026.9 Source: https://docs.speckle.systems/next/connectors/overview How connectors adopt the new data format in 2026.9. Publish and load stay the same. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. If you publish and load through Speckle connectors, your day-to-day work stays the same in 2026.9. After you update a connector, new publishes use the new format going forward. Most people do not need to do anything beyond updating their connector. Navisworks has no 2026.9 installer — see [Navisworks in 2026.9](/next/connectors/navisworks/introduction). For how to publish and load in each design tool today, see [Connectors](/connectors/overview). For dates and the full workspace steps, see [Speckle's data model is changing](/workspaces/data-model-migration). For a compact before-and-after table, see [Compare 2026.8 and 2026.9](/next/whats-new). This page covers the shared data-format change for connectors. 2026.9 pages exist for Revit, Grasshopper, Power BI, Navisworks, and Trimble Connect. For any other design tool, use the connector guides under **Current** in the version selector — see [Design tools without a dedicated page](#design-tools-without-a-dedicated-page). ## File uploads in 2026.9 The default upload path accepts fewer file formats in 2026.9. STL and the other affected formats remain supported for direct uploads in legacy/compatibility mode until it ends on **1 November 2026**. See [File uploads in 2026.9](/next/connectors/file-uploads) for supported formats and alternatives. ## Design tools in 2026.9 * [Revit in 2026.9](/next/connectors/revit/introduction) — reference points and model placement * [Grasshopper in 2026.9](/next/connectors/grasshopper/introduction) — node names, Explore, and script upgrades * [Power BI in 2026.9](/next/connectors/power-bi/introduction) — Get Tables and the 2026.9 3D visual * [Navisworks in 2026.9](/next/connectors/navisworks/introduction) — no 2026.9 desktop connector; **2026.8** is the last installer * [Trimble Connect in 2026.9](/next/connectors/cloud-integrations/trimble-connect) — new beta cloud sync (Team and Enterprise) ## Design tools without a dedicated page These tools have no dedicated 2026.9 page. Update the connector when a 2026.9 build exists. Publish and load stay the same. How-to remains under **Current** in the version selector — see [Connectors](/connectors/overview). * ProjectWise on-prem, ProjectWise Cloud, and other cloud integrations without a 2026.9 page (ACC, Databricks, Snowflake) * DGN / MicroStation / OpenRoads * Tekla Structural Designer * Rhino, SketchUp, Archicad, Blender, Civil 3D, Plant 3D, AutoCAD, ETABS, and Tekla Structures * Third-party connectors (Vectorworks, Karamba3D, ShapeDiver) A 2026.8-or-earlier connector cannot load data published by a 2026.9-or-newer connector. Check the receiving connector's supported data format before updating a shared workflow. Vectorworks does not yet support loading the 2026.9 data format. See [Why can't I load a model into Vectorworks anymore?](#why-cant-i-load-a-model-into-vectorworks-anymore). Compatibility mode applies to ACC sync and drag-and-drop uploads. It does not change the data format published or loaded by desktop connectors. ## What stays the same You still publish and load through your connectors, and you still view and share in the web app. Your existing connectors keep working. Models you already published stay readable. ## What changes After your project moves to the new data format, publish, load, and view are faster. New publishes from an updated connector use the new format going forward. A 2026.8 Navisworks publish still uses the pre-2026.9 data format; the server may convert it, but that is not guaranteed. ## What you should do Update your connector from **1 September 2026**, and no later than **1 November 2026**. Publish and load as usual after updating. New publishes use the 2026.9 format; existing models stay readable. Navisworks has no 2026.9 installer. Keep using the 2026.8 connector for publishes around 200 MB; upload larger NWC and NWD files. See [Navisworks in 2026.9](/next/connectors/navisworks/introduction). ## FAQ
The model was published from a connector that has already updated to 2026.9 — Revit, Archicad, or any other design tool once it updates. Vectorworks' current read path doesn't support that format yet. No 2026.8-or-earlier connector can load data published by a 2026.9-or-newer connector, so this isn't specific to Vectorworks. Ask the publisher to use a **2026.8** connector build until Vectorworks ships its own 2026.9 read-side update — download it from [releases.speckle.systems](https://releases.speckle.systems/). # Power BI in 2026.9 Source: https://docs.speckle.systems/next/connectors/power-bi/introduction Load Speckle models with Get Tables, relate on Object Key, and bind the 2026.9 3D visual. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. In **Get Data**, select **Connect to Speckle (Custom)**. Power Query calls the function **Speckle - Get Tables**. These instructions use Power BI connector release **2026.10.0**. The default Simplified layout loads a small Objects table plus Properties and Relations functions, instead of one wide table. The new 3D visual streams geometry from Speckle over a WebSocket and requires WebGPU. This page covers only what changed. For legacy workflows and unchanged setup guidance, see [How to use Speckle for Power BI](/connectors/power-bi/power-bi). Existing `Speckle.GetByUrl` reports can keep working when their target versions contain JSON data. To follow versions published only in the new data format, see [Upgrade Power BI to 2026.9](/next/connectors/power-bi/migration). ## What changed `Speckle.GetTables` accepts model, version, federated, and project URLs. The default **Simplified** layout provides three Navigator entries: * **Objects** has one row per object. Its standard columns are `Object Key`, `Application ID`, and `Model Info`. Federated loads also include `Source Model`. * **Properties** is a function. Pick the properties the report needs from a list, then load a table that contains `Object Key` and those property columns. This table replaces the single flat table that `Speckle.GetByUrl` returned. * **Relations** is a function. Choose outgoing graph relations such as `ON_LEVEL` or `IN_ROOM`, then load a table that contains `Object Key` and those relation columns. Create one-to-one relationships from the invoked Properties and Relations tables to Objects using `Object Key`. ## Functions | Function | Where it appears | Behavior | | - | - | - | | `Speckle.GetTables(url, options)` | **Connect to Speckle (Custom)** in Get Data | Returns the navigation table for the new data model | | `Properties(paths?, useFullPaths?)` | A Navigator entry bound to each loaded model | Returns `Object Key` plus the selected property columns | | `Relations(relationNames?)` | A Navigator entry bound to each loaded model | Returns `Object Key` plus selected outgoing relation columns | | `Speckle.AddProperties(source, propertyPaths, objects?, useFullPaths?)` | M code only | Adds selected properties to Objects. An optional Objects table can filter rows and keep extra columns | | `Speckle.AddAllProperties(source, objects?, useFullPaths?)` | M code only | Adds every property path to Objects. Intended for property-light models | | `Speckle.AddRelations(objects, relations, relationTypes, nodes, relationNames)` | M code only | Adds selected outgoing, one-hop relations to an Objects table | `Properties` and `Relations` are bound to the loaded model. They are not global M functions. `useFullPaths` is a logical value. `false` uses the shortest unique suffix and `true` uses the full dotted path. The connector adds numeric suffixes when names still collide at full depth. `Speckle.AddProperties` and `Speckle.AddAllProperties` take the navigation table returned by `Speckle.GetTables` as `source`. Their optional Objects override can filter the result and preserve extra columns. `Speckle.Objects.*` and `Speckle.Models.*` helpers still exist. They operate on the legacy `Speckle.GetByUrl` table only. They do not accept the tables returned by `Speckle.GetTables`. For the retained-function list, see [Upgrade Power BI to 2026.9](/next/connectors/power-bi/migration#retained-functions). ## Load Select **Get Data**. Search for Speckle, then select **Connect to Speckle (Custom)** and **Connect**. You should see the **Speckle Model URL** input. Paste the URL from the web app and select **OK**. Sign in when prompted. You should see Objects, Properties, and Relations in Navigator. Select **Transform Data** to open Power Query. Enable load for Objects. Select the Properties function, pick the properties the report needs in the **Properties** list, then select **OK** and **Invoke** to create a new query. Do the same with Relations for fields such as levels or rooms. Enable load for the resulting tables and leave the function queries with load disabled. After **Close & Apply**, create one-to-one relationships from these tables to Objects using `Object Key`. Power Query with the Properties function selected and its Properties list open, showing property paths with checkboxes The **All tables** layout also exposes Property Values, Property Paths, Object Types, Type Properties, the raw Relations table, Relation Types, and Nodes. Use these tables for custom relationships. Nodes includes `Elevation`, which can sort level names. The Properties function uses the shortest unique suffix for column names by default. Set **Use full paths** to `true` to use full dotted paths. If two names still collide at full depth, the connector adds numeric suffixes such as `.1` and `.2`. Instance values use unprefixed column names. Type values use the `Type_` prefix. For Get Tables loads, use the Properties and Relations Navigator functions, and relate on `Object Key`. Do not pass Get Tables output into `Speckle.Objects.*` or `Speckle.Models.*` helpers. ## View The new visual has four data fields: **Model Info** (required), **Object Keys** (required), **Object Data (Tooltip)**, and **Color By**. Use `Objects[Object Key]` as the standard object binding. `Application ID` remains supported, but large models require an extra lookup dictionary that can add tens of megabytes to the load. Geometry no longer passes through the Power BI dataset. The visual streams it from Speckle over a WebSocket, becomes interactive after the first geometry arrives, and continues loading in the background. In the Visualizations pane, select **Import a visual from a file**. Browse to `Documents/Power BI Desktop/Custom Visuals`, select `Speckle Power BI 3D Visual.pbiviz`, and **Open**. You should see the imported visual in the pane. Add the imported visual to your report. Check that its fields include **Object Keys**. The older visual has **Object IDs**. Drag `Objects[Model Info]` into **Model Info** and `Objects[Object Key]` into **Object Keys**. Drag tooltip fields into **Object Data (Tooltip)** and the category field into **Color By**. You should see the first geometry arrive, then the rest stream in the background. From 2026.10.0, the new visual has a separate identity and leaves legacy visuals in place on import. Add the new visual and connect its fields separately. Releases 2026.9.0 through 2026.9.2 shared the legacy identity and could replace legacy visuals on import. Use 2026.10.0 or later to keep both visuals in a report. The 3D visual requires WebGPU. There is no fallback. If WebGPU is missing, the visual shows an error. Firefox on macOS currently allows eight GPU storage buffer bindings, and the 3D visual needs nine, so it will not render in Power BI Service reports opened there. Use a Chromium-based browser or Power BI Desktop instead. The visual's Edit page supports per-category color overrides and a diagnostics mode. Color overrides remain fixed when the report theme changes. Diagnostics show streaming statistics and recent events. The toolbar sits at the bottom center and contains Zoom Extents and Camera. Camera includes orthographic projection, Move camera on filter, and Top, Front, Left, Back, and Right views. Resizing the visual rebuilds its render targets. The visual reads Power BI data in 30,000-row windows. When a real filter is active, it can process up to one million rows for exact isolation. Above 30,000 filtered rows, the visual keeps the viewport responsive but disables tooltips and click selection for that selection. Chart-click highlights on very large models are sampled. Use a slicer when exact isolation matters. The server must serve 4.0 artifact bundles and advertise a geometry stream. The Power BI client must run in a WebGPU-capable environment. The visual uses the existing OAuth flow and receives a limited-scope token for each load. The account's main token does not enter the report. ## FAQ Invoke the **Properties** function: pick the properties you report on, select **OK**, then **Invoke**. The result has one row per object, with `Object Key` and one column per property. For the 3D visual, also load Objects and relate it on `Object Key`, because `Model Info` lives there. To get it all in one table in M, use `Speckle.AddProperties(Source, {"path.one", "path.two"})`, where `Source` is the `Speckle.GetTables` result. The **All tables** layout is on. It adds supporting tables for building custom relationships. Most reports need only the default **Simplified** layout: set **Table layout** to Simplified under Advanced options, or remove `[TableLayout = "All tables"]` from the `Speckle.GetTables` call. No. Models with many property sets can have hundreds of paths, and every selected path adds a column and refresh time. Start with the properties the report uses. To add more later, edit the invoked query's step or invoke Properties again. Type part of its name in the list's search box, for example a property set name. The list shows full dotted paths such as `properties.Quantities.Qto_SpaceBaseQuantities.NetFloorArea`. The resulting column uses the shortest unique end of the path, such as `NetFloorArea`, unless you set **Use full paths** to `true`. Select **Connect to Speckle (Custom)**. Power Query calls this function **Speckle - Get Tables**, but Get Data uses a different label. The **Speckle Model URL** input still accepts your model URL. `Object Key` is the standard join and visual binding. `Application ID` still works, but large models need an extra lookup dictionary that can add tens of megabytes to the load. `GetTables` reads artifact bundles. JSON-only versions published before a 4.0 connector need `Speckle.GetByUrl`, or the model must be republished with a 4.0 connector. No. The installer copies the visual file to your Documents folder. Import that file into your report yourself; there is no automatic update through AppSource. To move from the legacy visual to the new one, follow the [migration steps](/next/connectors/power-bi/migration#add-the-new-3d-visual). Section box, view modes, edges, ghost mode, and named scene views are unavailable. Filtered-out objects are hidden. Top, Front, Left, Back, and Right remain available. Exact minimum versions for Speckle Server, Power BI Desktop, and WebView2 are not confirmed. Power BI Desktop's embedded WebView2 and Chromium-based browsers viewing Power BI Service both support the visual. Firefox on macOS does not: it supports WebGPU, but currently allows only eight GPU storage buffer bindings, and the visual needs nine. Other browsers on macOS allow ten or more. Windows and Android browsers generally allow sixteen or more. This is a known, accepted limitation. Firefox may raise the limit later. Not yet. Filtered-out objects are hidden outright instead of shown dimmed. There is no ghost icon or equivalent toggle in this release. This is a known rendering-stability issue in the viewer, not specific to Power BI — the same viewer now runs in the web app, the Power BI visual, and published reports. It shows up most often with objects far from the model origin or in models with very large bounds. The fix ships in the web viewer first, then in the following Power BI visual release, which is not on the same cadence. # Upgrade Power BI to 2026.9 Source: https://docs.speckle.systems/next/connectors/power-bi/migration Pin a broken report, rebuild queries with Get Tables, and add the new 3D visual. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Use these steps when your report needs to load versions published in the new data format. They use Power BI connector release **2026.10.0**, which supports both existing `Speckle.GetByUrl` queries and new `Speckle.GetTables` queries. For the new tables and visual, see [Power BI in 2026.9](/next/connectors/power-bi/introduction). For legacy workflows and unchanged setup guidance, see [How to use Speckle for Power BI](/connectors/power-bi/power-bi). There is no automatic conversion. Renaming the function in the Advanced Editor is not enough. From 2026.10.0, the new visual has a separate identity and leaves legacy visuals in place on import. Releases 2026.9.0 through 2026.9.2 shared the legacy identity and could replace legacy visuals on import. Use 2026.10.0 or later to keep both visuals in a report. ## When to switch Your report is at risk if all three statements are true: * It uses `Speckle.GetByUrl`. * It points to a model URL instead of a specific version. * The model will get new versions from a 4.0 authoring connector or an IFC file upload. Version 4.0 authoring connectors and IFC files uploaded in the web app create artifact-only versions. The next refresh then fails with `JsonRepresentationUnavailable`. Pinning to a pre-4.0 version URL is a stopgap. Rebuild the report if it must keep following new versions. Reports whose target versions still contain JSON data can keep using `GetByUrl` and the legacy visual. Updating the connector alone does not require a rebuild. ## Before and after | Before | After | | - | - | | Existing query calls `Speckle.GetByUrl` | **Connect to Speckle (Custom)** creates a `Speckle.GetTables` query | | `Speckle.GetByUrl` returns one flat table | The invoked **Properties** table has one row per object | | Join and color on `Application ID` | Join and bind on `Object Key` | | Legacy 3D visual | Separate new visual with **Model Info** and **Object Keys** from Objects | | JSON-only versions | Artifact bundles published with a 4.0 connector | | Version contains | `Speckle.GetByUrl` | `Speckle.GetTables` | | - | - | - | | JSON and artifacts | Returns the legacy flat table | Returns the new tables | | JSON only, published before 4.0 | Returns the legacy flat table | Fails and directs the user to `GetByUrl` or republishing | | Artifacts only, published with 4.0 | Fails and directs the user to `GetTables` | Returns the new tables | ## How to switch ### Pin a broken report If the report already fails, pin it to the last version published before 4.0. A model whose first version is artifact-only, such as a new IFC upload, has no version to pin to: go to [Rebuild the queries](#rebuild-the-queries). Open Power Query and select the query that calls `Speckle.GetByUrl`. You should see the model URL in the formula. Change the model URL to `.../models/MODEL_ID@VERSION_ID` for the last version that still contains JSON. You should be able to refresh against that version again. After you pin the URL, the report no longer follows new publishes. Continue the steps below when the report must pick up new versions. ### Rebuild the queries Use the existing model URL. Do not rename `GetByUrl` to `GetTables` in the Advanced Editor. Select **Get Data**, search for Speckle, then select **Connect to Speckle (Custom)** and **Connect**. Paste the existing model URL in **Speckle Model URL** and sign in when prompted. You should see Objects, Properties, and Relations in Navigator. Select **Transform Data** and enable load for Objects. You should see one row per object, with `Object Key`, `Application ID`, and `Model Info`. Select the Properties function, pick the columns used by the report in the **Properties** list, then select **OK** and **Invoke** to create a new query. Do the same with Relations for fields such as levels or rooms. Enable load for the resulting tables and leave the function queries with load disabled. After **Close & Apply**, create one-to-one relationships from the resulting tables to Objects using `Object Key`. For Navigator layouts, column naming, and M helpers, see [Power BI in 2026.9](/next/connectors/power-bi/introduction). ### Reconnect charts, measures, and slicers Update every report element that references the old table. Check column names. Shortened property paths, numeric collision suffixes, and the `Type_` prefix may change table references and calculations. ### Add the new 3D visual In the Visualizations pane, select **Import a visual from a file**. Import `Speckle Power BI 3D Visual.pbiviz` from `Documents/Power BI Desktop/Custom Visuals`. The new visual appears in the pane alongside the legacy visual. Add the imported visual to your report. Check that its fields include **Object Keys**. The older visual has **Object IDs**. Drag `Objects[Model Info]` into **Model Info**, `Objects[Object Key]` into **Object Keys**, tooltip fields into **Object Data (Tooltip)**, and the previous category field into **Color By**. Recreate any color rules on the new Edit page. You should see your model in the new visual. Refresh the report and test its filters, charts, and tooltips. Confirm that the new visual shows the expected objects before deleting the legacy visual from that page. Installing a connector update copies the visual file to your Documents folder. Visuals already imported into reports do not update automatically through AppSource. ### Remove the old queries Delete the `GetByUrl` queries after no visual, measure, or relationship references them. ## Retained functions Existing M functions remain available. Data-shaping helpers still expect the legacy `GetByUrl` table shape. The project issues function is independent of both object data paths. | Function | Behavior | | - | - | | `Speckle.GetByUrl(url, ExpandProperties)` | Keeps its 3.x contract and reads JSON versions only. It is no longer the published Get Data entry | | `Speckle.GetStructuredData(url)` | Returns the legacy flat objects table from JSON | | `Speckle.SendToServer(url)` | Downloads the version's raw JSON object tree | | `Speckle.Objects.Collections` | Shapes legacy `GetByUrl` output | | `Speckle.Objects.CompositeStructure` | Shapes legacy `GetByUrl` output | | `Speckle.Objects.MaterialQuantities` | Shapes legacy `GetByUrl` output | | `Speckle.Objects.Properties` | Shapes legacy `GetByUrl` output | | `Speckle.Models.Federate` | Operates on legacy `GetByUrl` shapes | | `Speckle.Models.MaterialQuantities` | Operates on legacy `GetByUrl` shapes | | `Speckle.Revit.Parameters.ToNameValueRecord` | Operates on legacy `GetByUrl` shapes | | `Speckle.Utils.ExpandRecord` | Operates on legacy `GetByUrl` shapes | | `Speckle.Project.Issues(url, getReplies)` | Remains independent of both object data paths and works with old and new reports | | `Speckle.GetVersion()` | Returns the connector version string, unchanged | The installer places the data connector in the current user's Documents folder. Reports opened by that user use the installed connector. Existing `GetByUrl` queries still work when their target version contains JSON data. ## FAQ Invoke the **Properties** function and pick the properties the report uses. The result has one row per object, with `Object Key` and one column per property. See [Power BI in 2026.9](/next/connectors/power-bi/introduction#faq) for the M alternative. The version is artifact-only. `GetByUrl` reads JSON data only, so pinning works only for a version published before 4.0. Models created by a 4.0 connector or a new IFC upload have no such version. Rebuild the query with **Connect to Speckle (Custom)**. The downstream query steps still expect the old flat table and will fail. Rebuild the query from **Connect to Speckle (Custom)**, load Objects, and invoke Properties and Relations. If the error's `RootObjectId` starts with `bundle.`, the version is artifact-only. Some connector releases report this as `DirectDownloadFailed` instead of `JsonRepresentationUnavailable`. The fix is the same: rebuild the query with `Speckle.GetTables`. Pinning to a version published before 4.0 works only if the model has one; a new IFC upload does not. No. Pinning to `.../models/MODEL_ID@VERSION_ID` is a recovery option. If the report must follow new publishes after a 4.0 authoring connector is in use, rebuild it with `Speckle.GetTables` and add the new visual. With 2026.10.0, importing the new file leaves legacy visuals in place. A new visual needs `GetTables` output before it can display a model. A legacy `GetByUrl` table cannot supply its required fields. Keep the legacy visual until you have loaded the new tables and checked the report. # Revit in 2026.9 Source: https://docs.speckle.systems/next/connectors/revit/introduction Apply Transform, the placement picker, and how published geometry stays in Revit's internal coordinates. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. In 2026.9, published geometry stays in Revit's internal coordinates. The **Reference Point** dropdown still selects the datum you want consumers to use. Speckle stores that choice next to the model as a **model placement**. The viewer and the Revit connector apply it when they load. This page covers only what changed. For install, sign-in, publish, and load in today's connector, see [How to use Speckle for Revit](/connectors/revit/revit). For the breaking change and bundle consumers, see [Upgrade Revit to 2026.9](/next/connectors/revit/migration). ## What changed One publish can now serve every datum. Collaborators choose their placement on their side instead of asking you to republish. The send settings still look the same. What changed is a new **Apply Transform** toggle next to **Reference Point**, and that the transform is stored separately by default. A linked model's placement in the host document is never written as the model's reference point. ## Publish Expand **Settings** at the bottom of the **Select objects** dialog while publishing a new version. You should see **Reference Point** and a new **Apply Transform** toggle. Set **Reference Point** to **Internal Origin** (default), **Project Base Point**, **Survey Point**, or **Shared Coordinates**. Survey Point uses the survey point origin only, with no rotation. Shared Coordinates includes True North rotation. Use Shared Coordinates when you need to match a survey or civil model's orientation, not just its origin. Keep **Apply Transform** off. That is the default, and it is the 2026.9 path: geometry stays in internal coordinates, and placement is stored separately. You should see the toggle remain off when you publish. Turn **Apply Transform** on only if a downstream tool that does not understand model placements needs the geometry pre-positioned. Once it is on, one publish cannot serve every datum for that model. If the selected base point cannot be found in the document, the connector falls back to Internal Origin. The viewer then shows **Internal Origin (fallback)**. ## Load The **Reference Point** receive setting is unchanged: **Source** (default), **Internal Origin**, **Project Base Point**, **Survey Point**, or **Shared Coordinates**. Models published from a 2026.9 connector land in the right place regardless of the sender's **Apply Transform** choice. If the sender baked the transform, Revit inverts it automatically. For the receive-setting steps in today's connector, see [How to use Speckle for Revit](/connectors/revit/revit). Re-publish once from a 2026.9 connector to unlock the picker and datum switching for an existing model. ## Placement record Scripts and SDK consumers read `modelPlacement.*` from `eav.model`, not `referencePointTransform` on the root object. Apply the placement yourself unless the sender turned **Apply Transform** on. * `modelPlacement.transform` — Internal Origin to the datum selected on publish. The value is 16 row-major doubles. Translation is in `modelPlacement.units`. * `modelPlacement.default` — which datum that is (`internalOrigin`, `projectBasePoint`, `surveyPoint`, `sharedCoordinates`). * `modelPlacement.options.*` — the transform for every available datum, so a consumer can switch. * `modelPlacement.appliedToGeometry` — `false` by default. `true` only if the sender turned **Apply Transform** on. If it is `true`, invert the transform before you place the model. * `referencePoints.*`, `projectLocation.trueNorthAngle` — raw base-point positions, True North, and site location. The viewer applies `modelPlacement.transform` at load time. The placement picker swaps in any of the `options.*` transforms. ### Source (default) * 2026.9, Apply Transform off: nothing applied. Geometry is already in internal coordinates. * 2026.9, Apply Transform on: sender's transform inverted automatically. * v3 / migrated model: sender's root transform inverted, as before. ### Named receive datums For **Internal Origin**, **Project Base Point**, **Survey Point**, or **Shared Coordinates**: * 2026.9, Apply Transform off: your chosen datum transform applied. * 2026.9, Apply Transform on: sender's transform inverted, then your datum applied. * v3 / migrated model: as before. For the numbered consumer steps and the re-publish path, see [Upgrade Revit to 2026.9](/next/connectors/revit/migration). ## View After you publish, the web viewer lands the model using that placement. A **placement picker** lets you inspect the same model from any other datum without republishing. The datum you published with is marked **(published)**. ## FAQ Check the placement picker. The published datum is marked **(published)**. If it shows **Internal Origin (fallback)**, the survey point could not be resolved in your document. Yes. The placement record describes the datums in your document. Collaborators still need matching shared coordinates for models to overlay. What you no longer need to do in 2026.9 is republish to change datums. Publish with **Shared Coordinates**. **Survey Point** uses the survey point origin only, with no rotation. # Upgrade Revit to 2026.9 Source: https://docs.speckle.systems/next/connectors/revit/migration Re-publish once, and switch scripts from root referencePointTransform to bundle modelPlacement. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. This page is the mechanical path onto 2026.9 model placement. For Apply Transform, the placement picker, and the placement record, see [Revit in 2026.9](/next/connectors/revit/introduction). For install, sign-in, publish, and load in today's connector, see [How to use Speckle for Revit](/connectors/revit/revit). ## When to switch Existing v3 models keep working. Re-publish from a 2026.9 connector if you need the viewer placement picker and named datums. Scripts and SDK consumers that read `referencePointTransform` on the root object must switch to `modelPlacement.*`. ## Before and after | Before | After | | - | - | | Geometry rewritten so the chosen datum is origin | Geometry stays in Revit internal coordinates | | Root `referencePointTransform` | Bundle `modelPlacement.*` on `eav.model` | | Datum kind not recorded | Named datum plus `options.*` for every datum | | One publish per consumer datum | One publish; consumers pick the datum | v3 connectors that read 2026.9 models get the old root-object transform rebuilt from the placement record. When a 2026.9 consumer reads a v3 model, the old root transform is migrated into a placement record, but the datum kind cannot be recovered. ## How to switch Use a 2026.9 Revit connector. You should see **Apply Transform** next to **Reference Point** in publish settings. Leave **Apply Transform** off, then publish as usual. You should see a new version on the model. Keep **Apply Transform** off unless a downstream tool that does not understand model placements needs the geometry pre-positioned. ### Scripts and SDK consumers Assume the model is already in scope. 1. Read `modelPlacement.*` from `eav.model`. 2. Apply `modelPlacement.transform`. The value is 16 row-major doubles. Translation is expressed in `modelPlacement.units`. 3. If `modelPlacement.appliedToGeometry` is `true`, invert that transform before you place the model. Do this regardless of the receive datum. 4. Then apply the receive datum you want, if it is not **Source**. AutoCAD and Civil 3D follow the same contract. ## FAQ It is not the placement record in 2026.9. Read `modelPlacement.*` from `eav.model`. See [Placement record](/next/connectors/revit/introduction#placement-record). Invert `modelPlacement.transform` before you place the model, then apply your receive datum. Revit does this automatically. A custom consumer must do the same. No. They keep working. 2026.9 consumers rebuild a placement record from the old root transform. Re-publish once from a 2026.9 connector if you need the viewer placement picker and named datums. Report it with the model URL and the publish and receive settings on both sides. The viewer's placement overlay shows world origin, model origin, and each reference point. # Get element data without object.children in 2026.9 Source: https://docs.speckle.systems/next/developers/api/introduction What changes for GraphQL and REST in 2026.9, and how to replace object.children filtering. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. This page covers what changes for **GraphQL and REST** consumers in 2026.9 — scripts, low-code flows (Power Automate, Zapier, n8n), and custom integrations that call the API directly. It is not a full reference: for everything unaffected, keep using the current [GraphQL](/developers/api/graphql) and [REST](/developers/api/rest) documentation. For the conceptual model behind this change and who's affected, see [Object model in 2026.9](/next/developers/object-model/overview) and [Data model migration for developers](/developers/migration/data-model-migration). Sending a 2026.9 version's `referencedObject` to the legacy objects endpoints (`/objects/ {projectId}/{objectId}`, `Project.object(id)`) returns **404** with `error: "BUNDLE_REFERENCE_NOT_FOUND"`. Treat that as "this version uses the new format," never as "empty model." You can tell which format a version uses from the shape of `referencedObject` itself — see the table below. ## Tell the two formats apart | `referencedObject` looks like | Format | `object.children` filtering | | - | - | - | | A 32-character hex string (e.g. `c462dbafa995e9d1ee3c60ccb0bc1087`) | Object graph, 2026.8 and earlier | Works as before | | `bundle...` | 2026.9 columnar format | **Not supported** | Workspaces in compatibility mode — sometimes called "legacy conversions" or "legacy sync" in support conversations, same thing — can still produce the first shape for uploads and ACC sync, until **1 November 2026**. See [Data model migration for developers](/developers/migration/data-model-migration#whos-affected) for how it's granted. Check the shape of `referencedObject` on the version you actually have — don't assume based on upload date or workspace settings alone. ## What's no longer supported For a version whose `referencedObject` is a bundle reference, these stop working. There is currently no GraphQL-level replacement for the filtering and selection behavior — see [Get element data today](#get-element-data-today) for what to use instead. * **`Object.children(query:, select:, limit:)`** — the server-side filter/select mechanism (for example, filtering by an IFC type and selecting a handful of property paths in one request). * **`Object.totalChildrenCount`** — nothing to count against; there is no object tree. * **`Project.object(id: referencedObject)`** — the reference isn't a content hash, so there's nothing to look up. * **Reading geometry as JSON** (the `data` field) — 2026.9 geometry is stored in a binary format read by the Viewer and SDKs, not served as a JSON payload. ## Get element data today Prior to 2026.9, one GraphQL query could filter elements by property and select just the fields you needed: ```graphql Prior to 2026.9 theme={null} query ($myQuery: [JSONObject!]) { project(id: "PROJECT_ID") { object(id: "REFERENCED_OBJECT") { totalChildrenCount children(query: $myQuery, select: ["id", "Name"], limit: 100) { totalCount objects { id data } } } } } ``` ```json Variables theme={null} { "myQuery": [{ "field": "ifcType", "value": "IfcDoor", "operator": "=" }] } ``` ```bash 2026.9 theme={null} curl -X POST \ "https://app.speckle.systems/api/v1/projects/PROJECT_ID/models/MODEL_ID/versions/VERSION_ID/eav/query" \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"format": "json"}' ``` The 2026.9 call returns every indexed property on every element, one row per property, rather than a pre-filtered result: ```json theme={null} [ { "objectId": "3a1f...", "path": "ifcType", "valueText": "IfcDoor", "valueNum": null, "type": "string", "units": null }, { "objectId": "3a1f...", "path": "name", "valueText": "Door-01", "valueNum": null, "type": "string", "units": null } ] ``` To reproduce the "every `IfcDoor`" filter from the query above, filter that array yourself: Filter the rows for `path == "ifcType"` and `valueText == "IfcDoor"`, and collect their `objectId` values. The outcome is the id of every door in the model. Filter the full array again for rows whose `objectId` is one of those ids. The outcome is every property row belonging to a matching element. Group the result by `objectId` to get one record per door with its properties. The outcome matches what `select` used to return, without the size limit. In a low-code tool, that's two filter steps in sequence — two **Filter array** actions in Power Automate, two **Filter** nodes in n8n — no custom code, just more steps than the single GraphQL query it replaces. There's also a `GET .../versions/{versionId}/eav/download` variant for a plain download, and a `GET .../models/{modelId}/eav/download` variant that always serves the latest version. This endpoint doesn't accept filter parameters yet — it always returns the whole properties table, and you filter after receiving it. That's fine at door-count scale; less fine on a model with hundreds of thousands of elements. ## Payload size, and moving to the bundle directly Losing `select` and `query` doesn't break anything — you still end up with the same elements once you've filtered client-side — but it does change what "minimal" means. The old query returned exactly the fields you asked for, for exactly the elements that matched. The properties endpoint above always returns everything: every indexed property, on every element, every time you call it. That's a fixed cost that scales with model size, not with how much of the model you actually wanted. For a one-off check, or a model with a few hundred elements, that's a non-issue. For something that runs repeatedly against a large model — a nightly flow, a live dashboard — downloading and re-filtering the full properties table on every run is the wrong shape for the job, even though it technically works. At that point, don't look for a lighter version of the JSON export — there isn't one yet (see the FAQ below). Instead, stop treating the version as "a JSON payload to filter" and start reading its bundle directly: ``` GET /api/v2/projects/{projectId}/models/{modelId}/versions/{versionId}/artifacts ``` This returns presigned URLs to the version's actual parquet files — the same underlying data the properties export flattens into JSON, but structured for reading only the columns and rows you need instead of pulling the whole table every time. This is what the SDK paths below attach to directly, which is why they scale where the JSON export doesn't. This only helps if your integration can run code that reads Parquet — it isn't a fit for most low-code tools, which is exactly the properties-export endpoint's use case instead. Self-hosted n8n is a partial exception; see the FAQ below. ### From an SDK instead of raw HTTP For anything that can run real code rather than a low-code flow, an SDK's native path reads the bundle above directly instead of downloading the full properties table yourself: * **Python:** see [Assess specklepy breaking changes](/next/developers/sdks/python/breaking-changes) — `operations.receive3` gives direct, filtered property access (`model.objects_with("ifcType")`), and the legacy `operations.receive` keeps working as a compatibility path. * **.NET:** see [Assess .NET SDK breaking changes](/next/developers/sdks/dotnet/breaking-changes). ## FAQ Probably not. If the failure happens at upload time — a 400 error, code `UNSUPPORTED_FILE_TYPE` — you're almost certainly still calling the deprecated `startFileImport` mutation, which the 2026.9 server rejects outright as of 1 September 2026. See [File uploads](/developers/api/guides/file-uploads#what-developers-need-to-know) to switch to `startFileIngestion`. This page covers a different symptom: uploads that succeed, but querying elements back afterward returns null or empty. The version you queried is in the 2026.9 format — check whether `referencedObject` is a `bundle.` reference (see [Tell the two formats apart](#tell-the-two-formats-apart)). This isn't a bug or a temporary gap: server-side filtering over the object tree doesn't apply to that format. Use the properties endpoint above instead. Yes, unchanged. Nothing on this page affects a version whose `referencedObject` is a hex string. The two formats can coexist — check the version you actually have rather than assuming based on project or workspace. Probably not. A version's id is reserved as soon as ingestion starts, but the version — and its properties — don't exist until ingestion actually succeeds, which can take from several seconds to around a minute depending on the file and rail. Querying immediately after upload will legitimately show nothing. Poll `Model.latestIngestion.statusData` until it reports `ModelIngestionSuccessStatus`, then query the version it names — don't fire the read on a timer or a webhook that isn't actually tied to ingestion completion. No — it works for any version that already has a properties artifact built, hex-referenced or bundle-referenced. It 404s with `"Version not found or has no EAV artefact"` if that version hasn't had one built yet, which is a different failure than "wrong format." Bundle versions always have one; older versions may or may not, depending on whether they've been through backfill. Not documented yet. This page will be updated when that changes. For now, download and filter client-side. Compatibility mode affects new uploads and ACC sync going forward; it doesn't change versions that already exist. Confirm you're querying the version created after compatibility mode was turned on, and that its `referencedObject` is a hex string, not a `bundle.` reference. See [Data model migration for developers](/developers/migration/data-model-migration#whos-affected) — compatibility mode ends **1 November 2026** either way, so plan the move regardless. Not available today for 2026.9 versions — count distinct `objectId` values in the properties export, or use an SDK's native accessors (see [From an SDK instead of raw HTTP](#from-an-sdk-instead-of-raw-http)). Not natively, in most cases. Power Automate and Zapier have no built-in way to parse Parquet — that's a platform gap, not something Speckle can route around. n8n is a partial exception: its Code node can't import external npm packages on n8n Cloud, so the same limitation applies there, but a self-hosted n8n instance can read Parquet if you enable external modules (`NODE_FUNCTION_ALLOW_EXTERNAL`) or install a community node built for it — that's a deliberate setup step, not the default. The properties export endpoint exists specifically so low-code tools have a plain-JSON option that works everywhere, cloud or self-hosted, with no extra configuration. See [Payload size, and moving to the bundle directly](#payload-size-and-moving-to-the-bundle-directly). Two questions decide it: can your integration run code that reads Parquet, and does it run repeatedly against a large model? If either answer is no — a low-code flow, a one-off check, a small model — use the JSON properties export; it's simpler and the overhead doesn't matter. If both are yes — a script or service running on a schedule against a model with many thousands of elements — read the bundle directly instead. See [Payload size, and moving to the bundle directly](#payload-size-and-moving-to-the-bundle-directly). Yes. Format is decided per version, at the time it's created, not per project or workspace. Older versions and versions made while compatibility mode was active can be hex-referenced while newer versions on the same model are bundle-referenced. Always check the version you're actually reading, never assume from a sibling version or from when the project was created. # Attaching results to objects in 2026.9 Source: https://docs.speckle.systems/next/developers/automate/attaching-results AttachResultToObjects and attach_result_to_objects still key by a content-hashed id. What that means for a function run against a 2026.9-format model. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. If your function calls `AttachResultToObjects` (.NET) or `attach_result_to_objects` (Python) to flag individual objects, this page covers what happens when it runs against a model in the 2026.9 data model. This is a different problem from the results not being visible in the product UI yet — see [Viewing Automate results in 2026.9](/next/developers/automate/viewing-results) for that. This page is about the attach call itself, inside your function code. There is no dedicated 2026.9 path for this API yet. What's below is the current, accidental behavior of the compatibility projection Automate still receives through — not a supported or tested contract. Don't build a function that depends on the specifics here holding. ## What the attach call expects Both SDKs key the objects you pass by `id`, the content-hashed Speckle object id, and carry `applicationId` alongside it: ```csharp theme={null} // Speckle.Automate.Sdk — AutomationContext.AttachResultToObjects Dictionary ids = affectedObjects.ToDictionary( x => x.id.NotNull($"You can only attach {level} results to objects with an id"), x => x.applicationId ); ``` ```python theme={null} # speckle_automate — AutomationContext.attach_result_to_objects ids[o.id] = getattr(o, "applicationId", None) ``` Both raise if the object you pass has no `id`. Bundle-only 2026.9 versions have no content-hashed id at all — see [Object model in 2026.9](/next/developers/object-model/overview) — so this call should not work against them. ## Why it doesn't fail today It doesn't fail, but not because it was built to handle 2026.9 data. The objects your function receives for a bundle-only version still come back as a `Base` tree through Automate's compatibility projection, and on that projection `id` is set equal to `applicationId` rather than left as a content hash. The dictionary above ends up keying an object by its own applicationId (`ids[applicationId] = applicationId`), which happens to satisfy the `NotNull` check and produce a result Automate can store. That's a side effect of a decision made for a different problem (receive fidelity on the compatibility path), not a designed identity story for Automate. There is no committed spec for what this API looks like once Automate has its own bundle-era path, and no ticket number to point at yet. An object your function constructs itself, or receives with neither `id` nor `applicationId` set, still throws. This isn't limited to objects you read from the model — check any object you build in the function before attaching a result to it. ## Results stored before a model was migrated A run that finished before its model moved to the 2026.9 format stored its results against the content-hashed `id`. Migration doesn't carry that hash into the migrated data: objects are identified by `applicationId` only, and an object that had no `applicationId` is keyed as `spk:` followed by its old hash. The stored results are kept as they were, but the ids inside them no longer match any object in the migrated model. Runs made after migration don't have this problem, because they key results by `applicationId`. Re-run the automation against the migrated version to get results that line up with its objects. ## What to do today Objects you receive from a 2026.9-format model carry one. Objects your function constructs itself need `applicationId` set explicitly, or the attach call throws regardless of `id`. Don't parse, compare, or cache by `id` expecting it to be a stable hash of the object's content. For a bundle-only version it's the same value as `applicationId`; for an object-graph version it's still a real hash. Treat `id` as an opaque key either way. Because this is compatibility-projection behavior and not a designed contract, a future Automate release can change how identity is keyed here without warning. Don't build tooling that depends on `id == applicationId` continuing to hold. ## FAQ No. [Viewing Automate results in 2026.9](/next/developers/automate/viewing-results) is about the product UI not showing results yet. This page is about the attach call inside your function succeeding or failing. A function can attach results successfully and still have nothing visible in the viewer. Automate's bundle-era story is a separate, not-yet-scoped effort. There's no spec, ADR, or ticket for it yet. This page will be replaced once one exists. Not by id. Results stored before migration reference the old content-hashed `id`, which the migrated model no longer carries. Re-run the automation on the migrated version. Better to make sure every object you attach a result to carries an `applicationId` before you call the attach method. Catching the exception hides a real problem: an object your function built without identity set. # Automate in 2026.9 Source: https://docs.speckle.systems/next/developers/automate/introduction Where Speckle Automate lives in the 2026.9 web app — Functions, project Automations, and workspace Automation. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Speckle Automate still runs your code when a new version is published on a model. The 2026.9 web app no longer uses the old Automations-tab wizard. Functions live on a workspace **Functions** page. You create an automation from project **Settings → Automations**. This page covers those surfaces only. Function authoring, testing, and the SDK stay on the [current Automate documentation](/developers/automate/introduction) until a later 2026.9 developer pass. For dates and who must act on the data-model change, see [Data model migration for developers](/developers/migration/data-model-migration). Running a function against a model in the 2026.9 data model works the same as always, but you currently can't see the results — not in the viewer, not on the project dashboard. See [Viewing Automate results in 2026.9](/next/developers/automate/viewing-results) before assuming a run failed. If your function attaches results to individual objects, see [Attaching results in 2026.9](/next/developers/automate/attaching-results) too — that call has its own, unrelated caveat for 2026.9-format models. Speckle Automate is available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Automate](/developers/server/deployment/enterprise-license#optional-automate). ## Find functions Functions are not in the workspace sidebar. Open them from a project, or go to `/workspaces/{slug}/functions`. Open the project, then **Settings → Automations**. You should see a search field, **View functions**, and **New Automation**. Select **View functions**. The workspace **Functions** page opens. You should see a search field and a **New function** button above a card grid. **New function** starts the create-function flow. Templates and GitHub authoring still follow [Create a function](/developers/automate/create-function). ## Create an automation An automation ties one function to one trigger model in a project. Open the project, then **Settings → Automations**. You should see the automations table, or **No automations yet.** Select **New Automation**. The **Create automation** modal opens with **Function**, **Trigger model**, and **Automation name**. Choose a function, choose the model that should trigger a run, name the automation, then select **Create**. The new row appears in the table. Live automations show **Triggered by** and the model name. The table can show a **Disabled** badge and a **Test** badge. Test automations show **Connected to** instead of **Triggered by**. They are a sandbox for local development. They do not run when someone publishes a new version, and they do not execute published functions. **Create test automation** in the modal switches to that path; **Standard automation** switches back. ## Manage functions in workspace Settings Workspace **Settings → Automation** lists functions that projects in this workspace can use. The table includes each function name, owner, and ID. The row menu includes **Regenerate token...** when you are allowed to rotate that function's token. An in-app **Open docs** control on this page may still point at an old URL. Use the Automate guides linked above, not that control. ## FAQ 2026.9 moved automations into project **Settings → Automations**. The old wizard screenshots on [Create Automation](/developers/automate/create-automation) describe the previous UI. From project **Settings → Automations**, select **View functions**. That route is the workspace Functions page. **New function** lives there. A test automation will not run when a new version is published. Open the automation from the table if you need to change or remove it. Use **Standard automation** in the create modal when you want a live trigger. # Viewing Automate results in 2026.9 Source: https://docs.speckle.systems/next/developers/automate/viewing-results Why the results doughnut icon is missing for models in the 2026.9 data model, and what to do meanwhile. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Automate still runs your functions against models in the 2026.9 data model, exactly as described in [Who's affected](/developers/migration/data-model-migration#whos-affected). A run against a 2026.9-format model completes, and its results are recorded, the same as any other run. This page is about seeing results in the product UI. If your function calls `AttachResultToObjects` or `attach_result_to_objects` inside the run itself, see [Attaching results in 2026.9](/next/developers/automate/attaching-results) for that separate caveat. The results indicator in the product UI and a documented API don't cover a model in the 2026.9 format right now. The Dashboards Automate results widget is the way to see them. If you're troubleshooting a run that appears to have succeeded but produced nothing visible in the viewer, this is why — it isn't a sign the run failed. ## What's missing For a model still in the current (pre-2026.9) data model, results show up exactly as described in [Viewing Automation Results](/developers/automate/viewing-results): a doughnut icon in the 3D viewer and in the project model list, both opening the same results summary. For a model in the 2026.9 data model, that icon does not appear in either place. This isn't specific to any one function or trigger — it applies to any 2026.9-format model with a completed run. There's also no documented, supported API to read the results back as a substitute. Automate functions can write results during a run, but nothing on this site currently documents a query for reading them back afterwards. (The equivalent gap for Data Validation checks specifically is tracked separately; an undocumented internal path exists there but carries no stability guarantee — see [Data Validation](/next/analytics/data-validation/overview) if that's what you're looking for.) ## Results in dashboards Dashboards include an **Automate results** widget that shows a version's automation runs and the results each function recorded, and isolates the objects a result refers to in the dashboard's 3D view. It reads a result's object ids and matches them to objects in the model by `applicationId`, so it works for the same reason [new runs do](/next/developers/automate/attaching-results#results-stored-before-a-model-was-migrated) and not for results stored against a content-hashed `id` before the model was migrated. ## What to do meanwhile Add the widget to a dashboard on the project and pick the model and version. It lists the runs and their results, and selecting a result isolates its objects in the 3D view. If you need to see results for a model that would otherwise land in the 2026.9 format — through ACC sync or drag-and-drop upload — ask us to switch the workspace into compatibility mode. It keeps that data in the format the current viewer and dashboard already render correctly. See [Data model migration for workspaces](/workspaces/data-model-migration). Compatibility mode is a bridge, not a fix. It ends for every workspace on **1 November 2026**. Check the automation's run history from project **Settings → Automations** rather than looking for the results icon. A completed run with no visible icon is this limitation, not a failure. ## FAQ Yes, if the run history shows it completed. The results icon and any API read path are what's missing for 2026.9-format models — the run itself, and what it produced, aren't affected. Yes, through the Dashboards Automate results widget. The other option is compatibility mode, which keeps new data in the format the existing viewer supports, so the results icon stays visible the normal way until compatibility mode ends on **1 November 2026**. No committed date yet. It depends on the same underlying frontend work covering the 2026.9 data model more broadly — see [Viewer developer notes in 2026.9](/next/developers/viewer/introduction) for the closest thing to a timeline. # Building applications on 2026.9 Source: https://docs.speckle.systems/next/developers/building-applications Where to start if you build an app that reads Speckle data rather than a connector — viewer apps, data-only apps, and why there is no drop-in replacement for the object-graph loaders. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. This page is for people building an **application on top of Speckle data** — a dashboard, an internal tool, a web app, a service that reacts to versions. Not a connector: you are not publishing from a host application, you are reading what others published. In 2026.9 a version's data is a [bundle](/next/developers/building-integrations) of parquet files rather than an object graph, and that changes how your app gets at it. Which door you take depends on whether you render. You import `@speckle/viewer`. Bridge the bundle to the object shape the viewer converts, with sample code you copy into your app. You read properties, quantities or geometry without the viewer. Read the bundle directly — the load mechanics are the same ones every non-SDK consumer uses. Writing scripts with a Speckle SDK instead? The SDK applies every bundle rule for you. Start from the [.NET](/next/developers/sdks/dotnet/breaking-changes) or [Python](/next/developers/sdks/python/breaking-changes) 2026.9 pages. ## My app writes data Publishing is the harder half. A 2026.9 version is a bundle built and uploaded through an ingestion, and there is no published JavaScript bundle builder — `@speckle/objectsender` writes object graphs, and .NET and Python are the only SDKs that build bundles today. That leaves three honest options, in the order most teams should consider them: | Option | When it fits | | - | - | | Publish from .NET or Python instead | The writing half can move process or language | | Implement the bundle contract yourself | You must stay in JavaScript, and can carry a parquet writer and the SGEO encoder | | Ask for compatibility mode | You need time, your consumers still read object graphs, and you can move off by 1 November 2026 | The wire sequence, the correctness rules and a build order are in [Publish a bundle from your own code](/next/developers/building-integrations/publish). Read it before choosing the second option: it is a real piece of work, and unlike the read path there is no worked sample. ## Why there is no drop-in object-graph loader If your app is built on `@speckle/objectloader` or `@speckle/objectloader2`, the natural ask is a version of those packages that reads bundles and hands you the same object graph — `getRootObject()`, `__closure`, `getObjectIterator()`, unchanged. That is not coming, on purpose. Emulating that surface would mean rebuilding the object graph that 2026.9 retires: a third implementation of the receive fidelity contract, kept in step with the .NET and Python SDKs forever, reconstructing hashes and closures that no longer exist in the data. It would also teach new apps a shape the platform is moving away from. What to do instead depends on what you were using the graph for. | What you used the object graph for | In 2026.9 | | - | - | | Reading properties across objects | Read the eav tables. Objects are keyed by `applicationId`, properties by dotted path | | Walking hierarchy | Read typed relations. Grouping is `IN_COLLECTION` and the scene view, not nested `elements` | | Getting geometry to draw | Decode SGEO from the geometry shards, or bridge to the viewer | | Object identity across versions | `applicationId`, not a content hash | The mechanics for all four are in [Load a bundle in your own code](/next/developers/building-integrations/load). That page is written for any non-SDK consumer, which includes you — it is not connector-specific. A loader that fetches `referencedObject` from the objects endpoints gets a 404 on every 2026.9 version. Dispatch on `Version.schemaVersion` before you fetch, and keep your existing reader for the older shape. ## What stays the same Your Speckle token, the GraphQL API for projects, models and versions, webhooks, permissions and sharing are unchanged. So is the shape of the problem: list a version, fetch its data, key your app's state to something stable. Only the fetch and the identity changed. # Building integrations in 2026.9 Source: https://docs.speckle.systems/next/developers/building-integrations The language-neutral model behind every 2026.9 producer and consumer. The bundle, the bundle builder, and where publish and load go from here. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. If you connect a host application or a service to Speckle with your own code rather than a Speckle SDK, 2026.9 changes what you write and read. There is no root object to serialize and no object graph to walk. A version is a **bundle**, a set of parquet files, and a **model ingestion** is how the server turns your upload into a version. This page introduces that model and points to the two flows built on it. It is the 2026.9 successor of [Data model and build order](/developers/connectivity/data-and-build). These pages are for people who build connectors, sync services, and other producers or consumers. If you write scripts with a Speckle SDK, the SDK applies every rule here for you. Start from the [.NET](/next/developers/sdks/dotnet/breaking-changes) or [Python](/next/developers/sdks/python/breaking-changes) 2026.9 pages instead. Open an ingestion, write and upload a bundle, and wait for the version. The wire sequence, the correctness rules, and a build order. List a version's artifacts, download the files you need, and rebuild objects, geometry, instances, grouping, and appearance from the bundle. Decide **publish only** or **publish and load** for your host before you start, the same way as today. See [Publish and load](/developers/connectivity/integration-depth). ## What changes | Concern | Before 2026.9 | In 2026.9 | | - | - | - | | What you write | One root object with nested `elements`, serialized as JSON objects | A bundle: parquet files for objects, properties, geometry, and a graph of nodes and relations | | Object identity | Content hash per object, plus a `__closure` table on the root | `applicationId` per object. Objects, geometry, and nodes get dense integer keys that are local to one bundle | | Hierarchy and shared assets | Nested `elements` and Proxy arrays on the root | Grouping containers, structural nodes, and typed [relations](/next/developers/object-model/relations) | | Geometry | `displayValue` objects in JSON | SGEO binary blobs in a sharded geometry table | | How a version is created | Upload objects, then call create-version with the root id | Open an ingestion, upload the bundle, complete it. The server creates the version | | When the version exists | When create-version returns | When the ingestion reaches `success`. Completing the upload is not enough | | Version metadata | Message and source application on the create call, units on the root | Source application on the ingestion, message on completion, units per object. See [Version metadata](/next/developers/object-model/version-metadata) | ## What a bundle builder is Every Speckle producer has a component that plays the role the SDKs call a **bundle builder**. In specklepy and Speckle.Sdk it is `BundleBuilder`. The Archicad connector implements the same role in C++ without an SDK. It is the producer-side model of a version, and it has four jobs. * **Intern identities into dense integer keys.** Objects are keyed by `applicationId`. Geometry is keyed by a value you derive from the owning object, such as `wall-1:g0`. Structural nodes such as definitions, instances, materials, colors, levels, and grouping containers are keyed by whatever stable key your host gives them. Each of the three key spaces counts from zero on its own. A relation's type is what says which space each end refers to. * **Record typed relations.** Every link is one row of `(relation, source, target, ord)`. Membership, hosting, connectivity, appearance, and instancing are all relations, never nested fields. * **Stream rows to parquet as you add them.** Geometry is encoded on the spot and flushed in row groups, so memory does not grow with the model. * **Stamp provenance.** The builder writes the `meta` row and the self-describing catalogs from the [bundle spec](https://github.com/specklesystems/speckle-bundle-spec)'s generated constants, never from literals you typed in. The builder's behaviour is the contract, whichever language you write it in: * **Get-or-add is interning.** Asking for a key that already exists returns the same handle and writes nothing. Asking for it again with different attributes is an error. One key means one node. * **Add is append.** Geometry, model properties, results, and camera views append a row on every call. * **Edges cannot be retracted.** A single-valued relation is write-once. Decide before you write. * **Units and producer are required up front.** The default unit is stamped on every object, and the producer slug and version go into `meta` and onto the ingestion. * **A default scene view is injected** when you declare none, grouping by `IN_COLLECTION`. * **Build once, then rename.** The builder writes files under a temporary stem and renames them to the reserved version id once the ingestion hands it out. ## What a bundle contains A bundle is a flat set of files sharing one stem, the version id, with no manifest file. Consumers know the filenames from the spec and discover the stem from the `meta` file. | File | Family | Required | Holds | | - | - | - | - | | `{id}.eav.objects.parquet` | eav | Yes | Object identity: `applicationId` to object key | | `{id}.eav.paths.parquet` | eav | Yes | Interned property paths | | `{id}.eav.eav.parquet` | eav | Yes | One row per object, path, and value | | `{id}.eav.types.parquet` and two siblings | eav | Ship them | Type-level properties and the object-to-type link. Write them even when empty | | `{id}.eav.model.parquet` | eav | No | Model-scoped properties such as the reference point. Omit the file when you have no rows | | `{id}.eav.structural_results.parquet` | eav | No | Analysis results. Omit when empty | | `{id}.eav.property_set_definitions.parquet` | eav | No | Authored property set schemas. Omit when empty | | `{id}.geometries.parquet` and shards | geometry | Yes | SGEO blobs keyed by geometry key. Overflow shards are `{id}.geometries.{n}.parquet` | | `{id}.envelope.nodes.parquet` | envelope | Yes | Definitions, instances, materials, colors, levels, containers, with fixed columns per kind | | `{id}.envelope.relations.parquet` | envelope | Yes | `(rel, src, dst, ord)` rows | | `{id}.envelope.rel_types.parquet` | envelope | Yes | Catalog of relation types and their namespaces, copied from the spec | | `{id}.envelope.node_kinds.parquet` | envelope | Yes | Catalog of node kinds, copied from the spec | | `{id}.envelope.meta.parquet` | envelope | Yes | One row: `schema_version`, `produced_by`, `producer_version`, `sdk_name`, `sdk_version` | | `{id}.envelope.scene_views.parquet` | envelope | No | Grouping projections the viewer offers | | `{id}.envelope.camera_views.parquet` | envelope | No | Saved cameras | Two files you do not write: * **The viewer `.dat`.** The server builds `{id}.viewer.dat` from your bundle after completion. That build is part of why the version is not visible the moment the upload completes. * **A manifest or index.** The `meta` file is the anchor. Everything else is found by name. Optional files are feature-detected by presence. An empty optional table is a bug, not a placeholder. The three type tables are the exception: the viewer needs all three present to build its property view, so write them even when they hold no rows. ## Relations you do not need, and relations you add Two questions come up as soon as a team maps its own domain onto the relational layer. Both have a short answer. **You do not have to emit every relation type.** The catalog describes what Speckle can carry, not what every model must contain. A producer for a host with no levels, no instances, or no MEP systems emits none of those relations, and a consumer treats the absence as "not in this model", never as an error. Emit what your domain has and nothing else. **You can add your own links, with the same guarantee interoperability has always had: none.** The relation catalog is Speckle's. Its numbers are reserved or retired on purpose, the validator rejects a relations file that uses a number outside the catalog, and every Speckle consumer ignores edges it does not know. Custom links therefore go in your own parquet file, uploaded with the bundle under the same version id, keyed by `applicationId` so they survive across versions. Speckle stores and lists that file and never reads it. The viewer, Speckle Intelligence, and the SDK receive path will not see those links, and a receiving application supports them only if you wrote that support. Say so in your own documentation. Before you add a file, check which of these three shapes your case is. Most turn out to be the first two. * **A relation Speckle already has.** A structural "supports" link, a duct run, a pipe network: `CONNECTS_TO` with a scope, `IN_SYSTEM`, or `SUBELEMENT` usually carries it, and then every consumer understands it. Read the [relation catalog](/next/developers/object-model/relations) first. * **A grouping, not a link.** A classification hierarchy, a cost breakdown, a zone scheme: put the code on each object as a property and declare a scene view over that property path. The viewer then offers your hierarchy as a tree without any new relation. * **A link to something outside the model.** An issue, a clash, a record in an asset register: when the other end is not an object in the bundle, an id on the object as a property is the portable form. Use a custom edge file only when both ends are objects in the same bundle. If a link is general to a discipline rather than to your tool, propose it as an issue on [speckle-bundle-spec](https://github.com/specklesystems/speckle-bundle-spec) with the two node kinds it joins and an example model. Reserved catalog numbers exist so that new relations can be added for everyone, and a relation in the catalog is the only kind every consumer will understand. ## Open-source producers to learn from Every Speckle connector is open source. Read them as worked examples of the publish and load rules, in the language closest to yours. The SDKs are the reference builders; the non-SDK producers show the same contract implemented from scratch. | Repository | Language | Hosts | How it publishes in 2026.9 | Read it for | | - | - | - | - | - | | [speckle-sharp-sdk](https://github.com/specklesystems/speckle-sharp-sdk) | C# | Any | The reference bundle builder and artifact pipeline under `Speckle.Sdk.Bundles` | The builder contract, sharding, progress and cancellation plumbing | | [specklepy](https://github.com/specklesystems/specklepy) | Python | Any | The reference bundle builder under `specklepy.bundle`, with the `bundle` extra | A compact builder, the SGEO encoder, the upload client | | [speckle-archicad](https://github.com/specklesystems/speckle-archicad) | C++ | Archicad | Its own parquet writer and ingestion client. No Speckle SDK | The complete non-SDK producer: column binding, EAV rules, SGEO, upload | | [speckle-sketchup](https://github.com/specklesystems/speckle-sketchup) | Ruby | SketchUp | Its own envelope writer and ingestion client. No Speckle SDK | A non-SDK producer in a dynamic language | | [speckle-blender](https://github.com/specklesystems/speckle-blender) | Python | Blender | specklepy's bundle builder | Instancing, per-object geometry keys, world-space display geometry | | [speckle-sharp-connectors](https://github.com/specklesystems/speckle-sharp-connectors) | C# | Revit, Rhino, Grasshopper, AutoCAD, Civil 3D, Plant 3D, ETABS, SAP2000, Tekla Structures, Tekla Structural Designer | Speckle.Sdk's bundle builder and the same v2 upload rail | Reference points, by-layer materials, type-level properties, linked models | | [speckle-powerbi](https://github.com/specklesystems/speckle-powerbi) | TypeScript | Power BI | Load only | Reading versions and properties without producing | The user interface is separate from publishing. The shared connector UI, [speckle-connectors-dui](https://github.com/specklesystems/speckle-connectors-dui) (TypeScript), is what the .NET desktop connectors, Archicad, and SketchUp embed. Using it is optional. It is worth reading for two things: the bindings show the read and write interactions a host has to expose, including how the UI follows an ingestion until the version exists, and reusing it keeps the experience familiar to people who already use other Speckle connectors. Blender ships its own native panels instead. Grasshopper has no UI at all and splits publish and load into components. Navisworks has no 2026.9 desktop connector. Large NWC and NWD files go through [direct uploads](/connectors/direct-uploads/introduction), where a server-side converter produces the bundle. Older archived repositories such as the QGIS, Unity, and Excel connectors publish the object graph of 2026.8 and earlier and are not a pattern for 2026.9. ## FAQ Yes. It lives at [speckle-bundle-spec](https://github.com/specklesystems/speckle-bundle-spec): the SQL source that defines every table, relation, and node kind, with the reasoning recorded beside each entry, plus the code generators, a validator, and conformance fixtures. Generated constants for C++, C#, Python, and TypeScript are under `generated/`. Pin to a commit, build against the constants for your language, and run the validator on every bundle in CI. To propose a relation, open an issue there with the two node kinds it joins and an example model. Emit nothing for them. An absent relation means "not in this model". Consumers must never treat a missing relation type as an error. On every object as a root scalar, on every instance node, in every SGEO header, and per property row where a value has a unit. There is no bundle-wide unit. # Load a bundle in your own code Source: https://docs.speckle.systems/next/developers/building-integrations/load How a consumer lists a version's artifacts, downloads the bundle, and rebuilds objects, geometry, instances, grouping, and appearance without a Speckle SDK. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. If you load versions without a Speckle SDK, there is no root object to download and no graph to walk. You list the version's artifacts, fetch the parquet files you need from presigned URLs, and rebuild the model from three key spaces joined by relations. A loader that downloads `referencedObject` from the objects endpoints gets a 404 on every 2026.9 version. This page assumes the model from [Building integrations in 2026.9](/next/developers/building-integrations). ## Tell the two formats apart Any version you are asked to load may still be an object graph from 2026.8 or earlier. Read the version record first. | Field | 2026.8 and earlier | 2026.9 bundle | | - | - | - | | `Version.schemaVersion` | `null` | `3` | | `Version.referencedObject` | A content hash | `bundle...` | | Where the data is | The objects endpoints, as JSON | The artifacts endpoint, as parquet files | Dispatch on the `bundle.` prefix. Keep your existing reader for the first shape, or refuse it with a clear message the way the Archicad connector does. Never derive storage paths from the triple in the reference; resolve the version through the project and version ids you already hold. ## How a load fetches a version Take the version id from the model URL, or list the model's versions and take the latest. The outcome is a project, model, and version id, and a version record whose `schemaVersion` is `3`. Get the version's artifacts endpoint with your Speckle token. The outcome is one entry per file with a presigned URL and an expiry, and the version's viewer `.dat` in the list. Get each URL without your Speckle token. Skip the geometry shards when you only read properties, and skip the `.dat`. The outcome is a bundle directory on local disk. Open `meta`, `rel_types`, and `node_kinds`. The outcome is the vocabulary this bundle was written with, including relation namespaces and any ids your reader does not know. Intern objects, nodes, and geometry by their dense keys, then apply relations in the order the rules below give. The outcome is objects with properties, geometry, placement, grouping, and appearance. Call the mark-received mutation with your application slug. The outcome is a receive recorded against the version, the way every Speckle connector does. The SDK tabs run the whole sequence in one call. The GraphQL and REST tabs are the calls a non-SDK consumer makes, numbered to match the steps. ```graphql theme={null} # 1. Read the version record and dispatch on its shape. query VersionShape($projectId: String!, $modelId: String!, $versionId: String!) { project(id: $projectId) { model(id: $modelId) { version(id: $versionId) { id schemaVersion referencedObject sourceApplication message } } } } # 6. Record the receive. mutation MarkReceived($input: MarkReceivedVersionInput!) { versionMutations { markReceived(input: $input) } } ``` ```json Variables for MarkReceived theme={null} { "input": { "projectId": "", "versionId": "", "sourceApplication": "my-consumer" } } ``` ```http theme={null} # 2. List. Use the model-level path without a version id for the latest version. GET /api/v2/projects/{projectId}/models/{modelId}/versions/{versionId}/artifacts Authorization: Bearer 200 { "files": [ { "name": ".envelope.meta.parquet", "url": "https://...", "expiresAt": "..." }, { "name": ".geometries.parquet", "url": "https://...", "expiresAt": "..." }, { "name": ".viewer.dat", "url": "https://...", "expiresAt": "..." } ] } 404 when the version has no bundle, or the token cannot read the project. # 3. Download. No Authorization header on presigned URLs. GET ``` ```python theme={null} from specklepy.api import operations with operations.receive3(account, project_id, model_id, version_id) as model: print(model.units, len(model.objects), model.unknown_relations) for obj in model.objects_with("category"): print(obj.application_id, obj.name) ``` ```csharp theme={null} using var model = await SpeckleBootstrap.Operations.Receive3( account, projectId, modelId, versionId, cancellationToken: ct ); Console.WriteLine($"{model.Units} {model.Objects.Count} {model.UnknownRelations.Count}"); ``` Presigned URLs expire after an hour and are not content-addressed. Never persist one. Cache the downloaded files by version id and revalidate with the ETag when you refetch. The `.dat` in the listing is the viewer's artifact, and a `geometryStream` field beside the file list is the viewer's streaming endpoint. Both are internal. Read the parquet files. ## Rules that decide whether your load is correct The bundle tells you its own vocabulary. Read it, and apply these rules in order. ### Reading the files * Read columns by name and tolerate columns you do not know. The spec adds columns without moving the version, so a bundle written before a column existed must still load. * Read every geometry shard, `{id}.geometries.parquet` and `{id}.geometries.{n}.parquet`. A reader that opens only shard zero silently drops geometry above the shard cap. * Treat a relation id or node kind missing from your vocabulary as skip-and-report, never as an error. A newer producer than your reader is normal. * Do not gate on `meta.schema_version`. It is provenance, not a compatibility switch. ### Identity * A bare integer is meaningless without its namespace. The relation type's source and target namespaces in `rel_types` say whether an end is an object, a node, or a geometry. * The object's identity is `applicationId`. If you project the bundle into a tree with ids on nodes, mint synthetic ids per bundle and expect them to differ across versions. ### Properties * Each row sets exactly one of the string, number, and boolean columns. Coalesce them. * Rebuild nesting from the dotted path. `properties.Constraints.Base Offset` is a nested dictionary, not a flat key. * Merge type-level rows into each object through the object-to-type link. Without that merge, most type parameters are missing. * The root scalars `speckle_type`, `name`, `units`, and `type` sit beside `properties.*`, not under it. ### Geometry * Verify the CRC and decode by primitive type. See [Geometry encoding in 2026.9](/next/developers/object-model/geometry-encoding). * `DISPLAY` is what to render. Prefer a `SOLID` only when your host can read its format, and fall back to the display mesh otherwise. Never draw `CENTERLINE` as a body. * Convert with the blob's own unit, not a model-wide unit. Objects, instances, and geometry can disagree. ### Instancing * Expand a definition once through `DEFINES`, then place it for every `DISPLAY_INSTANCE` edge using the instance node's transform, 16 row-major doubles in the instance's units. Scale only the translation when you convert units. `DEFINES_INSTANCE` nests one definition in another. * An object with no render edge is a carrier for a definition member's properties and grouping. Skip it when you bake geometry, or the member draws twice, once untransformed at the origin. `DEFINES_MEMBER` and `PLACES` join carriers to their definition and placement. ### Grouping * Build the tree from the default scene view. Each tier is either a relation such as `IN_MODEL` or `IN_COLLECTION`, or a property path such as `category`. With no scene view, group by `IN_COLLECTION`. * Nest containers through their parent reference column, not through a relation. * `IN_COLLECTION` is single-valued. `IN_GROUP` and `IN_SYSTEM` are not. ### Appearance * Material fills from specific to general: `HAS_MATERIAL` on the geometry, then `OBJECT_HAS_MATERIAL` on the object, then `NODE_HAS_MATERIAL` on the object's container. * Color is presentational: `OBJECT_HAS_COLOR` overrides `HAS_COLOR` on the geometry, and `NODE_HAS_COLOR` is the container default. * `HAS_COLOR` starts from a geometry or an object, and `ord` says which. Read it before you resolve the source key. * Appearance edges are single-valued per source. When a bundle repeats one, the last row wins. ### Placement * Read `modelPlacement.*` and `referencePoint.*` from the model-scoped properties. When `appliedToGeometry` is true, stored coordinates are already in that datum. When it is false, apply the transform yourself. No rows means the internal origin. ## Suggested build order Authenticate, resolve a version, list its artifacts, and download the non-geometry files. The outcome is a bundle directory and a passing read of the three catalogs. Objects by `applicationId`, nested properties from paths, type-level rows merged in. The outcome is a property table you can filter, before any geometry. Download the shards, verify CRCs, decode meshes, attach them through `DISPLAY` with the right units. The outcome is a model that renders untransformed geometry correctly. Definitions, placements, nested definitions, and carrier suppression. The outcome is repeated objects in the right places, each drawn once. The default scene view, container nesting, and the material and color precedence. The outcome is a tree and a look that match the Speckle viewer. The reference point contract, then the mark-received call. The outcome is geometry in the right datum and a receive recorded on the version. ## FAQ Either the version is an object graph from 2026.8 or earlier, the bundle has not been produced yet, or your token cannot read the project. Check `schemaVersion` on the version record first, then the ingestion status if the version is new. Yes. Geometry is the bulk of a bundle and lives in its own shards. Download the `eav` and `envelope` files only. The SDKs expose the same choice as an include-geometry option. Only as a new version, and every publish is one. Files are stored under the reserved version id, so the server never sees "the same bundle". Your choice is how to make the new file set. Copying the received files, rewriting the property rows you changed, stamping `meta` with your own producer, renaming to the new id, and uploading is valid when only values change: keys, relations, and geometry stay consistent. Build a new bundle when structure changes. Either way the version's source application is you. Speckle's own parameter editing applies changes in the host and republishes from there, and a receive-then-`send` round trip through a `Base` tree is unsupported. No, but every Speckle connector does. It is how the web app and analytics know a version was loaded, and it costs one mutation. Skip its edges and report which ids you skipped. The SDKs surface the same set as unknown relations. Do not fail the load and do not guess a meaning from the number. # Publish a bundle from your own code Source: https://docs.speckle.systems/next/developers/building-integrations/publish The ingestion sequence a producer drives to create a 2026.9 version, the rules that make a bundle correct, and a build order. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. A publish in 2026.9 is an ingestion you open, a bundle you write and upload, and a version the server creates when ingestion finishes. Nothing here calls a create-version mutation, and nothing is visible until the ingestion reaches `success`. This page assumes you know what a bundle and a bundle builder are from [Building integrations in 2026.9](/next/developers/building-integrations). ## How a publish creates a version The version id is allocated before any bytes move, and the version is born on the server. Every Speckle producer follows this sequence. Call the ingestion create mutation with the model, the source application slug and version, a progress message, and an idle timeout. The outcome is an ingestion id and a reserved version id. If the response has no version id, the server predates 2026.9. Stop; this path has no fallback. Run your conversion and write the files with the reserved id as their stem. The outcome is a complete bundle on local disk that you can validate before anything is uploaded. Post the list of bare filenames to the sign endpoint. The outcome is one presigned URL per file. Put each file to its URL, adding only the headers the sign response asked for, and keep the returned ETag exactly as received. The outcome is every file in storage and an ETag per filename. Post the ETags, the bundle reference as the root id, the object count, and the version message. The outcome is the server accepting the bundle and starting ingestion. The response echoes the version id. Subscribe to ingestion updates or poll until the status is terminal. The outcome on `success` is a version that answers queries, has a viewer `.dat`, and arrives as `CREATED` on the `projectVersionsUpdated` subscription. The SDK tabs run the whole sequence in one call. The GraphQL and REST tabs are the calls a non-SDK producer makes, numbered to match the steps. ```graphql theme={null} # 1. Open the ingestion. The response carries the reserved version id. mutation IngestionCreate($input: ModelIngestionCreateInput!) { projectMutations { modelIngestionMutations { create(input: $input) { id versionId cancellationRequested } } } } # While you convert: keep the idle clock alive and read the cancel flag. mutation IngestionUpdateProgress($input: ModelIngestionUpdateInput!) { projectMutations { modelIngestionMutations { updateProgress(input: $input) { id cancellationRequested } } } } # On any failure: close the ingestion. failWithInvalid takes ModelIngestionInvalidInput # (validationMessage) and failWithCancel takes ModelIngestionCancelledInput (cancellationMessage). mutation IngestionFailWithError($input: ModelIngestionFailedInput!) { projectMutations { modelIngestionMutations { failWithError(input: $input) { id } } } } # 6. After complete: wait for a terminal status. subscription ProjectModelIngestionUpdated($input: ProjectModelIngestionSubscriptionInput!) { projectModelIngestionUpdated(input: $input) { modelIngestion { id statusData { __typename ... on ModelIngestionSuccessStatus { versionId } ... on ModelIngestionProcessingStatus { progressMessage progress } } } } } ``` ```json Variables for IngestionCreate theme={null} { "input": { "projectId": "", "modelId": "", "progressMessage": "Sending from my-producer 1.0", "sourceData": { "sourceApplicationSlug": "my-producer", "sourceApplicationVersion": "1.0" }, "maxIdleTimeoutSeconds": 600 } } ``` ```http theme={null} # 3. Sign. Bare filenames only, no paths. POST /api/v2/projects/{projectId}/modelingestion/{ingestionId}/uploads/sign Authorization: Bearer apollographql-client-version: 1.0 Content-Type: application/json { "files": [".envelope.meta.parquet", ".eav.objects.parquet", "..."] } 200 { "uploads": { "": { "url": "https://...", "key": "...", "additionalRequestHeaders": { } } } } # 4. Upload. One PUT per file, no Authorization header. Send additionalRequestHeaders when present. PUT 200 ETag: "" # 5. Complete. ETags verbatim, quotes included. POST /api/v2/projects/{projectId}/modelingestion/{ingestionId}/uploads/complete Authorization: Bearer apollographql-client-version: 1.0 Content-Type: application/json { "etags": { "": "\"\"" }, "rootId": "bundle...", "totalChildrenCount": , "message": "Nightly export" } 200 { "versionId": "", "files": ["", "..."] } ``` ```python theme={null} from specklepy.api import operations from specklepy.bundle import BundleBuilder, Producer, SendOptions builder = BundleBuilder(Producer(slug="my-producer", version="1.0"), units="m") # add objects, containers, levels, and relations on the builder result = operations.send3( account, project_id, model_id, builder, SendOptions(message="Nightly export") ) print(result.version_id, result.bundle_reference) ``` ```csharp theme={null} var producer = new SpeckleApplication { HostApplication = "My producer", HostApplicationVersion = "1.0", Slug = "my-producer", SpeckleVersion = "2026.9", }; using var builder = new BundleBuilder(producer, units: "m"); // add objects, containers, levels, and relations on the builder var sent = await SpeckleBootstrap.Operations.Send3( account, projectId, modelId, builder, new SendOptions(Message: "Nightly export"), ct ); var version = await SpeckleBootstrap.Operations.WaitForVersion(account, sent, cancellationToken: ct); ``` Forward the ETag byte for byte. Object storage wraps it in double quotes and the complete endpoint compares against that exact value. Stripping the quotes fails the publish with an ETag mismatch that looks like a server fault. Close the ingestion on every exit. Report `failWithError`, `failWithInvalid`, or `failWithCancel` through the ingestion mutations, using a request that cannot itself be cancelled. An ingestion you leave open sits until the idle timeout fires. Send the `apollographql-client-version` header on the sign and complete calls. The server records it on the version for analytics. The publishing application itself comes from the source application slug and version you gave when opening the ingestion, not from a header. A single presigned put is limited to 5 GB on S3-compatible storage. Larger files use the multipart endpoints under the same ingestion path (`uploads/multipart/start`, `complete`, and `abort`) instead of one put per file. Progress and cancellation run through the same ingestion. Report progress on a throttle, with at most one update in flight, and never let a failed report fail the publish. The idle timeout is an idle clock, reset by each report, so a long conversion must keep reporting. Cancellation is cooperative in both directions: check your own cancel signal per object and per file, and watch `cancellationRequested` on every ingestion response. ## Rules that decide whether your bundle is correct The server checks only that every file arrived with a matching ETag. Correctness is checked by the bundle spec's validator before upload and by consumers after. These are the rules producers most often get wrong. ### Identity * `applicationId` must be stable across publishes and unique per placement. A linked file placed twice needs a per-placement suffix, or its objects and their topology collide. * Key geometry on the placed object, never on a shared source block. Two objects sharing one mesh describe different world-space geometry. * Derive geometry and definition keys from content, quantized, not from random ids. Random keys make material bindings fragile and defeat definition deduplication. * An object with no properties, no geometry, and no relations is noise. Do not intern it. ### Properties * One value per row: exactly one of the string, number, or boolean columns is set. Numbers must be finite. * Paths are dotted. Nesting is rebuilt from the path, never stored as a blob. * Stamp the root scalars on every object: `speckle_type`, `name`, `units`, and the host's own `type`. * Parameters shared by a type go to the type tables once, linked from each object, not repeated per object. * Decide a policy for multi-valued properties. The reference walk drops arrays; joining them is a valid alternative when your host emits them. ### Geometry * Write the SGEO header exactly: magic, version, primitive type, flags, the spec's unit code, and a CRC32 over the body, all little-endian. Consumers verify the checksum. See [Geometry encoding in 2026.9](/next/developers/object-model/geometry-encoding). * `DISPLAY`, `SOLID`, and `CENTERLINE` each keep their own ordinal counter per object. * Ship the solid beside the display mesh, not instead of it. Foreign hosts read the mesh. * `CENTERLINE` is never a render edge. A consumer that drew every geometry an object owns would draw the axis through the duct. * Shard the geometry table at 1536 MiB of uncompressed content. Shard zero keeps the canonical name. Readers glob all shards. ### Instancing * A definition owns its geometry once. Each placement is an instance node with a transform of 16 row-major doubles and its own units. * When you convert transform units, scale only the translation column. Scaling all sixteen values resizes the instance. * Definition members get no render edge. They keep an object row for properties and membership, and join back through `DEFINES_MEMBER` and `PLACES`. A member with a render edge draws twice. * Create definition nodes before you walk placements, so a placement never references a nameless definition. ### Grouping * Membership is an edge (`IN_COLLECTION`, `IN_MODEL`, `IN_GROUP`, `IN_SYSTEM`). Nesting of containers is a parent reference on the container node. Do not conflate them. * Containers are one node kind with a subtype (Layer, Collection, Folder, Model, Group, MEP System, Network). Key them by full path so two branches with the same leaf name stay distinct. * The tree a viewer shows is a scene view: a recipe of tiers, some relations and some property paths. Declare one, or accept the default over `IN_COLLECTION`. * Emit no container that would end up empty in the view. ### Appearance * Bind materials to geometry with `HAS_MATERIAL`. The object plane only fills where geometry has none, and is the only option for a placement. * `HAS_COLOR` can start from geometry or from an object, and `ord` says which. Without it, the color lands on an unrelated element. * Resolve inherited, by-layer appearance yourself. Land the layer's material on the layer node and on each inheriting object's own geometry. ### Topology * Emit an edge only when both ends are objects you sent. Resolve cross-object links in a second pass against your key map. * `ord` is an ordinal on ordered relations and a scope tag on `CONNECTS_TO`. Read the catalog. * `HOSTED_ON` runs hosted to host. Ownership (`SUBELEMENT`) wins over hosting when both apply. * Never reuse a retired relation id, and never invent one. ### Provenance and column binding * Address parquet columns through the generated constants for your language. A spec column insertion must be a compile or import error, not a silent row shift. If your parquet library has no schema object, add an arity assertion yourself. * Stamp `schema_version` as the spec's semver string from the generated constant, pin the spec by commit, and write real `produced_by` and `producer_version` values. Leave the SDK columns null when you use none. * Treat a dropped row as a failed publish. Count rows written, not rows attempted. The spec is public at [speckle-bundle-spec](https://github.com/specklesystems/speckle-bundle-spec). Build against the generated constants under `generated/` for your language and pin to a commit. The vendored copies in specklepy, the Archicad connector, and the SketchUp connector show what that looks like, and every bundle carries its own `rel_types` and `node_kinds` catalogs. Run the spec's validator on every bundle before you upload, from a checkout of the repository: ```bash theme={null} npm run validate -- ``` It checks file presence, live ids, column sets, and referential integrity. The server checks only ETags. Close the loop in CI as well: publish to a test project, wait for `success`, receive with an SDK, and check for unknown relations and decode errors. ## Suggested build order Use a personal access token or your own OAuth flow. Check the ingestion permission on the model, then open an ingestion and confirm the reserved version id is present. The outcome is a server you know accepts bundles. One object, one mesh, one container, a default scene view, and a correct `meta` row. Run the spec validator on the directory. The outcome is a bundle that passes before any upload. Sign, upload, complete, then wait for `success`. Open the version in the web app. The outcome is a version you can see, with the publishing client attributed correctly. Stable `applicationId` per placement, root scalars, type-level parameters, a policy for arrays. The outcome is a property store that filters and aggregates the way your users expect. SGEO encoding for each primitive you support, solids beside meshes, materials on geometry, by-layer resolution. The outcome is a model that renders with the right appearance. Definitions, placements, member suppression, then hosting, containment, and connectivity in a second pass. The outcome is a model Speckle Intelligence can answer questions about. Throttled progress, cooperative cancellation inside the upload, failure reporting on every exit, geometry sharding, and retries with backoff on transient errors. The outcome is a producer that survives large models and unreliable networks. ## FAQ For now, yes. Upgraded servers accept it with deprecation warnings and convert it to a bundle before the version appears, because thousands of existing integrations depend on that path. It is not the path to build new work on: the server stores the graph and then converts it, and that support will end. No removal date is set, and one will be announced before it is. A server without legacy-send support rejects it with `LEGACY_SEND_UNSUPPORTED`. Treat that as the wrong publish path, not a transient error. See [Publish through model ingestions](/developers/migration/publish-through-ingestions). # Developer docs for 2026.9 Source: https://docs.speckle.systems/next/developers/introduction Preview entry for 2026.9 developer documentation. Coverage is incremental. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. 2026.9-specific developer documentation starts here. Pages are added only when 2026.9 differs from the current developer guides or needs its own write-up. For the current product, see [Developer documentation](/developers/introduction). The object model is the first of those differences. Today's [Data Schema](/developers/data-schema/overview) is a tree-and-Proxy graph. 2026.9 stores properties in a columnar store and describes containment, connectivity, systems, and materials as typed relations. Columnar property store and relational layer versus today's tree-and-Proxy model. Named relation types that replace Proxies and nested `elements` walks. Before-and-after Speckle.Sdk examples for the 2026.9 breaking-change surface. Before-and-after specklepy examples for the 2026.9 breaking-change surface. JS/TS, GraphQL and REST, Viewer packages, Server, Automate, and custom connectors each have a holding note in this dropdown until those 2026.9 pages land. Use the developer docs under **Current** in the version selector for those topics. For dates, compatibility mode, Automate SDK bumps, and who must act, see [Data model migration for developers](/developers/migration/data-model-migration). For a compact before-and-after table, see [Compare 2026.8 and 2026.9](/next/whats-new). # Geometry encoding in 2026.9 Source: https://docs.speckle.systems/next/developers/object-model/geometry-encoding SGEO, the binary geometry a producer writes into a bundle, and the viewer .dat the server builds from it. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. If you write geometry into a bundle yourself, you encode it as **SGEO**, a small binary format with a fixed header and a per-primitive body. Get the header wrong and consumers reject the blob on its checksum. If you only consume geometry, you either decode SGEO from the bundle's geometry table or stream the **viewer `.dat`** that the server builds from it. You never write the `.dat`. Before 2026.9, as the [Geometry Schema](/developers/data-schema/geometry-schema) describes, geometry is a list of `displayValue` objects in JSON on each DataObject. In 2026.9 it is a table of blobs keyed by a geometry key, attached to objects through relations. This page covers the blob format, how the table is laid out, and what the `.dat` is for. For which relations attach geometry to what, see [Display geometry](/next/developers/object-model/relations#display-geometry). ## Where geometry lives in a bundle The geometry table is `{versionId}.geometries.parquet`. The writer starts a new shard, `{versionId}.geometries.{n}.parquet`, before a blob would push the current one past 1536 MiB of uncompressed content. Shard zero keeps the canonical name, so a small model has one file and a reader always globs all shards. Each row holds one blob, its dense integer key, and an id that is the SHA-256 of the blob bytes. Because every producer encodes SGEO identically, the same mesh from any host gets the same id, and readers deduplicate on it. A row also carries a `type` label: the SGEO primitive name (`mesh`, `line`, `curve`, and so on) for display meshes and centerlines, or the host format, such as `3dm`, for a `SOLID` row that carries the host's own bytes. Nothing in the geometry table says which object a blob belongs to. That is a relation: `DISPLAY`, `SOLID`, or `CENTERLINE` from the object, or `DEFINES` from a definition node whose placements reuse the blob. `DISPLAY`, `SOLID`, and `CENTERLINE` each keep their own ordinal per object, so an object's first display mesh is ordinal zero whether or not a solid was written before it. `DEFINES` uses the definition's member ordinal instead, shared with `DEFINES_MEMBER` and `DEFINES_INSTANCE`. ## The SGEO header Every blob starts with 16 bytes, little-endian. | Offset | Size | Field | Value | | - | - | - | - | | 0x00 | 4 | magic | `SGEO` | | 0x04 | 1 | version | `1` | | 0x05 | 1 | primitive type | Code from the table below | | 0x06 | 2 | flags | Bitfield from the table below | | 0x08 | 2 | units code | `mm` 1, `cm` 2, `m` 3, `km` 4, `in` 5, `ft` 6, `yd` 7, `mi` 8, other 0 | | 0x0A | 2 | reserved | `0` | | 0x0C | 4 | crc | CRC-32 (IEEE, polynomial `0xEDB88320`) of the body bytes only | | 0x10 | | body | Per primitive type | Conventions that every encoder follows: * The body starts 8-byte aligned at `0x10`, and every array of doubles stays 8-aligned. Pairs of 32-bit scalars are padded to keep it so. * Doubles are IEEE-754 binary64. Face indices and colors are signed 32-bit integers. * Derived values such as length, area, volume, bounding box, and arc radius are not stored. Readers recompute them. * One unit per blob. Sub-objects inside a composite lose their own units. | Code | Primitive | Code | Primitive | | - | - | - | - | | 0 | Mesh | 7 | Points | | 1 | Line | 8 | Ellipse | | 2 | Polyline | 9 | Spiral | | 3 | Polycurve | 10 | Box | | 4 | Curve | 11 | Region | | 5 | Arc | 12 | Text | | 6 | Circle | | | | Bit | Flag | Applies to | | - | - | - | | 0 | Quantized | Reserved, must be 0 in v1 | | 1 | Closed | Polyline, curve, polycurve | | 2 | Rational | Curve has non-uniform weights | | 3 | Periodic | Curve | | 4 | HasNormals | Mesh | | 5 | HasUvs | Mesh | | 6 | HasColors | Mesh, points | | 7 | HasSizes | Points | | 8 | HasTrimDomain | Ellipse | | 9 | ScreenOriented | Text | | 10 | HasMaxWidth | Text | ## Bodies The mesh body is the one every producer needs. | Order | Field | Type | Notes | | - | - | - | - | | 1 | vertex count | u32 | Number of vertices, so a third of the coordinate count | | 2 | face count | u32 | Length of the face list | | 3 | vertices | f64 × 3n | x, y, z per vertex | | 4 | faces | i32 × face count | The same flattened face list as `Mesh.faces` in 2026.8 and earlier | | 5 | normals | f64 × 3n | Only with `HasNormals`, padded to 8 bytes first | | 6 | uvs | f64 × 2n | Only with `HasUvs`, padded to 8 bytes first | | 7 | colors | i32 × n | Only with `HasColors` | Curves follow one rule: the viewer has no NURBS evaluator, so a curve body leads with the display polyline it renders and trails with the analytical definition (degree, points, weights, knots). A polycurve or region nests each segment as its own SGEO blob behind an 8-byte prefix (a `u32` length and a reserved `u32`), padded to 8 bytes. Arcs, circles, and ellipses are stored analytically. Points and point clouds store coordinates plus optional colors and sizes. Treat the SDK encoders as the byte-exact reference for every body: `SgeoEncoder` in Speckle.Sdk (namespace `Speckle.Objects.Utils`) and `sgeo.py` in specklepy. Both ship decoders and round-trip tests you can port. The CRC covers the body only, and the geometry id covers the whole blob including the CRC. A producer that computes either over the wrong span produces blobs that decode nowhere and never deduplicate against anyone else's. ## The viewer `.dat` After the upload completes, the server builds `{versionId}.viewer.dat` from the bundle and appends it to the version's artifact list. The version is not visible until that build finishes. The WebGPU viewer downloads only the `.dat`, never the parquet files. The `.dat` is one self-contained binary: a geometry region of chunk-encoded meshes and lines, an index region of fixed-order sections (meta, primitives, chunks, placements, materials, colors, realizations), and a 128-byte trailer that maps the file. Its current format expands reusable definitions into placements and gives each occurrence a realization id, which is what lets the viewer select one instance of a repeated object. That identity exists only in the `.dat`. The bundle keeps the compact authored graph. The `.dat` is an internal artifact of the viewer and the server. Its layout can change without a bundle spec change. Do not parse it, and do not write one. ## Read geometry from a script Receive the version as a `Model` through `receive3` / `Receive3`. The SDK decodes SGEO into the mesh and curve types you already use and exposes them per object. If you read the parquet files directly through the artifacts endpoint (`GET /api/v2/projects/{projectId}/models/{modelId}/versions/{versionId}/artifacts`, one presigned URL per file), decode the blobs with the SDK decoder or a port of it, and read every geometry shard. ## FAQ Read the parquet geometry table, not the `.dat`. Download every geometry shard from the artifacts listing and open the files with any parquet library. Each row's blob starts with the 16-byte header on this page: check the magic, read the primitive type and unit code, and verify the CRC-32 over the body. Then parse the body for that primitive, starting with the mesh layout above. Port the decoder from `sgeo.py` in specklepy or `SgeoDecoder` in Speckle.Sdk rather than writing one from the tables alone; both are short and tested. The `.dat` is the viewer's own build of the same geometry and is not readable by anything else. No. The `.dat` is built by the server and read only by the Speckle viewer. Its layout is not published, it can change without a bundle spec change, and it carries viewer-specific realization ids that mean nothing elsewhere. There is nothing to license because there is nothing to build against. The portable geometry is the bundle itself: SGEO blobs in the parquet geometry table, with open-source decoders in specklepy and Speckle.Sdk. To show a model, embed the Speckle viewer rather than reading its artifact. No. The solid is the host's own format and only a matching host can read it. Every consumer, including the viewer, renders the SGEO display mesh. Ship both. Skip that primitive, keep the owning object, and report the skip. If nothing renderable remains and there is no solid, mark the object as failed in your results so the report matches the bundle. # Object model in 2026.9 Source: https://docs.speckle.systems/next/developers/object-model/overview Columnar property store and relational layer versus today's tree-and-Proxy model. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. If you write scripts, notebooks, or small automations against Speckle object data, 2026.9 changes the shape of that data. Before 2026.9, the [Data Schema](/developers/data-schema/overview) is a directed tree of Collections and DataObjects, with [Proxies](/developers/data-schema/proxy-schema) at the Root Collection for shared resources. 2026.9 replaces that tree-and-Proxy graph with two things working together: a **columnar property store** for querying and aggregation, and an **explicit relational layer** for how elements relate. This page is the conceptual model for that change. Dates, compatibility mode, Automate SDK bumps, and who must act are on [Data model migration for developers](/developers/migration/data-model-migration). For a compact before-and-after table, see [Compare 2026.8 and 2026.9](/next/whats-new). There is no Proxy type anywhere in 2026.9 bundle data - not renamed, not kept around as a compatibility shim. No `RenderMaterial`, `Level`, `Group`, `Definition`, `InstanceProxy`, or `InstanceDefinitionProxy` object exists in the format. Everything a Proxy used to carry is now either a row in the columnar property store or an edge in the relational layer. Detached references go with them. Before 2026.9, assigning one object to a detached property on several parents stored it once and left a `{"speckle_type": "reference", "referencedId": ...}` pointer in each, resolved through the parent's `__closure`. A bundle has neither: there is no closure, and no reference object type. An object that several others need is an edge in the relational layer, and a value that several objects share is one row each in the property store. Standard connectors, SDKs, and APIs keep working with published data. This page matters if your script assumes the nested object graph or unpacks Proxies itself, rather than going through supported accessors. See [Data model migration for developers](/developers/migration/data-model-migration). ## What's different | Concern | Before 2026.9 | In 2026.9 | | - | - | - | | Object graph | Directed tree: Root Collection → Collections → DataObjects | Flat objects plus typed relations. Hierarchy is not nested `elements` | | Properties | Nested fields on `Base` / DataObject | Columnar property store: one value per object and property path, built for filter and aggregate | | Shared resources | Proxies at the root (`objects[]` of `applicationId`s) for materials, levels, groups, instances | Relational layer: typed edges such as `ON_LEVEL`, `HAS_MATERIAL`, `IN_SYSTEM` | | Version root | `version.referencedObject` is the Root Collection (the commit object) carrying `units`, Proxies, and Info | No root object. Identity stays on the version record; `units` is per object; model-wide facts are model-scoped properties. See [Version metadata](/next/developers/object-model/version-metadata) | | Topology | Reconstruct from Proxies and nested `elements` | Containment, connectivity, systems, and materials are first-class relations. Speckle Intelligence queries this layer | | Publishing | Build one root object whose `elements` holds everything, send it, then create a version pointing at its id | Build a bundle with no top, upload it through a model ingestion. The server creates the version when the upload completes | | Script that walks a tree | Receive, traverse `Collection.elements`, resolve Proxy `objects` | Identify objects, read properties from the columnar store, follow named relations. Do not unpack Proxies to rebuild those links | Project → Model → Version remains the address of a published snapshot. That addressing system is unchanged. What lives at a version is what changed. What a version points at also changed. There is no root object to start from; see [Where version metadata lives in 2026.9](/next/developers/object-model/version-metadata) for what carries the version's units, source application, and model-wide facts instead. ## Columnar property store Before 2026.9, a wall's parameters live on the DataObject (and on nested geometry in `displayValue`). To total area or filter by type, a script walks the tree and reads nested fields. In 2026.9, object identity stays stable (`applicationId` from the source application). Attributes are stored as rows in a columnar property store: each row is one object, one property path, and one value. That layout is what makes filter, group, and aggregate cheap on large models, instead of walking a reconstructed graph. Treat property paths as the public names of attributes (for example a category or type name), not the JSON shape of a received `Base` object. Nested dictionaries belong to the object graph of 2026.8 and earlier. This page does not document a query API or SQL surface. Use supported SDK accessors for the data you already read. If a tool assumes the old object-graph shape and breaks, follow [Migration guidance](/developers/migration/data-model-migration#migration-guidance). ## Relational layer Proxies solved overlapping membership without duplicating geometry: a wall could sit on a level, use a material, and belong to a group by appearing in each Proxy's `objects` list. The collection tree was still the only hierarchy a traversal walked. 2026.9 puts those links beside the property store as **typed relations**. Containment, connectivity, systems, and materials are richer than today's Proxies: they include host-to-child containment, MEP and spatial connectivity, and system membership, not only shared resources at the root. The named relation types, and how they compare to Proxies, are on [Relations in 2026.9](/next/developers/object-model/relations). Speckle Intelligence uses both halves. It looks up properties on objects, and it follows relations for questions such as what connects to what and what contains what. That behaviour is in the [comparison table](/next/whats-new). ## Publishing creates the version on the server Before 2026.9, a publish is a client-side act in two steps. You assemble one [root object](/developers/data-schema/version-root-object), put every object under its `elements` (with Proxies beside them at the root), send that graph to get its id, then create a version that points at the id. The root object is both the data and the anchor, and the client decides the moment the version exists. In 2026.9 there is no root to assemble and no version to create. A bundle builder holds objects, grouping containers, and relations side by side, with no top. `send3` / `Send3` opens a model ingestion, which reserves a version id, uploads the bundle under that id, and completes the ingestion. The server creates the version at that point, in one step. Three habits change with this: * **There is no `elements` to fill.** Membership is a relation such as `IN_COLLECTION` or `ON_LEVEL`, set on the object, not a list on a parent. * **Version metadata is given up front.** The source application and message go to the ingestion when it opens, not onto a root object at the end. * **The version exists only after ingestion completes.** A publish returns a reserved id. Wait for the version before you query, link, or receive it. The full sequence, and where each piece of metadata now lives, is on [Where version metadata lives in 2026.9](/next/developers/object-model/version-metadata). If you build a producer without a Speckle SDK, the file set, wire sequence, and bundle rules are on [Building integrations in 2026.9](/next/developers/building-integrations). ## What a script should assume Resolve project, model, and version the same way you do today. The snapshot you point at is still a version. The outcome is a published model you can read. Key objects by source identity (`applicationId`). Read attributes from the columnar property store by property path. The outcome is values you can filter or aggregate without walking nested `Base` fields. Use named relations for level, material, containment, connectivity, and systems. The outcome is membership and connectivity without unpacking a Proxy's `objects` array. See [Relations in 2026.9](/next/developers/object-model/relations). If you maintain tooling that reads Speckle data more directly than the standard SDK or API surface, and it breaks against the new format, pin to **2026.8** while you update. Compatibility mode for ACC sync and drag-and-drop uploads ends **1 November 2026**. Details: [Data model migration for developers](/developers/migration/data-model-migration). ## What is not on this page Connector-specific dumps, SDK before-and-after samples, and a SQL or local query API are separate work. Until those pages exist, use the [Data Schema](/developers/data-schema/overview) for the object graph of 2026.8 and earlier, and the [developer migration page](/developers/migration/data-model-migration) for who is affected in 2026.9. ## FAQ Yes, for versions published in today's tree-and-Proxy format. Use [Data Schema overview](/developers/data-schema/overview), [Concepts](/developers/data-schema/concepts), and [Proxy schema](/developers/data-schema/proxy-schema) for that graph. Use this page for 2026.9 bundle data. No. Existing connectors, SDKs, and integrations continue to work with published data. Watch Automate functions that process versions from a connector that only writes the new bundle format: bump the SDK dependency. See [Who's affected](/developers/migration/data-model-migration#whos-affected). That reconstruction is the object graph of 2026.8 and earlier. On 2026.9 data, containment and shared resources live on the relational layer, and properties live in the columnar store. A missing nested `elements` tree or Proxy `objects` list is expected. Update the script to identify objects, read property paths, and follow named relations — or pin to 2026.8 until you can. See [Relations in 2026.9](/next/developers/object-model/relations). That page maps today's Proxies to typed edges such as `ON_LEVEL`, `SUBELEMENT`, `CONNECTS_TO`, and `IN_SYSTEM`. No. There is no `RenderMaterial`, `Level`, `Group`, `Definition`, `InstanceProxy`, or `InstanceDefinitionProxy` object in the format - not hidden, not deprecated-but-present. If your code checks for a Proxy type or a root-level `*Proxies` array on 2026.9 data, it will find nothing, not an empty compatibility stand-in. See [Relations in 2026.9](/next/developers/object-model/relations) for what carries that information now. # Relations in 2026.9 Source: https://docs.speckle.systems/next/developers/object-model/relations Typed containment, connectivity, geometry, systems, and materials — richer than today's Proxies. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Before 2026.9, as the [Data Schema](/developers/data-schema/overview) describes, overlapping membership is a [Proxy](/developers/data-schema/proxy-schema) at the Root Collection: a material, level, group, or definition lists `applicationId`s in `objects`. Hierarchy is a tree you walk through `Collection.elements`. 2026.9 replaces that reconstruction with an **explicit relational layer**: typed, directed edges between objects (and, where needed, structural nodes such as a level, material, or grouping container). For the two-store picture, see [Object model in 2026.9](/next/developers/object-model/overview). Dates and who must act are on [Data model migration for developers](/developers/migration/data-model-migration). Proxies themselves do not exist in 2026.9 bundle data - there is no `RenderMaterial`, `Level`, `Group`, `Definition`, `InstanceProxy`, or `InstanceDefinitionProxy` object anywhere in the format. The relation types below are what carries that information instead. ## Why relations exist Proxies let one object participate in several organizations without copying geometry. They do not encode connectivity, hosting, or room occupancy as a graph a consumer can query. 2026.9 keeps the "no duplication" rule and makes those links first-class, which is what lets Speckle Intelligence answer topology questions instead of only looking up properties on each object. Rooms and MEP spaces that carry geometry are **objects** in this layer, not grouping nodes. A furniture item's room membership is a relation to that room object (`IN_ROOM`), not a Proxy list on a container. ## Relation types you will see Names below are the live vocabulary of the relational layer (the same names the 2026.9 viewer inspector uses). A connector emits only the types that exist in the source model. Omit a row from your script's assumptions unless that host actually publishes it. ### Containment and grouping These replace nested `elements` walks and most organisational Proxies. | Relation | From → to | Replaces, in 2026.8 and earlier | When you use it | | - | - | - | - | | `SUBELEMENT` | object → object | Nested DataObject `elements` (curtain wall → panels, stair → runs) | Host-to-child ownership the property store cannot encode | | `IN_COLLECTION` | object → grouping container | Collection tree / layer membership | Authored layer, category, or collection membership | | `IN_MODEL` | object → grouping container | Source-file / federation grouping | Which source model an object came from | | `IN_GROUP` | object → grouping container | Group Proxy | Authored groups (for example Rhino or AutoCAD). Distinct from layer | | `IN_ROOM` | object → room object | Not a first-class Proxy graph | Spatial occupancy (furniture, door, window → room) | | `IN_ASSEMBLY` | member object → assembly object | Host-specific nesting | Fabrication membership (for example Tekla). Distinct from `SUBELEMENT` | | `ON_LEVEL` | object → level | Level Proxy | Level membership | | `IN_SYSTEM` | object → system or network container | System / network grouping | MEP system membership. Derived networks use the same relation; the container subtype distinguishes them | Grouping containers nest among themselves (a collection tree). That nesting is structural. It is not an object-to-object `elements` walk. ### Connectivity These are new as a queryable graph. Before 2026.9 there is no Proxy equivalent. | Relation | From → to | Meaning | | - | - | - | | `CONNECTS_TO` | object → object | Directed connectivity. Scope distinguishes MEP flow, opening/room adjacency, and unscoped links | | `HOSTED_ON` | object → object | Hosted element → host (door or window → wall). Different from `SUBELEMENT` ownership | | `BOUNDS` | object → object | Bounding wall → room. Room footprint, not occupancy | `CONNECTS_TO` is directed in the store. Neighborhood queries used by the product treat it as a one-hop connection in either direction. ### Display geometry An object's own geometry is a relation too, not a `displayValue` array on the object. The blob format behind these rows is on [Geometry encoding in 2026.9](/next/developers/object-model/geometry-encoding). | Relation | From → to | Replaces, in 2026.8 and earlier | When you use it | | - | - | - | - | | `DISPLAY` | object → geometry | `displayValue` meshes on the object | The object's own render mesh (walls, in-place elements). Instanced objects use `DISPLAY_INSTANCE` instead | | `SOLID` | object → geometry | The host solid (for example a Rhino Brep) beside its `displayValue` | A true solid body where the host has one (Rhino, Civil 3D). Reach for it when you need the body, not the tessellated shell | | `CENTERLINE` | object → geometry | `baseCurve` / `baseLine` on the object | The axis a duct, pipe, conduit, or framing member follows. Routing, length take-off, clash lines, and single-line drawings | `DISPLAY` is what renders. `SOLID` and `CENTERLINE` are additional shapes for consumers that need the body or the axis. Do not draw every object-to-geometry relation, or the centerline appears through the middle of the duct. ### Materials and appearance | Relation | From → to | Replaces, in 2026.8 and earlier | | - | - | - | | `HAS_MATERIAL` | geometry → material | RenderMaterial Proxy bound to display meshes | | `HAS_COLOR` | geometry → color | Display color, kept distinct from material | | `OBJECT_HAS_MATERIAL` | object → material | Placement / instance paint when the object carries it | | `OBJECT_HAS_COLOR` | object → color | Object-plane color override | | `NODE_HAS_MATERIAL` | container → material | Authored layer or tag material (ByLayer fill) | | `NODE_HAS_COLOR` | container → color | Authored layer or tag color (ByLayer default) | Material and color are separate on purpose. An object can carry both. Material fills from specific to general: geometry `HAS_MATERIAL`, then `OBJECT_HAS_MATERIAL`, then the container's `NODE_HAS_MATERIAL`. Color is presentational: `OBJECT_HAS_COLOR` overrides geometry `HAS_COLOR`, and `NODE_HAS_COLOR` is the ByLayer default. ### Instancing The Definition and Instance Proxies of 2026.8 and earlier become structural nodes plus relations. | Relation | From → to | Replaces, in 2026.8 and earlier | | - | - | - | | `DEFINES` | definition → geometry | Definition Proxy holding shared geometry | | `DISPLAY_INSTANCE` | object → instance placement | Instance that renders with a transform | | `DEFINES_INSTANCE` | definition → nested instance | Nested instancing inside a definition | | `DEFINES_MEMBER` | definition → member object | Definition membership on the object plane (geometry and nested alike) | | `PLACES` | member object → instance | Association without rendering, so member properties stay reachable | `DISPLAY_INSTANCE` is the render root. `PLACES` is the same object-to-instance link without drawing. Do not treat a definition member as a render placement, or it will draw untransformed at the origin. ## What a script should do instead of unpacking Proxies Use the same project, model, and version address you use today. The outcome is the snapshot you intend to read. Key source elements by `applicationId`, not by their position in a nested `elements` tree. The outcome is a stable object set across versions. If you are producing data rather than only reading it, this only holds if every placement's `applicationId` is unique — a repeated id resolves to the same object, not a second occurrence. Take attributes from property paths on those objects. See [Columnar property store](/next/developers/object-model/overview#columnar-property-store). The outcome is values you can filter without walking nested `Base` fields. For membership, hosting, or connectivity, use relation names such as `ON_LEVEL`, `SUBELEMENT`, `CONNECTS_TO`, and `IN_SYSTEM`. The outcome is topology without unpacking a Proxy `objects` array. That join is already the relation. This page does not document SQL, a local query API, or copy-paste SDK calls. Those surfaces are separate. Until they ship in these docs, use supported SDK accessors and the [developer migration page](/developers/migration/data-model-migration) for breakage and pinning. ## FAQ No. `HOSTED_ON` is placement on a host (a door on a wall). `SUBELEMENT` is ownership (a curtain wall owns its panels). A door is hosted on a wall; it is not a component of the wall. The edge is absent. Scripts should treat a missing relation type as "not in this model," not as a failed receive. Only hosts that have that concept in the source will emit it. That walk is the tree of 2026.8 and earlier. On 2026.9 data, use `IN_COLLECTION`, `IN_MODEL`, `ON_LEVEL`, and `SUBELEMENT` instead of assuming a nested `elements` graph. See [Object model in 2026.9](/next/developers/object-model/overview). No. Detaching and the `reference` object type belong to the object graph of 2026.8 and earlier; a bundle has no `__closure` to resolve them through. Publish the shared thing as its own object and relate the others to it, or, if what you are sharing is really a value rather than an object, write that value as a property on each object. See [Object model in 2026.9](/next/developers/object-model/overview). No. It is the authored location curve. A Revit wall's location line follows its Location Line setting and can be a core or finish face. A point-placed MEP fitting (elbow, tee, cross) has no location curve, so it emits one `CENTERLINE` segment per connector, ordered by connector. No, and that is not the intent. Relations describe how finished objects relate: containment, hosting, connectivity, appearance, instancing. They do not describe how an object was made, and nothing in Speckle rebuilds geometry from a recipe. What you can carry: the exact body through `SOLID` in the host's own format, feature parameters as properties, and ownership through `SUBELEMENT`. A dependency order can travel in your own edge file, which no Speckle consumer reads. Exchanging modelling history would need operation node kinds in the catalog and a modelling kernel on the receiving side. Neither exists today. Yes, as a resolved structure. Parts are objects. A sub-assembly owns its parts through `SUBELEMENT`, or joins them through `IN_ASSEMBLY` when membership is the point. A part used many times is one definition placed by instances, each with its own transform, and a repeated sub-assembly is a nested definition. Part-to-part contact is `CONNECTS_TO`, and exact bodies ride `SOLID`. What does not travel is the constraint system: mates such as coincident or concentric, degrees of freedom, and the solver that positions parts from them. You publish the positions those constraints produced, not the constraints. Yes. Store custom edges in your own parquet files, not in the relation files Speckle SDKs generate — rewriting those files mismatches on the next republish, and you own whatever you add. Do not mint unused numeric relation type ids from the Speckle catalog; Speckle reserves those numbers for future platform types. Which cases need a custom file, and which are really an existing relation or a property, is on [Building integrations in 2026.9](/next/developers/building-integrations#relations-you-do-not-need-and-relations-you-add). They are treated as the same object referenced twice, not as two occurrences. `applicationId` is not required on every object, but wherever it is relied on as identity — a `DISPLAY_INSTANCE` or `DEFINES_INSTANCE` placement, a `Flatten().ToDictionary(o => o.applicationId)` lookup, any join back to a source element — that identity has to be unique for the objects relying on it. A producer that reuses an id across two distinct placements will see the second one silently collapse onto the first: same node, same transform, no error raised. # Where version metadata lives in 2026.9 Source: https://docs.speckle.systems/next/developers/object-model/version-metadata There is no root object in 2026.9 bundle data. What carries a version's identity, source application, units, and model-wide facts instead. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. If your script starts from `version.referencedObject`, reads `units` off the root object, or walks down from it, that script breaks on a 2026.9 version. Bundle data has **no root object**. The jobs the root object used to do are split across four places: the version record on the server, the model ingestion that publishes it, a one-row provenance stamp inside the bundle, and model-scoped properties. This page says where each piece went and what a script reads instead. Before 2026.9, as the [Data Schema](/developers/data-schema/overview) describes, a version points at one object: `version.referencedObject` is the id of the [Root Collection](/developers/data-schema/concepts#root-collection), historically called the commit object. That object is the entry point for every traversal, and it carries the model-wide facts a script reads first: `units`, a `name`, the nested `elements` tree, [Proxies](/developers/data-schema/proxy-schema), and [Info](/developers/data-schema/concepts#info) such as views and the reference point transform. The version record beside it carries the message, source application, author, and creation date. [Versions and the root object](/developers/data-schema/version-root-object) covers that split for 2026.8 and earlier in full. For how objects relate to each other in 2026.9, see [Relations in 2026.9](/next/developers/object-model/relations). For the two-store picture, see [Object model in 2026.9](/next/developers/object-model/overview). ## What the root object carried, and where it lives now | Before 2026.9 | In 2026.9 | Read it with | | - | - | - | | Version id, message, author, created date on the version record | Unchanged shape on the version record. The record exists only after ingestion completes | `client.version.get` / `client.Version.Get` | | `sourceApplication` on the version record, set by `version.create` | Set when the ingestion opens, from the producer slug and version you give the bundle builder | `Version.sourceApplication` | | `referencedObject` is the root object's content hash | A bundle reference: `bundle...`. `Version.schemaVersion` is `3` | Dispatch on the `bundle.` prefix. Never fetch it from the objects endpoints | | `units` on the root object | A `units` property on every object. The bundle builder requires a default unit and stamps it per object | `Model.units` / `Model.Units`, or the object's own `units` property | | Root `name` and the nested `elements` tree | No root node. Grouping containers (subtypes Model, Layer, Collection, Folder, Group) joined to objects by `IN_MODEL` and `IN_COLLECTION`. A scene view picks the tree | [Relations](/next/developers/object-model/relations#containment-and-grouping) | | Proxy lists on the root (materials, levels, groups, instances) | Typed relations | [Relations](/next/developers/object-model/relations) | | Info: views, `referencePointTransform`, analysis results | Model-scoped properties (`referencePoint.*`, document settings, project information), camera views, and optional structural results | `Model.properties` / `Model.Properties`, `Model.camera_views` / `Model.CameraViews` | | `totalChildrenCount` and the `__closure` table | The object count is reported when the upload completes. There is no closure table | `Version.totalChildrenCount` | | Not carried | A `meta` row in the bundle: `schema_version`, `produced_by`, `producer_version`, `sdk_name`, `sdk_version` | `Model.Meta` (.NET). Scripts rarely need it | Two rows need more detail because scripts depend on them today. **The bundle reference is a pointer, not a hash.** On a bundle-only version, `referencedObject` names the version, not its content. Resolve the version through the project and version id you already hold, then read its data with `receive3` / `Receive3`. The embedded model id is the model at creation time and goes stale if the version is later moved. **Units are per object, not per version.** A bundle can carry more than one unit. The SDK's `Model.units` is the first non-empty unit it finds, which is the builder's default on data you published yourself. When precision matters, read the object's own `units` property. ## How a publish creates a version `send3` / `Send3` runs all of this for you. Knowing the sequence explains why the version is not queryable the moment the call returns, and where each piece of metadata is set. The SDK creates an ingestion on the model, carrying the producer slug and version from your bundle builder and the message from your send options. The outcome is an ingestion with a reserved version id. The builder writes its parquet files, named by the reserved version id, and stamps the `meta` row with the spec version and producer. The outcome is a complete bundle on local disk. Each file goes to storage through a presigned upload. The outcome is every file stored under the version id. The SDK completes the ingestion with the bundle reference and the object count. The outcome is the server creating the version in one step, with `referencedObject` set to the bundle reference and `schemaVersion` set to `3`. `send3` returns the reserved id immediately. Poll the ingestion, or call `WaitForVersion` in .NET, before you query, link, or receive it. The outcome is a version that answers queries and arrives as `CREATED` on the `projectVersionsUpdated` subscription. `account`, `project_id` / `projectId`, and `model_id` / `modelId` are already in scope. ```python theme={null} from specklepy.api import operations from specklepy.bundle import BundleBuilder, Producer, SendOptions builder = BundleBuilder(Producer(slug="my-script", version="1.0"), units="m") # add objects, containers, levels, and relations on the builder result = operations.send3( account, project_id, model_id, builder, SendOptions(message="Nightly export") ) print(result.version_id, result.bundle_reference) ``` ```csharp theme={null} var producer = new SpeckleApplication { HostApplication = "My script", HostApplicationVersion = "1.0", Slug = "my-script", SpeckleVersion = "2026.9", }; using var builder = new BundleBuilder(producer, units: "m"); // add objects, containers, levels, and relations on the builder var sent = await SpeckleBootstrap.Operations.Send3( account, projectId, modelId, builder, new SendOptions(Message: "Nightly export"), ct ); var version = await SpeckleBootstrap.Operations.WaitForVersion(account, sent, cancellationToken: ct); ``` `version.create` / `Version.Create` still exist for object graphs from 2026.8 and earlier, and they too return a reserved id now. See [Publish through model ingestions](/developers/migration/publish-through-ingestions) for that path. Automate functions publish the same way. `CreateNewVersionInProject` accepts a bundle builder and returns the reserved version id. ## Read version metadata from a script Read the **version record** for identity and provenance: `message`, `sourceApplication`, `authorUser`, `createdAt`, `schemaVersion`, and `referencedObject`. This is the same query you run today. Read **model-wide facts** from the received `Model`, not from a root object. `units` gives the default unit. `properties` holds the model-scoped rows: the reference point (`referencePoint.kind`, `referencePoint.transform`, `referencePoint.units`) and any document settings or project information the connector published. `camera_views` holds saved cameras. Legacy `receive` / `Receive2` on a bundle-only version returns a compatibility projection. Its root is a `Collection` named `Received model` with the constant id `artifact-root`, carrying `units`, `version = 4`, and rebuilt proxy lists. That root is built when you receive, not stored in the bundle. Do not key on its id, and do not read a message or source application from it. ## FAQ No. Start from the version and receive it as a `Model`, then key objects by `applicationId` and follow relations. A container with subtype `Model` exists as the `IN_MODEL` target, but it is a grouping tier for federated source files, not a root, and it carries only a name. They are different numbers. `Version.schemaVersion` is the server's storage-shape flag: `3` means the version is served as a bundle, `null` means an object graph from 2026.8 or earlier. `meta.schema_version` inside the bundle is the semver of the bundle format the producer wrote against. Neither moves when the other does. It gets a 404 with a `BUNDLE_REFERENCE_NOT_FOUND` body. That is the contract, not empty data. Dispatch on the `bundle.` prefix and receive the version through the SDK instead. Add them as model-scoped properties on the bundle builder, not on an object. That is the home for document settings, project information, and a reference point. Units go on the builder, or on an individual object when it differs from the default. # Assess .NET SDK breaking changes Source: https://docs.speckle.systems/next/developers/sdks/dotnet/breaking-changes Before-and-after Speckle.Sdk examples so you can judge 2026.9 migration impact. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Use this page to judge what a Speckle.Sdk script must change for 2026.9. It is not a replacement for the [scripts and notebooks](/developers/sdks/dotnet/getting-started/scripts-and-notebooks) guide, and it is not a full API reference. Prior to 2026.9, the path is still **PAT → bootstrap → `Receive2` → `Flatten`**. In 2026.9 that receive is obsolete. The new path is **`Receive3`**, which returns a disposable `Model` with columnar properties and typed relations. Dates, compatibility mode, and who must act are on [Data model migration for developers](/developers/migration/data-model-migration). The object-model change itself is on [Object model in 2026.9](/next/developers/object-model/overview). Versions published by a 2026.9 connector need a Speckle.Sdk **2026.9** build. An older SDK 404s on that data. Versions from older connectors keep working on the SDK you have today. See [Who's affected](/developers/migration/data-model-migration#whos-affected). Prefer `Receive3` for new scripts. `Receive2` stays callable on legacy object-graph versions. ## What changes for a script | Concern | Prior to 2026.9 | In 2026.9 | | - | - | - | | Packages | `Speckle.Sdk` plus `Speckle.Objects` | One `Speckle.Sdk` package. `Speckle.Objects` is a type-forwarding shell you can delete | | Load a version | `Receive2` with `version.referencedObject` | `Receive3` with a model URL or project, model, and version ids. Returns `Speckle.Sdk.Bundles.Model` | | Filter and count | `Flatten()` then `DataObject.properties` | `model.Objects`, `ObjectsWith`, and `GetString` / `GetDouble` | | Nested property walk | `properties["x"]` then `["y"]` | Dotted path (`GetString("x.y")`) or `PropertyView.Under` | | Level, material, groups | Unpack proxy `objects` lists | Accessors on `ModelObject` (`Level`, `Material`, `Collection`) | | Publish from a script | `Send2` then `Version.Create` | `Send3` with a `BundleBuilder`. The version is visible only after ingestion completes | | Transports | `Send` / `Receive` with `ITransport` | Frozen legacy surface. A bundle reference through transport `Receive` throws | ## Update packages Bump every Speckle NuGet reference to the same **2026.9** version, then remove `Speckle.Objects`. Namespaces stay `Speckle.Objects.*`, so usings do not change. ```bash theme={null} dotnet add package Speckle.Sdk ``` Then delete the `Speckle.Objects` package reference from the project file. Pin an explicit 2026.9 build rather than a floating range. Mixing a pre-merge `Speckle.Objects` with a merged `Speckle.Sdk` fails the build. Update every Speckle package together. You can drop `typeof(Speckle.Objects.Geometry.Point).Assembly` from `AddSpeckleSdk` unless you register your own `Base` types. Geometry types now live in `Speckle.Sdk`. ## Load a model Prior to 2026.9, you resolve `referencedObject` and call `Receive2`. In 2026.9, `Receive2` is marked `[Obsolete]`. `Receive3` takes the same account and ids and returns a disposable `Model`. Wrap that `Model` in `using`: it owns the downloaded bundle files on disk until you dispose it. Auth, bootstrap, and version lookup stay on [scripts and notebooks](/developers/sdks/dotnet/getting-started/scripts-and-notebooks). The snippets below assume `account`, `client`, `projectId`, `modelId`, and `latest` are already in scope. ```csharp Prior to 2026.9 lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null} var root = await SpeckleBootstrap.Operations.Receive2( client.ServerUrl, projectId, latest.referencedObject!, account.token ); ``` ```csharp 2026.9 lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null} using var model = await SpeckleBootstrap.Operations.Receive3( account, projectId, modelId, latest.id ); ``` `Receive3` can also take the model URL the web app copies. Omit `@versionId` to receive the latest version without a version id. ## Count and filter objects Prior to 2026.9, you walk a `Base` tree. In 2026.9, objects are a flat list. Properties are path-keyed (`"category"`, `"Constraints.Base Offset"`). Relations are accessors, not Proxy lists. ```csharp Prior to 2026.9 lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null} var counts = root.Flatten() .OfType() .GroupBy(d => d.properties.GetValueOrDefault("category") as string ?? "Unknown"); var byLevel = root.Flatten() .OfType() .GroupBy(d => d.properties.GetValueOrDefault("level")?.ToString() ?? "Unknown"); var walls = root.Flatten() .OfType() .Where(d => d.properties.GetValueOrDefault("category") as string == "Walls"); ``` ```csharp 2026.9 lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null} var counts = model.Objects.GroupBy(o => o.GetString("category") ?? o.Name ?? "Unknown"); var byLevel = model.Objects.GroupBy(o => o.Level?.Name ?? "Unknown"); var walls = model.ObjectsWith("category").Where(o => o.GetString("category") == "Walls"); ``` Look up one object with `model.ObjectByApplicationId(id)`. `applicationId` is the only identity a bundle object has. Do not treat `Base.id` as a content hash on bundle-only versions. ## Replace property walks Prior to 2026.9, nested parameters are dictionaries you walk: `obj.properties["x"]` then `["y"]`. In 2026.9 those paths are flat. `PropertyView` is the type that replaces that walk. ### PropertyView `PropertyView` (`Speckle.Sdk.Pipelines.Receive.Artifacts`) is a read-only view over one object's property rows. Keys are dotted paths (`"Constraints.Base Offset"`), not nested dictionaries. It does not allocate until you enumerate it. `ModelObject.Properties` is this view; cast to `PropertyView` when you need the helpers below. * **`GetString` / `GetDouble` / `GetBool`:** typed lookup. Null if the path is missing or the value is another type. * **`Under("Constraints")`:** the subtree under that prefix, with the prefix stripped. No allocation. * **Indexer / `TryGetValue`:** untyped lookup, same paths as `GetString`. * **`ToNested()`:** the old nested-dictionary tree. Allocates. Use only when a caller still requires that shape. `ModelObject.GetString`, `GetDouble`, and `GetBool` do the same typed lookup with instance, then type, then root-scalar precedence. Prefer those for a single path. Use `PropertyView.Under` when you need a group. ```csharp Prior to 2026.9 lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null} var wall = root.Flatten().OfType().First(); var groups = wall.properties.GetValueOrDefault("parameters") as Dictionary; var x = groups?.GetValueOrDefault("x") as Dictionary; var y = x?.GetValueOrDefault("y"); ``` ```csharp 2026.9 lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null} var wall = model.Objects.First(); var y = wall.GetString("parameters.x.y"); var offset = wall.GetDouble("Constraints.Base Offset"); var constraints = ((PropertyView)wall.Properties).Under("Constraints"); foreach (var kv in constraints) { Console.WriteLine($"{kv.Key}: {kv.Value}"); } ``` ## Replace Proxy walks Prior to 2026.9, grouping by level or material means indexing `applicationId`s and resolving proxy `objects` lists. In 2026.9 those links are typed relations. See [Relations in 2026.9](/next/developers/object-model/relations) for the names. ```csharp Prior to 2026.9 lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null} var byAppId = root.Flatten() .Where(o => o.applicationId is not null) .ToDictionary(o => o.applicationId!); ``` ```csharp 2026.9 lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null} var byLevel = model.Objects.GroupBy(o => o.Level?.Name ?? "Unknown"); var hosted = model.Objects.Where(o => o.Host is not null); ``` A missing nested `elements` tree or Proxy `objects` list on 2026.9 data is expected. Do not unpack Proxies to rebuild containment. ## What Receive2 still does `Receive2` remains callable. It is obsolete for a reason. * **Legacy object-graph versions:** behaviour is unchanged. You still pass `referencedObject` as a content hash. * **Bundle-only versions:** `referencedObject` is a bundle reference (`bundle...`). A 2026.9 SDK dispatches on that prefix and returns a best-effort `Base` tree (DataObject idiom, `version = 4` on the root). That projection does not scale to the model sizes the bundle format is built for, and it is not a lossless round trip. * **Older SDKs:** fetching that `referencedObject` from the objects API returns **404** with upgrade guidance. Upgrade Speckle.Sdk rather than parsing the 404 body. Transport-based `Receive` cannot load bundle-only versions. It throws if you pass a bundle reference. Receiving a bundle-only version as a `Base` tree and sending it again with `Send2` is not a supported copy workflow. The tree is a baked view, not the authored graph. Receive, derive new data, then send remains ordinary supported use. ## Publish from a script Most analysis scripts only receive. If you currently call `Send2` then `Version.Create`, the 2026.9 replacement is `Send3` with a `BundleBuilder`. `Send2` stays accepted and starts emitting deprecation warnings. There is no removal date. `Send3` returns a reserved version id immediately. Queries, the version URL, and the `version_create` webhook fire when ingestion completes. Poll for the version, or watch the project's model ingestions, if you need to follow up in the same process. ## FAQ Upgrade Speckle.Sdk first so versions from a 2026.9 connector do not 404. Versions from older connectors keep working on `Receive2`. Rewrite to `Receive3` when you need relations, columnar property lookups, or models that are too large to materialize as a `Base` tree. `Model` is the bundle itself: objects, path-keyed properties, and relation accessors, with geometry parsed only when you ask. A `Base` tree inflates every object and mesh into managed objects. That is why `Receive2` is obsolete for the new format. Downloaded parquet files stay under a scratch directory until `Dispose` runs. Always wrap the result in `using`. Objects and already-loaded geometry stay in memory after dispose; geometry you have not touched yet cannot be read afterwards. Yes for hash-era data, until that path is retired. It will never carry bundles. Move server-facing scripts to `Receive3`. See the [send and receive paths](/developers/sdks/dotnet/concepts/send-and-receive-paths) page for the transport story. # Assess specklepy breaking changes Source: https://docs.speckle.systems/next/developers/sdks/python/breaking-changes Before-and-after specklepy examples so you can judge 2026.9 migration impact. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Use this page to judge what a specklepy script must change for 2026.9. It is not a replacement for the [specklepy](/developers/sdks/python/introduction) guides, and it is not a full API reference. Prior to 2026.9, the path is still **PAT → `operations.receive` → walk a `Base` tree**. In 2026.9 that receive is a compatibility shim. The new path is **`operations.receive3`**, which returns a disposable `Model` with columnar properties and typed relations. Dates, compatibility mode, and who must act are on [Data model migration for developers](/developers/migration/data-model-migration). The object-model change itself is on [Object model in 2026.9](/next/developers/object-model/overview). Versions published by a 2026.9 connector need specklepy **2026.9.0b3** or later, installed with the `bundle` extra. An older build 404s on that data. Versions from older connectors keep working on the specklepy you have today. See [Who's affected](/developers/migration/data-model-migration#whos-affected). Prefer `operations.receive3` for new scripts. `operations.receive` stays callable on legacy object-graph versions, and on bundle-only versions it returns a projected `Base` tree. ## What changes for a script | Concern | Prior to 2026.9 | In 2026.9 | | - | - | - | | Package | `pip install specklepy` | `pip install "specklepy[bundle]==2026.9.0b3"`. The `bundle` extra pulls in pyarrow | | Load a version | `operations.receive` with `referenced_object` | `operations.receive3` with account plus project, model, and version ids. Returns `Model` | | Filter and count | Walk `elements`, then `DataObject.properties` | `model.objects`, `objects_with`, and `get_string` / `get_double` | | Nested property walk | `properties["x"]` then `["y"]` | Dotted path (`get_string("x.y")`) or `PropertyView.under` | | Level, material, groups | Unpack proxy `objects` lists | Accessors on `ModelObject` (`level`, `host`, `collection`) | | Publish from a script | `operations.send` then `client.version.create` | `operations.send3` with a `BundleBuilder`. The version is visible only after ingestion completes | | Transports | `send` / `receive` with `ServerTransport` | Frozen legacy surface. A bundle reference through `receive` needs an authenticated `ServerTransport` | ## Update specklepy first Install a 2026.9 specklepy that can receive bundle-only versions, including the `bundle` extra. **2026.9.0b3** is the first public build that does this. A later stable **2026.9.0** replaces the beta pin; the calls on this page do not change. ```bash theme={null} pip install "specklepy[bundle]==2026.9.0b3" ``` On a bundle-only version, `version.referenced_object` is a bundle reference such as `bundle...`, not a content hash. An older specklepy treats that string as an object id, requests it from the objects API, and receives a 404 whose body tells you to upgrade. Do not fetch `version.referenced_object` from the objects REST endpoints. Bundle references always 404 there, including after you upgrade. Pass ids to `operations.receive3`, or pass the reference to `operations.receive` and let specklepy dispatch. ## Load a model Prior to 2026.9, you resolve `referenced_object` and call `operations.receive`. In 2026.9, `operations.receive3` takes an `Account` plus project, model, and version ids and returns a disposable `Model`. Use it as a context manager: it owns the downloaded bundle files on disk until the `with` block ends. Auth and version lookup stay on [Authentication](/developers/sdks/python/getting-started/authentication) and the [Quickstart](/developers/sdks/python/getting-started/quickstart). The snippets below assume `account`, `client`, `transport`, `project_id`, `model_id`, and `version_id` are already in scope. Build `account` with `Account.from_token` and a PAT, or `get_default_account()`. ```python Prior to 2026.9 lines icon="python" theme={null} version = client.version.get(version_id, project_id) root = operations.receive(version.referenced_object, remote_transport=transport) ``` ```python 2026.9 lines icon="python" theme={null} with operations.receive3(account, project_id, model_id, version_id) as model: pass ``` Close the model (leave the `with` block, or call `model.close()`) so the download directory is deleted. Parsed objects stay usable after close. Geometry you have not touched yet cannot be read afterwards. ## Count and filter objects Prior to 2026.9, you walk a `Base` tree. In 2026.9, objects are a flat list. Properties are path-keyed (`"category"`, `"Constraints.Base Offset"`). Relations are accessors, not Proxy lists. ```python Prior to 2026.9 lines icon="python" theme={null} from specklepy.objects.data_objects import DataObject def iter_elements(obj): yield obj for child in getattr(obj, "elements", None) or []: yield from iter_elements(child) counts = {} for obj in iter_elements(root): if not isinstance(obj, DataObject): continue key = (obj.properties or {}).get("category") or "Unknown" counts[key] = counts.get(key, 0) + 1 by_level = {} for obj in iter_elements(root): if not isinstance(obj, DataObject): continue key = (obj.properties or {}).get("level") or "Unknown" by_level.setdefault(key, []).append(obj) walls = [ o for o in iter_elements(root) if isinstance(o, DataObject) and (o.properties or {}).get("category") == "Walls" ] ``` ```python 2026.9 lines icon="python" theme={null} counts = {} for obj in model.objects: key = obj.get_string("category") or obj.name or "Unknown" counts[key] = counts.get(key, 0) + 1 by_level = {} for obj in model.objects: key = obj.level.name if obj.level else "Unknown" by_level.setdefault(key, []).append(obj) walls = [o for o in model.objects_with("category") if o.get_string("category") == "Walls"] ``` Look up one object with `model.object_by_application_id(id)`. `application_id` is the only identity a bundle object has. Do not treat `Base.id` as a content hash on bundle-only versions. ## Replace property walks Prior to 2026.9, nested parameters are dictionaries you walk: `obj.properties["x"]` then `["y"]`. In 2026.9 those paths are flat. `PropertyView` is the type that replaces that walk. `ModelObject.properties` is already this view. * **`get_string` / `get_double` / `get_bool`:** typed lookup. `None` if the path is missing or the value is another type. Instance, then type, then root-scalar precedence. * **Indexer (`obj["path"]`):** untyped lookup, same precedence. * **`properties.under("Constraints")`:** the subtree under that prefix, with the prefix stripped. * **`to_nested()`:** the old nested-dictionary tree. Allocates. Use only when a caller still requires that shape. Prefer `get_string` / `get_double` for a single path. Use `under` when you need a group. The snippets below assume `wall` is already in scope: a `DataObject` from the tree, or a `ModelObject` from `model.objects`. ```python Prior to 2026.9 lines icon="python" theme={null} groups = (wall.properties or {}).get("parameters") or {} x = groups.get("x") or {} y = x.get("y") ``` ```python 2026.9 lines icon="python" theme={null} y = wall.get_string("parameters.x.y") offset = wall.get_double("Constraints.Base Offset") constraints = wall.properties.under("Constraints") for key, value in constraints.items(): print(f"{key}: {value}") ``` If the script reads `parameter["value"]` or other per-parameter metadata from the received tree, that shape is gone on bundle-only versions. Read the value from a dotted path, not from a metadata wrapper. ## Replace Proxy walks Prior to 2026.9, grouping by level or material means indexing `applicationId`s and resolving proxy `objects` lists. In 2026.9 those links are typed relations. See [Relations in 2026.9](/next/developers/object-model/relations) for the names. ```python Prior to 2026.9 lines icon="python" theme={null} by_app_id = {} for obj in iter_elements(root): app_id = getattr(obj, "applicationId", None) if app_id: by_app_id[app_id] = obj ``` ```python 2026.9 lines icon="python" theme={null} by_level = {} for obj in model.objects: key = obj.level.name if obj.level else "Unknown" by_level.setdefault(key, []).append(obj) hosted = [o for o in model.objects if o.host is not None] ``` A missing nested `elements` tree or Proxy `objects` list on 2026.9 data is expected. Do not unpack Proxies to rebuild containment. ## What operations.receive still does `operations.receive` remains callable. It is the compatibility path, not the 2026.9 default. * **Legacy object-graph versions:** behaviour is unchanged. You still pass `referenced_object` as a content hash. * **Bundle-only versions:** `referenced_object` is a bundle reference (`bundle...`). A 2026.9 specklepy dispatches on that prefix and returns a best-effort `Base` tree (`Model.to_base()`, DataObject idiom, `version = 4` on the root). That projection does not scale to the model sizes the bundle format is built for, and it is not a lossless round trip. It needs an authenticated `ServerTransport` for the reference's project. * **Older specklepy:** fetching that `referenced_object` from the objects API returns **404** with upgrade guidance. Upgrade specklepy rather than parsing the 404 body. Receiving a bundle-only version as a `Base` tree and sending it again with `operations.send` is not a supported copy workflow. The tree is a baked view, not the authored graph. Receive, derive new data, then send remains ordinary supported use. ## Publish from a script Most analysis scripts only receive. If you currently call `operations.send` then `client.version.create`, the 2026.9 replacement is `operations.send3` with a `BundleBuilder`. `operations.send` stays accepted and starts emitting deprecation warnings. There is no removal date. `send3` returns a reserved version id immediately. Queries, the version URL, and the `version_create` webhook fire when ingestion completes. Poll for the version, or watch the project's model ingestions, if you need to follow up in the same process. ## FAQ Upgrade specklepy first so versions from a 2026.9 connector do not 404. Versions from older connectors keep working on `operations.receive`. Rewrite to `operations.receive3` when you need relations, columnar property lookups, or models that are too large to materialize as a `Base` tree. `Model` is the bundle itself: objects, path-keyed properties, and relation accessors, with geometry parsed only when you ask. A `Base` tree inflates every object and mesh into Python objects. That is why `operations.receive` is the compatibility path for the new format, not the default. Downloaded parquet files stay under a scratch directory until `close` runs. Always use a `with` block. Objects and already-loaded geometry stay in memory after close; geometry you have not touched yet cannot be read afterwards. Yes for hash-era data, until that path is retired. For bundle-only versions, `operations.receive` still needs an authenticated `ServerTransport` so it can dispatch to `receive3`. Move server-facing scripts to `operations.receive3`. On a bundle-only receive, parameter metadata is collapsed to scalars on dotted paths. Read the value with `get_double` or `obj["Width"]`, not from a metadata wrapper. That is a contracted receive-fidelity change, not a bug in your filter. # JS/TS SDK notes in 2026.9 Source: https://docs.speckle.systems/next/developers/sdks/typescript/introduction 2026.9 notes for the TypeScript and JavaScript SDK are not on this preview yet. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. 2026.9 developer notes for the TypeScript and JavaScript SDK are not on this preview yet. Use the [current JS/TS SDK documentation](/developers/sdks/typescript/introduction) until those notes land. **Building directly on the Viewer package, or on `@speckle/objectloader` / `@speckle/objectloader2`?** This is the case most likely to break silently, and it's easy to miss in the general migration comms because it isn't "just" an SDK or API consumer. Your app stops getting data as soon as any version you load is a 2026.9 bundle: the objects endpoints return 404\. Start from [Building applications](/next/developers/building-applications), which routes rendering apps and data-only apps to the right load path and explains why there is no drop-in object-graph loader. Package-level JS/TS notes for 2026.9 are still to come. For the Viewer specifically, see [Building on the Viewer package in 2026.9](/next/developers/viewer/introduction). # Server notes in 2026.9 Source: https://docs.speckle.systems/next/developers/server/introduction 2026.9 notes for Speckle Server deployment and self-hosting are not on this preview yet. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. 2026.9 developer notes for Speckle Server deployment and self-hosting are not on this preview yet. Use the [current Server documentation](/developers/server/introduction) until those notes land. The open-source Speckle Server (core release) does not support 2026.9. If you run the open-source server, pin your connectors to 2026.8 or earlier. 2026.9 connectors will not work against it. This does not apply to Speckle Enterprise Server, including deployments on third-party infrastructure. If you maintain or operate an Enterprise-licensed server, work with your infrastructure support agent to plan your move to 2026.9. # Building on the Viewer package in 2026.9 Source: https://docs.speckle.systems/next/developers/viewer/introduction What changes for apps that import the Viewer package when the data they load becomes a 2026.9 bundle, and the two ways to keep rendering. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. If your application imports `@speckle/viewer` and loads Speckle data itself, 2026.9 changes what it loads. A version's data is no longer an object graph fetched from the objects endpoints; it is a [bundle](/next/developers/building-integrations) of parquet files. The published Viewer package has no loader for that shape, so a bundle version renders nothing and the objects endpoints return 404. The rest of the package is unaffected. Render pipelines, extensions, filtering, selection, queries, the world tree and view modes all work the same way, because the change is in where the data comes from, not in what the viewer does with it once converted. ## Am I affected? | How your app uses the Viewer | Affected | | - | - | | Imports `@speckle/viewer`, constructs a `Viewer` and a loader | Yes | | Extends render pipelines or extensions, reads render views or batches | Yes | | Embeds the hosted web viewer in an iframe | No | | Reads data only through the GraphQL or REST API | No | ## Two ways forward Add about a dozen files to your app, keep the same published packages, and render bundles. Sample code and a step-by-step path. Keeps your workspace's data in the object-graph format, so your app keeps working unchanged until the mode ends on **1 November 2026**. Loading bundles is the route that outlasts compatibility mode, which ends on **1 November 2026**. It is sample code rather than a package release, so you own the copy and it carries a date — see the guide for what it does and does not cover. Neither option reaches what 2026.9 makes possible. The bundle format is built for streaming reads, sharded geometry and querying properties without materialising objects, and both options here keep your app on the object graph it replaced: compatibility mode by producing that graph, the bridge by rebuilding it in memory. Getting the performance the format allows needs a viewer built for it. Plan for that, and treat both of these as ways to keep working until it arrives. Compatibility mode is not self-serve, and it ends for every workspace on **1 November 2026**. See [Compatibility mode](/next/it-admin/compatibility-mode) for how to request it. ## Not the Viewer package Two nearby cases have their own pages. * **A data-only JavaScript app** that reads Speckle data without rendering it — built on `@speckle/objectloader` or `@speckle/objectloader2` — should read the bundle directly rather than bridging to an object graph. Start from [Building applications](/next/developers/building-applications). * **The 3D viewer in the product UI** is not this package. See [3D viewer in 2026.9](/next/3d-viewer/introduction). ## Package reference Package-level Viewer API documentation is unchanged by 2026.9 and lives in the other documentation version: [Viewer developer documentation](/developers/viewer/introduction). The API surface the bridge relies on — `Loader`, `SpeckleLoader`, `WorldTree`, `loadObject` — is documented there. # Load a 2026.9 bundle in your Viewer app Source: https://docs.speckle.systems/next/developers/viewer/loading-bundles Sample code and a step-by-step path for rendering 2026.9 bundle versions with the published Viewer package, without waiting for a new package release. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. If your app imports `@speckle/viewer` and loads Speckle data itself, a 2026.9 version gives it nothing to draw: the version's data is a [bundle](/next/developers/building-integrations) of parquet files, and the objects endpoints return 404. This page is the bridge. You add about a dozen files to your own app, keep the same two published packages you already depend on, and the viewer renders bundles. Nothing is patched and nothing new is published. You read the bundle, project it onto the object shape the viewer already converts, and hand those objects to the loader. This is sample code, not a package: it is not versioned and it is not supported the way a release is. Copy it into your app and own the copy. ## Check whether this affects you Read a version record before assuming either shape. | Field | 2026.8 and earlier | 2026.9 bundle | | - | - | - | | `Version.schemaVersion` | `null` | `3` | | `Version.referencedObject` | A content hash | `bundle...` | | Where the data is | The objects endpoints, as JSON | The artifacts endpoint, as parquet files | You need this page if your app constructs a viewer and a loader itself. You do not need it if you embed the hosted web viewer in an iframe, or if you only read data through the GraphQL or REST API. Compatibility mode keeps a workspace's data in the object-graph format until the mode ends on **1 November 2026**. See [Compatibility mode](/next/it-admin/compatibility-mode). ## What the bridge does 1. Reads the version record and dispatches on its shape. 2. Lists the version's artifacts and downloads the parquet tables it needs. 3. Decodes SGEO geometry. 4. Projects the bundle onto `Base` objects, with collection, material, colour and instance proxies. 5. Hands those objects to `ObjectLoader2Factory.createFromObjects` through a `SpeckleLoader` subclass. Everything after that is untouched public API. Extensions, filtering, selection, queries, camera and view modes all behave as they do today, because by the time the viewer sees your data it is the same kind of object tree it always converted. The worked sample, including a mini viewer app that loads both shapes of version, is [examples/viewer-bundle-bridge](https://github.com/specklesystems/speckle-docs-new/tree/main/examples/viewer-bundle-bridge). It lives in the docs repo, so take that directory on its own rather than cloning the rest: ```bash theme={null} git clone --filter=blob:none --sparse --depth 1 \ https://github.com/specklesystems/speckle-docs-new.git cd speckle-docs-new git sparse-checkout set examples/viewer-bundle-bridge ``` ## What the bridge costs you That last sentence is the trade. The bridge reconstitutes the object graph 2026.9 retires: it reads the whole bundle, builds `Base` objects in memory, and hands them to the converter that has always run. So it inherits the load time and memory profile you have today, and it gives up most of what the bundle format exists to enable — streaming reads, sharded geometry fetched on demand, dense integer keys, properties queried without materialising objects, and the server-built viewer artifact. 2026.9 raises the performance ceiling well above what this bridge can reach. Reaching it needs a viewer built for the format, not a projection back onto the shape it replaced. Read the bridge as what keeps your app working across the format change, not as where it should stay. It is at its best on models of the size you render well today; it will not make a model that is slow now fast, and on very large models it can be worse than the object graph was, because the whole bundle is read before anything draws. ## 1. Pin both packages exactly Pin `@speckle/viewer` and `@speckle/objectloader2` to the same version, with no carets. The bridge depends on internals of neither, but it does depend on `initObjectLoader` being overridable and on `createFromObjects` existing, and a range would let a future release move either. ```json package.json theme={null} { "dependencies": { "@speckle/objectloader2": "2.31.14", "@speckle/viewer": "2.31.14" } } ``` You should see both packages resolve to exactly `2.31.14` in your lockfile. ## 2. Add a parquet reader and a zstd codec A bundle is parquet, and the files are zstd-compressed. Both dependencies go in **your** `package.json`, not in a Speckle package. ```bash theme={null} pnpm add hyparquet hyparquet-compressors ``` Read the geometry table with UTF-8 decoding turned **off**. The `content` column is a byte array with no string logical type, and a reader that decodes every byte array as UTF-8 by default will mangle every SGEO blob — silently, with no error and no geometry. You should see a parquet read return rows whose `content` values are byte arrays, not strings. Find the tables by matching the end of each file name, never by building it from the version id. A bundle's files share a stem, but that stem is not always the version — a Revit upload lists as `acme-b-zz-m3-wa-ar.rvt.envelope.nodes.parquet`, with only the viewer's own artifacts named after the version. ## 3. Drop in the projection Copy `src/bridge/` from the sample into your app. `projectBundle` turns the bundle into the object shape the viewer already converts: a collection tree, one object per `applicationId` carrying its display geometry, and instance, material and colour proxies. Rendering is unconditional: geometry, nested instances, grouping, and the full material and colour precedence from the geometry up through the object to its container. Two things cost extra reads, so they are options rather than defaults: ```ts theme={null} projectBundle(bundle, { properties: true, referencePoint: true }) ``` `properties` merges each object's instance and type-level rows — the type rows live in their own table, and without that merge most Revit type parameters are simply absent. `referencePoint` carries the model's datum onto the root. An app that only draws leaves both off and never downloads the eav tables at all. Solids, centrelines and the scene-view tree are carried by the bundle and read by none of this. Add what your app needs rather than assuming its absence is a bug — the rules for every table and relation are in [Load a bundle in your own code](/next/developers/building-integrations/load). You should see `projectBundle` return a root object whose `elements` hold your objects. ## 4. Swap the loader Both shapes of version end at `viewer.loadObject`. The only difference is which loader gets there, so dispatch on `schemaVersion` and keep your existing path intact. Assume `viewer`, the project, model and version ids, and a token are already in scope. ```ts Prior to 2026.9 theme={null} const loader = new SpeckleLoader(viewer.getWorldTree(), objectUrl, token) await viewer.loadObject(loader, true) ``` ```ts 2026.9 theme={null} const { loader } = await loadBundleVersion({ tree: viewer.getWorldTree(), ref: { serverUrl, projectId, modelId, versionId }, token, project: projectBundle }) await viewer.loadObject(loader, true) ``` The subclass itself is short, because everything asynchronous happens before construction. The base class passes `resourceData` through to `initObjectLoader`, which is how the projected objects reach the override before any subclass field exists — the same route `SpeckleOfflineLoader` takes. ```ts bundleLoader.ts theme={null} export class BundleLoader extends SpeckleLoader { constructor(targetTree: WorldTree, resource: string, root: BaseObject) { super(targetTree, resource, undefined, undefined, root) } protected initObjectLoader( _resource: string, _authToken?: string, _enableCaching?: boolean, resourceData?: unknown ): ObjectLoader2 { const root = resourceData as BaseObject | undefined if (!root) throw new Error('BundleLoader was constructed without a projected root') return ObjectLoader2Factory.createFromObjects([root]) } } ``` You should see the model render, and `viewer.getWorldTree()` report nodes. Your own extensions need no changes. They are created the same way, see the same world tree, and resolve the same ids. The sample proves that with two the Speckle web app never runs: `ExplodeExtension`, which ships with the viewer, and a box select written from scratch — ```ts extensions/boxSelect.ts theme={null} export class BoxSelectExtension extends Extension { get inject(): Array { return [SelectionExtension, CameraController] } private idsInside(rect: Rect): string[] { const camera = this.viewer.getRenderer().renderingCamera const ids = new Set() this.viewer.getWorldTree().walk((node: TreeNode) => { const aabb = node.model.renderView?.aabb if (aabb && inside(project(centre(aabb), camera), rect)) { ids.add(String(node.model.raw.applicationId)) } return true }) return [...ids] } } ``` If an extension written from scratch against public API works on bridged data, the Viewer 2 surface works on 2026.9 data generally — not only the paths Speckle exercises. Read render views across every node, not only `atomic` ones, and expect some to have no bounds. Render views hang off the nested geometry nodes, so a walk that checks atomic nodes alone finds nothing on a model that renders perfectly well. ## 5. Rekey your interactions to applicationId Everything above is copy-paste. This step is your app's own data model, and skipping it is what makes a load look successful while your saved state silently matches nothing. Before 2026.9, a Speckle object's identity was a content hash, stable across versions of the same unchanged element and usable as a durable key. In a bundle there is no hash. **The object's identity is `applicationId`** — the id the authoring application gave the element. The bridge sets `id` to `applicationId` on every object, so the ids the viewer hands you in selection events, queries and filtering state are `applicationId` values. What that changes: * **Anything you persisted keyed by object id needs a migration or a rekey.** Saved selections, comment anchors, your own annotations, cached per-object state. A stored content hash will not match anything in a bundle. * **`applicationId` is stable across versions in a way hashes were not.** An element that moved still carries the same `applicationId`, where its hash changed. For most apps this is better: your per-object state survives a republish. * **Synthetic ids are per-bundle.** Anything the projection mints rather than reads — containers (`coll-7`), definitions (`def-3`), materials (`mat-0`) — is local to one bundle and will differ in the next version. Never persist those. * **Duplicate `applicationId` values are possible.** Producers are asked for stable unique ids and mostly deliver them, but a host with no stable id per element can repeat one. Decide whether last-wins or a reported conflict is right for your app. If your app already keys on `applicationId` because it cross-references a host model, this step is a no-op and you are most of the way done. You should see selection in your app resolve to the same objects it did before, keyed by `applicationId`. ## What does not come across A bundle carries far more than the projection reads, and more than the published viewer can draw. None of these raise an error, so check the list against what your app promises. **Relations.** The catalog is in [Relations](/next/developers/object-model/relations). The projection reads DISPLAY, DEFINES, HAS\_MATERIAL, HAS\_COLOR, DISPLAY\_INSTANCE, DEFINES\_INSTANCE, IN\_COLLECTION and the object and node appearance relations. Everything else is carried and unread: solids, centrelines, scene views, levels, rooms, systems, groups, assemblies, connectivity and hosting. Those rows are in the bundle and available to you — nothing in the sample reads them into the tree. **Geometry.** Meshes, lines, polylines and the tessellated curve family render. Text, points, boxes and regions decode but are not converted. The sample counts what it skipped and prints the tally, so a model that is mostly annotation looks empty for a stated reason. **Vocabulary you do not know.** Read columns by name and tolerate columns you do not know, and treat a relation id or node kind your reader does not recognise as skip-and-report rather than an error. A producer newer than your copy of the bridge is normal, and the sample surfaces those ids for you. Do not gate a load on `meta.schema_version`. It is provenance, not a compatibility switch, and the spec adds columns without moving it. The sample is verified against `@speckle/viewer@2.31.14`, `@speckle/objectloader2@2.31.14` and bundle spec 1.2.0, as of September 2026. Check those pins before assuming a behaviour still holds. ## Viewer concepts that still apply The bridge changes where data comes from, not how the viewer works. The loader and tree documentation still applies: What a loader is and where it sits in a load. The abstract `Loader` contract the subclass implements. What the converter builds, and how to query it. Earlier viewer migrations, for context on what changed before. ## FAQ Publishing it would make a third implementation of the receive fidelity contract that Speckle then has to keep in step with the .NET and Python SDKs. Sample code you own is honest about what it is: a worked example of documented rules, dated, in your app, under your control. Yes — pass `includeGeometry: false` and the geometry shards, which are the bulk of a bundle, are never fetched. The projection here renders, so that leaves it with nothing to draw; it is useful once you extend the projection to read the eav tables. Not from another origin. Your app cannot read Speckle's auth cookie — that is the origin model — and sending the request with `credentials: 'include'` does not help either, because the cookie is `SameSite=Lax` and so never rides a cross-site fetch. Use a token. A public project needs none at all: send no `Authorization` header rather than an empty one, which is rejected. Yes, and you keep the same version. The bridge uses `ObjectLoader2Factory.createFromObjects` instead of `createFromUrl`, which is why no request goes to the objects endpoints. Either the version is an object graph from 2026.8 or earlier, the bundle has not been produced yet, or your token cannot read the project. Check `schemaVersion` on the version record first, then the ingestion status if the version is new. Read the bundle directly rather than bridging to an object graph. Start from [Building applications](/next/developers/building-applications), which points at the load mechanics for data-only apps. A nested instance — a definition placed inside another definition — logs this once per nested placement. The converter looks the node up after the parent definition has already consumed it. The tree is still correct: the nested definition expands and renders under its transform. What it does skip is the container-colour fallback for that nested placement. Give every object you mint a distinct id. The converter counts definition members by `applicationId` and stops as soon as its count is met, so a duplicate consumes another member's slot and that member is dropped. This is why the sample suffixes definition geometry rather than reusing its carrier's id. Instance placement is not being applied. Check that your projection emits an `InstanceProxy` per `DISPLAY_INSTANCE` edge with the instance node's transform, and that objects carrying a definition member's properties are not also drawn — a carrier with geometry draws twice, once untransformed at the origin. # Compatibility mode for ACC sync and uploads Source: https://docs.speckle.systems/next/it-admin/compatibility-mode Compatibility mode ends for every workspace on 1 November 2026. After that date, ACC sync and drag-and-drop uploads always use the 2026.9 data format. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Scripts and reports that expect the earlier data format can stop working when a workspace moves to 2026.9. Compatibility mode keeps ACC sync and drag-and-drop uploads in that format while you update the tools that read the data. For ACC hub setup that does not change, see [Enable Autodesk Forma Data Management integration](/it-admin/integrations/acc). For the user-facing migration steps, see [Speckle's data model is changing](/workspaces/data-model-migration). Compatibility mode ends for every workspace on **1 November 2026**, whenever it was turned on. From that date, ACC sync and drag-and-drop uploads write the 2026.9 format. Update dependent scripts and reports before then. For changes to accepted file extensions, see [File uploads in 2026.9](/next/connectors/file-uploads). ## When to request it Compatibility mode is a short bridge while you update downstream tools. It is not a way to stay on the old format. Request it when all of the following are true: * The workspace uses **ACC sync** or **drag-and-drop uploads**. * Something downstream of Speckle depends on the old data format. * You cannot update that downstream tool before the workspace starts writing the new format. Do not request it only because connectors are still on an older release. Connector upgrades have their own window. See [Plan the connector upgrade window](/next/it-admin/connector-updates). ## As a workspace admin Identify whether any project uses ACC sync or drag-and-drop, and whether any script, custom report, or other tool reads that data in the old format. If it does, ask Speckle to switch the workspace into compatibility mode now. It is not self-serve, and it ends on **1 November 2026** regardless of when it was turned on. After Speckle confirms the workspace is in compatibility mode, ACC sync and drag-and-drop continue to write the old format until you ask to leave it, and no later than **1 November 2026**. On that date every workspace leaves compatibility mode, whether or not downstream tools are ready. Contact Speckle in-app, through [speckle.community/help](https://speckle.community/help), or via your Customer Success Advisor. ## As an IT administrator Compatibility mode does not change ACC hub enablement, firewall allowlists, or connector installers. Keep using the [IT Setup Guide](/it-admin/setup) for those tasks. Identify tools that read data from ACC sync and drag-and-drop uploads, and update them before **1 November 2026**. ## After 1 November 2026 Compatibility mode is switched off for every workspace on this date, and Speckle no longer offers it. New ACC sync and drag-and-drop uploads then use the new data format. Downstream tools that still expect the old format can break until they are updated. Existing models stay readable. Desktop connector publish and load are not turned off by this date. # Plan the connector upgrade window Source: https://docs.speckle.systems/next/it-admin/connector-updates Update connectors from 1 September 2026, and no later than 1 November 2026. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. 2026.9 gives IT teams a dated window to bring connectors current. Update from **1 September 2026**, and complete the estate no later than **1 November 2026**. For installation, baselines, host support, and the usual update cadence, see [Keep connectors current across your estate](/it-admin/connector-updates). This page covers only the dated window. This window is not a freeze of desktop connectors. Existing connectors keep working for publish and load. Compatibility mode is a separate, temporary option for ACC sync and drag-and-drop only. See [Compatibility mode for ACC sync and uploads](/next/it-admin/compatibility-mode). The Navisworks desktop connector is not in this window. **2026.8** is the last installer. There is no 2026.9 package to roll out. Keep a **200 MB** publish on 2026.8. Move larger NWC and NWD files to upload (up to **2 GB**) or ACC sync (tested to **6 GB**). A 2026.8 publish uses the current data model; server-side conversion to the 2026.9 format is not guaranteed. See [Navisworks in 2026.9](/next/connectors/navisworks/introduction). ## Why the dates exist The window opens on **1 September 2026**. Use it to roll updates as routine maintenance rather than a last-minute project. The backstop is **1 November 2026**, when compatibility mode for ACC sync and drag-and-drop ends. Updating in this period gets the performance improvements sooner. You can update earlier than **1 September 2026** if your change process allows it. Do not plan to still be rolling out after **1 November 2026**. ## How this differs from the current cadence The current IT guidance still applies: stay on the current release, and treat quarterly as the minimum cadence if you cannot approve every release. For 2026.9, **1 November 2026** is a hard backstop for this window, not a replacement for that standing process. After **1 November 2026**, return to the cadence in [Keep connectors current across your estate](/it-admin/connector-updates). ## As an IT administrator 1. Inventory connector versions across the estate. You should have a single target version before the pilot starts. 2. Pilot from **1 September 2026** with a small group covering your main host applications. Publish and load a representative model, including a large or federated one. 3. Roll forward together so teams do not sit on mixed versions through October. You should see one connector generation across the estate. 4. Finish by **1 November 2026**. Record the baseline so the next update starts from a known position. Use the deployment routes already documented: `.exe` for single-user installs, and ZIP for managed all-user installs. See [Move to a new baseline](/it-admin/connector-updates#move-to-a-new-baseline). ## As a self-hosted server admin Self-hosted servers are not required to adopt this data model on a fixed date. If your current connector and server versions work together, pin both, and keep downstream users on that same combination. See [Self-hosted servers](/developers/migration/data-model-migration#self-hosted-servers). ## FAQ No. Existing connectors keep working for publish and load. The date is the end of the upgrade window, and the end of compatibility mode for ACC sync and drag-and-drop. Plan to be current by then so you are not rolling out under time pressure. The deadline is **1 November 2026**. Starting from **1 September 2026** leaves time to pilot and roll forward together. Compressing the work into late October still meets the date, but it removes that buffer. Yes, as the standing process. This window is a dated exception for 2026.9. After **1 November 2026**, follow [Keep connectors current across your estate](/it-admin/connector-updates). No. There is no 2026.9 Navisworks installer. **2026.8** is the last package. Keep a 200 MB publish on 2026.8. Move larger files to NWC and NWD upload or ACC sync. See [Navisworks in 2026.9](/next/connectors/navisworks/introduction). Not as a fixed server-upgrade deadline. Pin the connector-and-server combination that already works, and keep downstream users on it. See [Self-hosted servers](/developers/migration/data-model-migration#self-hosted-servers). # IT administration for 2026.9 Source: https://docs.speckle.systems/next/it-admin/introduction Dated 2026.9 actions for IT and workspace admins. Coverage is incremental. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Use this section when you manage Speckle for an organisation. It covers the 2026.9 dates that differ from the current IT guides, the workspace-wide **AI features** switch, and workspace Settings and Usage for workspace admins. For firewall rules, SSO, connector installation, and cloud integrations, see the [IT Setup Guide](/it-admin/setup). 2026.9 does not change how you install connectors, configure SSO, or enable ACC and ProjectWise. Trimble Connect is new in 2026.9: a workspace admin connects a Trimble **service account** in the project sidebar — there is no separate ACC Hub-style enablement step. See [Sync models from Trimble Connect](/next/connectors/cloud-integrations/trimble-connect). Two dated actions do change: * **Compatibility mode ends on 1 November 2026.** If ACC sync or drag-and-drop uploads feed a downstream tool that still needs the old data format, request it now and update that tool before the end date. * Plan a **connector upgrade window** from **1 September 2026**, and complete it no later than **1 November 2026**. Those actions are not a freeze of desktop connectors. Publish and load continue. Compatibility mode applies only to ACC sync and drag-and-drop uploads. ## What to do | Date | What you do | Learn more | | - | - | - | | 1 September 2026 | Start rolling connector updates across the estate. | [Plan the connector upgrade window](/next/it-admin/connector-updates) | | Now | If ACC sync or drag-and-drop still needs the old format, ask Speckle to enable compatibility mode and start updating the downstream tool. | [Compatibility mode](/next/it-admin/compatibility-mode) | | 1 November 2026 | Compatibility mode ends for every workspace. Finish connector updates. | [Compare 2026.8 and 2026.9](/next/whats-new) | For the user-facing migration steps, see [Speckle's data model is changing](/workspaces/data-model-migration). ## Turn AI features off for the workspace Speckle Intelligence is available when the workspace plan includes it. A workspace admin can turn **AI features** off for the whole workspace from workspace **Settings**, then **General**. Only workspace admins can change this switch; members and guests can open the General page but cannot change it. When AI features are off, **Chat** and the sparkle control in the 3D viewer are unavailable to everyone in the workspace, so nobody can start a conversation or spend AI credit. Turn the switch back on the same way to restore access. The switch is a workspace setting, not a plan change. It applies to one workspace, so if your organisation runs several workspaces, turn AI features off in each one. To remove Speckle Intelligence from the plan itself, use **Settings**, then **Billing and plans**, or contact us. On Speckle Enterprise Server, Intelligence is also controlled by the licence. See [Enterprise license — Intelligence](/developers/server/deployment/enterprise-license#optional-intelligence). Setup, security, support mode, and cloud-integration pages are unchanged. Switch to **Current** in the version selector for those guides. As a workspace admin, use [Workspace settings in 2026.9](/next/workspaces/settings) for the live Settings map, and [Usage statistics in 2026.9](/next/workspaces/usage) for activity, plan limits, and AI spend. Organisation playbooks for Intelligence are [skills](/next/analytics/intelligence-skills). Standing constraints on every conversation are [AI Rules](/next/analytics/intelligence-rules) (admin-managed). # Enhanced roles and permissions Source: https://docs.speckle.systems/next/it-admin/roles-and-permissions Enhanced roles and permissions for 2026.9 are coming soon. Use the current roles documentation until then. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Enhanced roles and permissions for 2026.9 are coming soon. Until that documentation ships, workspace and project access still follow the current two-level model. This preview does not yet describe new role types or a new admin screen. Manage members and project collaborators the same way you do today. For the roles that apply now, see [Roles and Permissions](/workspaces/roles-and-seats). # 2026.9 Source: https://docs.speckle.systems/next/welcome 2026.9 documentation. Coverage is incremental and is not a copy of the guides under **Current** in the version selector. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. This is the 2026.9 documentation. It is not a parallel copy of the User Guides, Developers, or IT Administrators trees. Those pages live under **Current** in the version selector. Start there for [Welcome](/quickstart/welcome) and any topic that does not have a 2026.9 page yet. Start with [Compare 2026.8 and 2026.9](/next/whats-new) to see what changes for you. A missing page is expected. Switch to **Current** in the version selector for the complete guides. # Compare 2026.8 and 2026.9 Source: https://docs.speckle.systems/next/whats-new What changes for you in 2026.9, next to how Speckle works today. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Use this page to see what 2026.9 changes for you, next to how Speckle works today. For the current product, switch to **Current** in the version selector. If you only publish and load through Speckle connectors, your day-to-day work stays the same. The rows below are the exceptions and dates that matter. For the full steps, see [Speckle's data model is changing](/workspaces/data-model-migration). ## What's different | What you do | Before 2026.9 | In 2026.9 | Learn more | | - | - | - | - | | Publish, load, and view | You publish and load through connectors and the web app | You still do. After your project moves to the new data format, those flows are faster | [What to do next](/workspaces/data-model-migration) | | Models you already published | Your existing models stay readable | They stay readable. New publishes use the new format going forward | [What to do next](/workspaces/data-model-migration) | | ACC sync or drag-and-drop | Uploads use today's data format | Uploads move to the new format. If another tool still needs the old format, ask Speckle to turn on compatibility mode as a short bridge. It ends for every workspace on **1 November 2026** | [Who should pay closer attention](/workspaces/data-model-migration#who-should-pay-closer-attention) | | Connector updates | Your current connectors keep working | Update them from **1 September 2026**, and no later than **1 November 2026** | [What you should do now](/workspaces/data-model-migration#what-you-should-do-now) | | Speckle Intelligence | It looks at properties on each object | It can also see how parts of a model relate to each other — what connects to what, and what contains what | [What to do next](/workspaces/data-model-migration) | | Data Validation | Checks, plus project standards on Enterprise | Project standards are not in 2026.9. Author checks. A later rollup from Checks to workspace standards is planned | [Data Validation in 2026.9](/next/analytics/data-validation/overview) | | Open a model in the web app | Current viewer: section box, Selection info, Filters | New viewer: hybrid load, docked **Selection** / **Filters** / **Views**, section planes | [3D viewer in 2026.9](/next/3d-viewer/introduction) | | View point clouds | Point clouds render in the viewer | Not drawn in the new viewer yet. The data is unchanged and connectors that load it keep working. Support is planned for a later release | [3D viewer in 2026.9](/next/3d-viewer/introduction#open-a-model) | | View colours and materials | Colours and materials from the source application render in the viewer | Some objects show as grey in the new viewer: Grasshopper colours, Civil 3D surface materials, and models published before the move to 2026.9. The data is unchanged. Publishing again fixes only the last case | [3D viewer in 2026.9](/next/3d-viewer/introduction#open-a-model) | | Compare model versions | ··· **View changes** on a version opens a dedicated diff view | Deprecated — no diff view in the Models ··· menu. Ask Speckle Intelligence (Chat, the viewer sparkle, or a Report) to detect, report, and assess the impact of what changed | [Worked example](/next/workflows/assess-model-changes-with-intelligence) | | Navisworks models | Publish from the desktop connector | No 2026.9 desktop connector. **2026.8** is last, and still advised at **200 MB**. Larger NWC/NWD: upload to **2 GB**, ACC tested to **6 GB** | [Navisworks in 2026.9](/next/connectors/navisworks/introduction) | | Trimble Connect | Not available | New beta cloud sync on the Enterprise plan. Service account for background downloads; personal Trimble ID to browse | [Sync models from Trimble Connect](/next/connectors/cloud-integrations/trimble-connect) | This table is a summary. Follow the linked page for steps and dates. Connector-specific changes live under Publishing & Loading: [Revit in 2026.9](/next/connectors/revit/introduction), [Grasshopper in 2026.9](/next/connectors/grasshopper/introduction), [Power BI in 2026.9](/next/connectors/power-bi/introduction), [Navisworks in 2026.9](/next/connectors/navisworks/introduction), and [Trimble Connect](/next/connectors/cloud-integrations/trimble-connect). Viewer chrome, **Selection**, **Filters**, and **Views** are on [3D viewer in 2026.9](/next/3d-viewer/introduction). Until a 2026.9 page exists for another topic, use the guides under **Current** in the version selector. ## If you build on Speckle If you use SDKs, APIs, Automate, or a self-hosted server, see [Data model migration for developers](/developers/migration/data-model-migration). That page covers SDK updates, compatibility mode for uploads, and when to stay on 2026.8. Holding notes for the other developer tabs are under Developers in this preview. ## FAQ Most people who publish and load through Speckle connectors keep the same workflow. 2026.9 details for Revit, Grasshopper, Power BI, Navisworks, and Trimble Connect are under Publishing & Loading. Other design tools still use the connector guides under **Current** in the version selector. Use the guides under **Current** in the version selector. If there is no 2026.9 page for that topic yet, the feature is still documented there. It did not go away. No. Compatibility mode is only for ACC sync and drag-and-drop uploads when another tool still expects the old format. It ends on **1 November 2026**. See [Who should pay closer attention](/workspaces/data-model-migration#who-should-pay-closer-attention). # Assess model changes with Speckle Intelligence Source: https://docs.speckle.systems/next/workflows/assess-model-changes-with-intelligence A worked example — ask Chat what changed between two versions, read the report, then filter and colour the model by how significant each change is. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow linked Current documentation for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. The dedicated diff view is gone in 2026.9 — see [Compare Versions](/3d-viewer/compare-versions). In its place, Speckle Intelligence can detect what changed between two versions, explain it in plain language, and — because Chat can also drive the viewer — colour the model by how significant each change is. This page walks through one real conversation end to end, from the first question to a scene coloured by change severity, so you know what to expect and can reuse the pattern on your own models. Speckle Intelligence Chat is available when your workspace plan includes it. On a self-hosted server, it is available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Intelligence](/developers/server/deployment/enterprise-license#optional-intelligence). ## What this workflow does * **Detect** — find the two versions to compare and diff them, without you opening a versions panel or clicking a diff button. * **Report** — explain what changed in plain language: scale first, then the categories that carried the change. * **Assess impact** — score changed elements by how significant the change is, not just changed-or-not. * **Visualise** — colour the model by that score so the impact is visible, not just written down. ## Walkthrough In Chat or the viewer sparkle, ask a plain question — no version pickers, no diff button: > What is the most significant change between the last two versions of the model? Intelligence lists the model's version history, attaches the previous version alongside the one you have open, and runs a diff between them. You do not see those as separate steps; they happen as part of answering the question. The reply is a written summary, not a raw diff dump — scale first, then the categories that carried the change, in order of significance. On one structural model, the answer read: > The most significant change is a structural steel re-specification that swept through the > model. Scale: 6,598 elements modified, 119 added, 105 removed across 66 levels — only \~60% > of the model was left untouched. Structural Framing (3,873 modifications) shows beam > families replaced en masse, with cross-sections cleared and rebuilt and the material grade > upgraded (Steel 43-275 → Steel 345 MPa). Structural Columns (135) and Structural Connections > (376 modified, 61 added, 22 removed) shifted to match. Walls (1,753 modified) look like a > secondary effect of the structural resizing rather than an independent edit. Intelligence reads this from the live model — the same [connected, queryable data](/next/analytics/intelligence#how-it-works) Chat uses for any other question — not from a static export or a change log someone maintained by hand. Keep going the way you would with a colleague: > Filter to just those elements and colour them by how significant. You do not have to define "significant" or set a threshold. Intelligence scores each changed element by how many of its properties moved, buckets that into tiers, and applies a filter and colour-by in the viewer you are already looking at — the same [Filters panel](/next/3d-viewer/introduction#filter-and-color) documented for manual use. The reply names the tiers it chose and what landed in each one: > 🔴 Major (9+ params changed) — 1,757 elements, the deepest re-specs. 🟠 Moderate (5–8 params) > — 2,587 elements. 🟡 Minor (1–4 params) — 2,254 elements. 🟢 Added — 119 new elements. The scene is now filtered to only the changed elements, coloured by tier, so the heaviest re-specification is visually obvious without you building that filter by hand. From here you can ask to isolate one tier, break it down by level, or start a new question — the filter stays until you clear it or ask for something that replaces it. ## Turn this into a skill If your team asks this shape of question often — after every structural issue, before every coordination meeting — save the pattern instead of retyping it. [Save the chat as a skill](/next/analytics/intelligence-skills#save-a-chat-as-a-skill) once the conversation behaves the way you want, or write the significance tiers and vocabulary into a skill by hand so every comparison uses the same thresholds and the same added/omitted/revised language. See [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills). You can also save the conversation as a [Report](/next/analytics/reports) if you want a shareable artefact rather than a one-off chat — bind the two versions as source aliases and the comparison becomes something you or a teammate can reopen without re-asking Intelligence. ## FAQ No. Ask about "the last two versions", or name one if you want an older baseline — for example "compare this to the version from before the coordination meeting." Intelligence finds and attaches the versions it needs. Not fixed. In this example Intelligence scored elements by how many properties changed and split them into rough tiers. Ask it to explain its thresholds, or tell it to weight geometry changes over parameter-only changes, if you want a different definition of significant for your project. Yes. Like every other Intelligence query, comparing versions needs both versions in the new data format. Versions still in the old format cannot be queried. See [Speckle's data model is changing](/workspaces/data-model-migration). Yes — the questions on this page are plain language, not a script. Ask them in Chat or the viewer sparkle on any project with at least two versions in the new data format. ## See also * [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence) * [Create and share Intelligence Reports](/next/analytics/reports) * [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills) * [Compare Versions](/3d-viewer/compare-versions) — the deprecated Current-viewer diff view this replaces * [3D viewer in 2026.9](/next/3d-viewer/introduction) # Benchmark a project against your portfolio with Speckle Intelligence Source: https://docs.speckle.systems/next/workflows/benchmark-against-your-portfolio-with-intelligence Pin a library of past-project figures as Knowledge so Chat can tell you how the project you're looking at compares, instead of exporting each project by hand to compare them. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow linked Current documentation for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Chat answers questions about one project at a time — see [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence#where-to-ask). It is not a portal onto every project in the workspace. So "how does this compare to our past work" is not something Chat can answer from the live model alone — it needs a benchmark to compare against. This page pins that benchmark as Knowledge so the comparison happens inside the conversation you're already having, instead of a separate export-and-compare step. Speckle Intelligence Chat is available when your workspace plan includes it. On a self-hosted server, it is available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Intelligence](/developers/server/deployment/enterprise-license#optional-intelligence). This pins a static benchmark library for comparison inside Chat. To watch several **live** projects side by side in one view instead — combined totals or a difference view, updating as those projects change — use [Perform portfolio analysis](/analytics/dashboards/common-workflows#perform-portfolio-analysis) in Dashboards. ## What this workflow does * **Maintain a benchmark library** — a spreadsheet or warehouse table of figures from past projects (steel tonnage, embodied carbon, cost per m², whatever your team tracks). * **Ask in project scope** — Chat reads the project you have open plus the pinned library, and compares the two. * **Flag outliers** — ask for what's unusual, not just the raw comparison. * **Keep the library current** — point Chat at a live warehouse table instead of a static file if the benchmark should update as finance or a data team refreshes it. ## Walkthrough Export or maintain a table of the metric you want to benchmark — one row per past project, with the figure your team already tracks (steel tonnage, embodied carbon per m², cost per unit). A spreadsheet is fine to start; a Databricks, Snowflake, or Microsoft Fabric table keeps it current without re-uploading. Create a skill and pin the library as [Knowledge](/next/analytics/intelligence-skills#what-you-can-attach). Tell the skill, in your own language, which column is which project and which is the metric, and how you want the comparison framed — a ratio, a percentile, or a plain "higher/lower than average". See [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills). Open the project you want to check, arm the skill, and ask: > How does this project compare to our past hospital projects on steel tonnage? Intelligence reads the current project's data plus the pinned library and answers within that one conversation — you don't export either side by hand. Keep going: > Is that difference something worth flagging? Because the comparison basis is the library you pinned — not a guess — Intelligence can say where this project sits against it, and say so in the vocabulary your skill defined. ## When you need several live projects in one view A pinned library is a snapshot — accurate as of when you last updated it. If you want combined totals or a difference view across several **live** projects that stays current as those projects change, that is a Dashboards job: [Perform portfolio analysis](/analytics/dashboards/common-workflows#perform-portfolio-analysis) adds a Model Viewer per project and uses **Aggregate** or **Compare** mode across them. ## FAQ Not in one conversation — Chat answers about the project you have open, not several projects at once. Pin a benchmark library so the comparison basis travels with the skill, or use [Perform portfolio analysis](/analytics/dashboards/common-workflows#perform-portfolio-analysis) in Dashboards when you want several live projects in one view instead. As fresh as you keep it. A static spreadsheet is a snapshot as of upload. Point the skill's Knowledge at a live warehouse table instead if the benchmark should update automatically. The current project does. Comparing versions or reading model relationships needs the new data format. See [Speckle's data model is changing](/workspaces/data-model-migration). Save the conversation as a [Report](/next/analytics/reports) and share it — viewing a saved report does not need the viewer to run their own Chat turn. ## See also * [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence) * [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills) * [Create and share Intelligence Reports](/next/analytics/reports) * [Perform portfolio analysis](/analytics/dashboards/common-workflows#perform-portfolio-analysis) — the live, multi-project dashboard route # Workflows in 2026.9 Source: https://docs.speckle.systems/next/workflows/overview Which workflow guides still apply in 2026.9, and which 2026.9 pages replace changed steps. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Use this hub to pick a workflow guide from the set under **Current** in the version selector and the 2026.9 pages that change how that outcome looks. It does not clone those tutorials. For that set, see [Workflows](/workflows/overview). ## What still applies These guides still describe the outcome. Use them for the repeatable pattern. Switch to the 2026.9 pages below when a step hits the new viewer, Intelligence, or a dump-host connector. * [Design review](/workflows/design-review-workflow) — saved views, federation, markups, and issues. In 2026.9 the viewer chrome is different: see [3D viewer in 2026.9](/next/3d-viewer/introduction). * [Model validation](/workflows/model-validation-workflow) — rules and dashboards. Workspace **Intelligence** still opens dashboards. Chat is a separate surface: see [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). * [Grasshopper componentised pipeline](/workflows/grasshopper-componentised-workflow) — modules that hand off data through Speckle models. Node names, Explore, and script upgrades are on [Grasshopper in 2026.9](/next/connectors/grasshopper/introduction) and [Upgrade Grasshopper to 2026.9](/next/connectors/grasshopper/upgrading). * [Revit room data extraction](/workflows/revit-room-data-extraction-specklepy) — pull room data with SpecklePy. Revit placement and Apply Transform are on [Revit in 2026.9](/next/connectors/revit/introduction). * [SpecklePy model analytics](/workflows/specklepy-model-data-analytics) — load published data into DuckDB. Publish and load still follow the connector guides under **Current** unless your host has a 2026.9 page. See [Connectors in 2026.9](/next/connectors/overview). * [Grasshopper design explorer](/workflows/grasshopper-design-explorer) — compare alternatives from Grasshopper. Do not treat that page as a 2026.9 rewrite. Explore and related connector changes live under [Grasshopper in 2026.9](/next/connectors/grasshopper/introduction). Mapping Speckle data to native families and types is still coming soon in those guides. 2026.9 does not add that tutorial. ## New in 2026.9 Worked examples with no Current equivalent — each shows a real pattern end to end rather than just listing what's possible: * [Assess model changes with Speckle Intelligence](/next/workflows/assess-model-changes-with-intelligence) — ask Chat what changed between two versions, then filter and colour the model by how significant each change is. * [Take off quantities and cost with Speckle Intelligence](/next/workflows/take-off-quantities-with-intelligence) — ask Chat for a priced takeoff against your own pinned rate card. * [Benchmark a project against your portfolio with Speckle Intelligence](/next/workflows/benchmark-against-your-portfolio-with-intelligence) — pin a benchmark library as Knowledge so Chat can compare the open project against your past work. * [Validate incoming models automatically](/next/workflows/validate-incoming-models-automatically) — set a Validation Check to auto trigger so every new version is checked against your standard without anyone starting it by hand. ## What 2026.9 changes in those outcomes * **Viewing** — hybrid load, docked **Selection** / **Filters** / **Views**, and section planes. See [3D viewer in 2026.9](/next/3d-viewer/introduction). * **Intelligence** — Chat in the project sidebar and the viewer sparkle. Workspace **Intelligence** is still dashboards. See [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). * **Connectors** — Revit Apply Transform, Grasshopper Explore, and Power BI Get Tables. See [Connectors in 2026.9](/next/connectors/overview), [Revit in 2026.9](/next/connectors/revit/introduction), [Grasshopper in 2026.9](/next/connectors/grasshopper/introduction), and [Power BI in 2026.9](/next/connectors/power-bi/introduction). Until a 2026.9 page exists for another step, use the workflow guide under **Current** in the version selector. ## FAQ 2026.9 docs stay sparse. A missing page means use the guide under **Current**, not that the workflow went away. This hub exists so you can find both. Yes. The outcome is the same. The 3D viewer chrome around those tools changed. Follow [Design review](/workflows/design-review-workflow) for the pattern and [3D viewer in 2026.9](/next/3d-viewer/introduction) for the new panels. That guide still describes the dashboard pattern. Connector steps that changed in 2026.9 are on [Grasshopper in 2026.9](/next/connectors/grasshopper/introduction), not as a second tutorial here. # Take off quantities and cost with Speckle Intelligence Source: https://docs.speckle.systems/next/workflows/take-off-quantities-with-intelligence Ask Chat for a quantity takeoff and a priced estimate straight from the model, using your own rate card, instead of building a takeoff dashboard by hand. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow linked Current documentation for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. A quantity takeoff and a priced estimate are usually two separate jobs: count elements in a dashboard or export, then take that export somewhere else to apply rates. This page asks for both in one conversation — a takeoff by category, priced against your own rate card, with anything it can't price flagged instead of guessed. Speckle Intelligence Chat is available when your workspace plan includes it. On a self-hosted server, it is available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Intelligence](/developers/server/deployment/enterprise-license#optional-intelligence). This is the Chat-driven route. For a dashboard you can pin, share, and keep open on a screen instead of asking for it each time, build a [quantity takeoff dashboard](/analytics/dashboards/common-workflows#run-a-quantity-takeoff) instead — the two approaches read the same published data. ## What this workflow does * **Take off** — count and total elements by category, level, or any other property, without building the breakdown in a dashboard first. * **Price** — apply your own unit rates and cost codes instead of a generic estimate. * **Flag gaps** — call out anything with no matching rate, rather than inventing a number. * **Reuse** — pin the rate card once so every future takeoff on any project uses this year's prices. ## Walkthrough In workspace **Settings → Skills**, create a skill and pin your rate card (a spreadsheet, or a live warehouse table if finance keeps it there) as [Knowledge](/next/analytics/intelligence-skills#what-you-can-attach). Write the unit rates and cost codes into the skill's instructions in your own language — elemental, package, or whatever your commercial team already calls them. See [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills). In Chat, arm the skill with `/skill-name` and ask in plain language: > Give me a material takeoff, priced against our rate card. Intelligence reads quantities from the published model — the same [connected, queryable data](/next/analytics/intelligence#how-it-works) it uses for any other question — and matches each line against the pinned rate card. The reply groups quantities the way your skill's instructions say to — by category, level, or package — with each line priced. Anything without a matching rate is called out separately instead of estimated, so a missing row is visible rather than silently averaged away. Keep going in the same conversation: > What's the impact on cost if steel goes up by 15%? Intelligence recalculates from the same quantities and the same pinned rates, so the answer reflects your actual take-off, not a generic assumption. ## Share it beyond the chat Save the conversation as a [Report](/next/analytics/reports) if you want a shareable artefact — the takeoff and its pricing stay live against the bound version rather than frozen at the moment you asked. For a takeoff someone will keep open and re-filter by level or category on a screen, use the dashboard route in [Run a quantity takeoff](/analytics/dashboards/common-workflows#run-a-quantity-takeoff) instead; **Element table** there also exports straight to CSV. ## FAQ Only if you say so. Put your unit and rounding conventions in the skill's instructions — Intelligence does not know your commercial team's conventions unless you tell it once, in the skill. It gets flagged as unmatched rather than priced by guesswork. Write that behaviour into the skill explicitly (see the [cost, carbon, and quantities skill catalogue](/next/analytics/intelligence-skills#cost-carbon-and-quantities)) if you want the flag to use a specific phrase your commercial team recognises. Yes. Like every other Intelligence query, a takeoff needs a version in the new data format. Versions still in the old format cannot be queried. See [Speckle's data model is changing](/workspaces/data-model-migration). Yes — just ask for the takeoff without pricing, for example "give me a material takeoff" or "give me a report of quantities by category and level." Pricing only kicks in once you've pinned a rate card in a skill. ## See also * [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence) * [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills) * [Create and share Intelligence Reports](/next/analytics/reports) * [Run a quantity takeoff](/analytics/dashboards/common-workflows#run-a-quantity-takeoff) — the dashboard-based route # Validate incoming models automatically Source: https://docs.speckle.systems/next/workflows/validate-incoming-models-automatically Author a check once and set it to run on every new version, so a consultant, subcontractor, or federated model is validated against your standard at each submission without anyone remembering to run it. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow linked Current documentation for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Checking every incoming model by hand against your own standard doesn't scale — someone has to remember to run it, on every submission, on every model. A **Validation Check** with **auto** trigger removes the remembering: author the rule once, and it runs itself against every new version of the tracked model. This page covers that specific pattern — a standard applied at every submission milestone, not a one-off spot check. This is a rules-based check, not a Chat conversation — Data Validation runs the same `WHERE` / `CHECK` predicates every time rather than reasoning about a question. For plain-language questions about a model, use [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence) instead. ## What this workflow does * **Encode the standard once** — required parameters, naming pattern, or a value that must match a related object, as `WHERE` / `CHECK` rules. * **Run it without anyone asking** — **auto** trigger fires the check against tracked models when a new version lands, so validation happens at the moment of submission, not whenever someone remembers. * **Score the submission** — a pass rate against your threshold, not just a pass/fail per object. * **Keep a history** — every run is recorded, so you can see whether a consultant's compliance is improving or not across a project. ## Walkthrough Open **Run check** in the project sidebar and draft your rules — for example, every element from the incoming discipline must carry a required parameter, follow a naming pattern, or match a value on a related host object. See [Checks](/analytics/data-validation/checks) for rule structure, predicates, and how to check an object against something it's related to. Run **Preview** against the model you're building the check for. Tighten `WHERE` first if the scope is too broad — a check that's too loose floods the result with noise nobody will read. Save the check with **auto** trigger, and set your pass (and optional warn) threshold. From this point, every new version of the tracked model runs this check without anyone starting it manually. Each new version's result appears in **Checks** with its pass rate. A consultant's or subcontractor's model is validated against your standard the moment it's published — not at whatever point someone gets around to checking it. ## Reuse the standard elsewhere A saved check is tied to its tracked models. If the same standard applies on other projects, recreate it there rather than expecting it to follow a model automatically — 2026.9 does not yet have a rollup from one project's checks into a workspace-wide standard; see [Project standards](/next/analytics/data-validation/overview#project-standards) for where that's headed. ## FAQ No — after saving, only the check's name and description are editable. Tracked models, rules, predicates, and trigger mode stay frozen. Create a new check for different behaviour. See [Checks](/analytics/data-validation/checks). Data Validation preview and saved-check runs need a version in the 2026.9 data format. If a submission is still on the old format, ask the consultant or subcontractor to publish with a current connector. See [Speckle's data model is changing](/workspaces/data-model-migration). Yes, on a version in the 2026.9 data format — add a related object to the rule and pick the relationship (host element, room, connected element, and others). See [Checks against related objects](/next/analytics/data-validation/overview#checks-against-related-objects). The result appears in **Checks** with its pass rate; this page does not cover a separate notification channel. Build a **Model Validation** or **Property checker** widget into a dashboard if you want the pass/fail state visible somewhere your team already looks — see [Run a quick validation check](/analytics/dashboards/common-workflows#run-a-quick-validation-check). No. A skill is an opt-in playbook someone arms with `/skill-name` in a conversation. A Validation Check with auto trigger runs on its own schedule (every new version) independent of Chat. They can complement each other — for example, ask Chat to summarise a check's recent failures in plain language — but the check itself is authored and run through Data Validation. ## See also * [Checks](/analytics/data-validation/checks) * [Data Validation in 2026.9](/next/analytics/data-validation/overview) * [Viewing Results](/analytics/data-validation/viewing-results) * [Run a quick validation check](/analytics/dashboards/common-workflows#run-a-quick-validation-check) — the dashboard-widget route for a spot check rather than a standing gate # Workspaces in 2026.9 Source: https://docs.speckle.systems/next/workspaces/introduction Workspace sidebar in 2026.9 — Home, Projects, Intelligence, gated Documents, Team, and Settings. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. The workspace sidebar in 2026.9 lists the live areas of the web app. Workspace cards from before 2026.9 show Home, Projects, Intelligence, Team, and Settings only. This page is the map for what you actually see. For how workspaces work today, see [Workspaces](/workspaces/introduction). Workspaces are available on Speckle Cloud and on Speckle Enterprise Server. For self-hosted setup, see [Enterprise license](/developers/server/deployment/enterprise-license#enable-workspaces). ## Find your way around The left sidebar is the same on Home and on other workspace pages: * **Home** — recent activity and a summary of the workspace. * **Projects** — the projects in this workspace. See [Projects](/workspaces/projects). * **Intelligence** — workspace dashboards. This is not Chat. Chat lives in the project sidebar, next to **Browse**. See [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence) and [Intelligence Dashboards](/analytics/intelligence-dashboards). * **Documents** — the workspace file library. This item appears only when the workspace includes Speckle Intelligence Chat and the documents library is enabled. * **Team** — members, invites, and seats. See [Inviting](/workspaces/inviting) and [Roles and permissions](/workspaces/roles-and-seats). * **Settings** — workspace-wide controls. The settings map and Usage how-to live under IT Administrators: [Workspace settings in 2026.9](/next/workspaces/settings) and [Usage statistics in 2026.9](/next/workspaces/usage). **Documents** is gated. If you do not see it, the workspace does not have that library yet. It is not missing from the product. ## Open user settings Your account is no longer behind a top-right avatar. Open the **workspace switcher**: the workspace name at the top of the left sidebar. In that menu, select **your name** (the row with your avatar). That row opens **User settings** on **Profile**. It is a link, not a signed-in label. There is no separate Profile or Settings item in this menu. User settings then lists **Profile**, **Notifications**, **Developer** (access tokens and apps), and **Emails**. The same workspace-switcher menu also has **Theme**, **Copy support reference**, and **Log out**. Server administrators also see **Server settings**. Clicking your name is how you open profile settings. Treat it as the call to action, not as a label that only shows who is logged in. ## What has no 2026.9 page Projects, models, versions, roles, and inviting still use the guides under **Current** in the version selector. This page does not clone them. ## FAQ Workspace **Intelligence** opens dashboards. Chat is in the project sidebar, next to **Browse**. The sparkle in the 3D viewer is a third entry point for questions about loaded models. See [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). **Documents** appears only when the workspace includes Speckle Intelligence Chat and the documents library is enabled. Other sidebar items stay. Ask a workspace admin if you expected to see it. Open workspace **Settings** in the left sidebar. The children and who can change them are on [Workspace settings in 2026.9](/next/workspaces/settings) (IT Administrators). Depth that is still accurate lives on [Configuration](/workspaces/configuration). They moved into the workspace switcher. Open the workspace name at the top of the left sidebar, then select your name. That opens User settings. See [Open user settings](#open-user-settings). # Workspace settings in 2026.9 Source: https://docs.speckle.systems/next/workspaces/settings Map of workspace Settings in 2026.9, including who can see each item. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Open workspace **Settings** when a change should apply to the whole workspace. This page is the live map for workspace admins. [Configuration](/workspaces/configuration) still covers SSO, SCIM, billing, and roles in depth. This page does not clone those guides. Workspace members can open most settings pages. Only workspace admins can change workspace-level controls. Some items appear only when the plan includes them. Workspaces are available on Speckle Cloud and on Speckle Enterprise Server. For self-hosted setup, see [Enterprise license](/developers/server/deployment/enterprise-license#enable-workspaces). ## Open Settings Sign in and open the workspace. The left sidebar shows Home, Projects, Intelligence, Team, and Settings. You should see **Settings** at the bottom of that list. Select **Settings**. The sidebar expands to the children below. You should see **General** first. ## Settings map Items appear in this order. Hidden items are gated by plan or permission, not missing from the product. * **General** — name, short ID, description, logo, and the **AI features** switch. Everyone who can open Settings sees this page. Only admins can save changes or turn AI features off. See [Turn AI features off for the workspace](/next/it-admin/introduction#turn-ai-features-off-for-the-workspace). * **Usage** — activity, plan limits, and AI spend. Workspace admins see this item when the plan includes usage analytics. See [Usage statistics in 2026.9](/next/workspaces/usage). * **Project metadata** — fields every project in the workspace can fill out. Workspace admins see this item when the plan includes project metadata. See [Projects — metadata](/workspaces/projects#metadata). * **Project labels** — labels used to organise projects. See [Projects — project labels](/workspaces/projects#project-labels). * **Issue labels** — labels used on project issues. See [Issues — labels](/3d-viewer/issues#labels). * **Tokens** — workspace share tokens for read-only access to models, presentations, or dashboards. You can revoke one token or **Revoke all**. * **Security** — discoverability, domain protection, SSO, and related identity controls. See [Workspace discoverability](/workspaces/workspace-discoverability), [Domain protection](/workspaces/domain-protection), [SSO](/workspaces/sso), and [SCIM](/workspaces/scim). * **Billing and plans** — plan, payment, and Customer Portal. See [Billing](/workspaces/billing). * **Data residency** — where workspace data is stored. See [Data residency](/workspaces/data-residency). * **Automation** — functions available to projects in this workspace, including **Regenerate token...**. Speckle Automate is available only on Speckle Enterprise Server. For setup, see [Enterprise license — Automate](/developers/server/deployment/enterprise-license#optional-automate). Where Automate lives in the 2026.9 web app is on [Automate in 2026.9](/next/developers/automate/introduction). * **Support** — support sessions. This item appears when Admin Support Mode is enabled. See [Admin Support Mode](/it-admin/support-mode). On self-hosted servers, that feature is available only on Speckle Enterprise Server. For setup, see [Enterprise license — Admin Support Mode](/developers/server/deployment/enterprise-license#optional-admin-support-mode). * **Skills** — reusable playbooks for Speckle Intelligence Chat. Members see this item when the plan includes Chat. Create skills here (including **Draft with AI**), then invoke them in Chat with `/skill-name`. See [Reuse organisation playbooks with Intelligence skills](/next/analytics/intelligence-skills). * **AI Rules** — standing instructions Speckle Intelligence follows in every conversation. Members can open this item; only workspace admins can change rules. See [Set standing AI Rules for the workspace](/next/analytics/intelligence-rules). ## Project settings stay on the project Workspace Settings do not replace project settings. Open a project, then **Settings**, for that project's **General**, **Webhooks**, **Tokens**, and **Automations**. [Configuration](/workspaces/configuration) still describes project visibility, collaborators, and share tokens. ## FAQ Those items are gated. **Usage** is for workspace admins on a plan that includes usage analytics. **Skills** appears when the workspace includes Speckle Intelligence Chat. **Automation** appears when Automate is available. The rest of Settings still opens. Workspace admins can change workspace-level settings. Members can view most pages but cannot apply those changes. See [Roles and permissions](/workspaces/roles-and-seats). Open **Settings**, then **General**, and turn **AI features** off. Only workspace admins can change it, and it applies to everyone in the workspace. See [Turn AI features off for the workspace](/next/it-admin/introduction#turn-ai-features-off-for-the-workspace). Open **Settings**, then **Security**. The existing guides still apply: [SSO](/workspaces/sso) and [SCIM](/workspaces/scim). # Usage statistics in 2026.9 Source: https://docs.speckle.systems/next/workspaces/usage Workspace Settings → Usage in 2026.9 — activity, plan limits, and AI spend. Documentation set: Speckle 2026.9. Status: current. Authority: canonical for this version and the coverage on this page. Applies to version 2026.9, from 2026-09; this is not a rollout date for every deployment. Authoritative Speckle 2026.9 documentation for the topic covered here. For Speckle 2026.9, prefer this page over conflicting earlier guidance. Follow the linked pages in the other documentation version for unchanged topics and where this page says coverage is not yet available. Respect data-format, deployment, plan, permission, and compatibility limitations stated in the page. This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to **Current** (2026.8 and earlier) in the version selector. Workspace **Settings → Usage** shows activity, plan limits, and AI spend for this workspace. Use this page as a workspace admin. The guides under **Current** in the version selector have no equivalent page. The closest are [Configuration](/workspaces/configuration) and [Billing](/workspaces/billing). If **Usage** is missing from Settings, you do not have that permission or the plan does not include it. The Settings map is on [Workspace settings in 2026.9](/next/workspaces/settings). ## Open Usage Sign in, open the workspace, then select **Settings**. You should see **General** at the top of the Settings list. Select **Usage**. The heading is **Usage**. The subtitle is "Activity, plan limits and AI spend for this workspace." You should see a filter bar and section tabs. ## Filter and export The filter bar applies to the activity sections, not to **Limits**. * Range: **Last 7 days**, **Last 30 days**, **Last 90 days**, or **Last 12 months**. * **Projects**, project labels, and **Member** narrow the scope. **Clear** removes that scope. * Charts and tables include **Download CSV** when there are rows to export. **Limits** is workspace-wide. Changing the filters does not change that tab. ## Sections * **Projects** — which projects see the most activity, and how many are active month to month. * **Users** — the most active people, and how many are active month to month. * **Integrations** — where versions come from, and which ACC and ProjectWise files are wired to auto-refresh. * **Dashboards & Reports** — which projects every dashboard and report is attached to, and who owns it. * **AI** — token spend by user, project, purpose, and tool. This tab appears when the workspace includes Speckle Intelligence Chat. Under a project scope, workspace-level chats drop out. * **Limits** — what the plan includes and how much of it is used. **Manage plan** opens **Billing and plans**. See [Billing](/workspaces/billing). Empty activity sections show "No usage data available" until people start working in the workspace. If a load fails, the page shows "Couldn't load usage data" and **Try again**. Speckle Intelligence Chat is available when your workspace plan includes it. On a self-hosted server, it is available only on Speckle Enterprise Server. For deployment setup, see [Enterprise license — Intelligence](/developers/server/deployment/enterprise-license#optional-intelligence). ## FAQ **Limits** is workspace-wide. The filters apply to Projects, Users, Integrations, Dashboards & Reports, and AI. Use **Manage plan** on the Limits tab to open **Billing and plans**. **AI** appears when the workspace includes Speckle Intelligence Chat. The other tabs stay. Chat itself is documented on [Ask questions about your models with Speckle Intelligence](/next/analytics/intelligence). No. Before 2026.9, the guides cover billing and configuration, not this analytics surface. Use [Configuration](/workspaces/configuration) and [Billing](/workspaces/billing) for those topics, and this page for Usage.