get_scene | Return the full scene graph. | — | { nodes, rootNodeIds, collections } |
get_node | Fetch a node by id, whole, with the scene materials its finishes use. | { id } | { node, materials? }, or refusal node_not_found |
describe_node | Node summary with ancestry, children count and properties. | { id } | { id, type, parentId, ancestry[], childrenCount, properties, description } |
find_nodes | Filter nodes by type (any node kind) / parent / zone / level, or by import source id (provenance.refs[].id or legacy metadata.sourceIds, exact or prefix). | { type?, parentId?, zoneId?, levelId?, sourceId?, sourceIdPrefix? } | { nodes: AnyNode[] } |
list_levels | List every building's levels in floor order with their role (storey, roof-only, support). | — | { activeSceneId, activeLevelId, levelCount, occupiedStoryCount, supportLevelCount, roofLevelIds, levels[] } |
get_level_summary | Compact summary of one level: role, counts, walls with openings, zones with areas, slabs, ceilings, items, stairs, roofs, and everything else by type. Omit levelId for the lowest storey. | { levelId?, level? } | { levelId, role, counts, walls, zones, slabs, ceilings, items, stairs, roofs, other } |
get_walls | Walls on a level with length, stored and resolved height, and child doors/windows. | { levelId?, level? } | { levelId, walls[] } |
get_zones | Room/zone polygons with holes, areas (holes taken out), bounds and floor choices. | { levelId?, level? } | { levelId, zones[] } |
measure | Distance between two nodes' world-space reference points (hosted doors, windows and items resolved through their host; every node kind); area when applicable. | { fromId, toId } | { distanceMeters, fromPoint?, toPoint?, areaSqMeters?, units: 'meters' } |
view_scene | Look at the building from a viewpoint the agent picks (a side, a street-height eye, a photo's camera, square-on, from above) and get the picture back, with the photo's crop beside it when a region is given. interior: { levelId } looks inside one floor: the other floors and its roofs and ceilings left out, everything on it (walls, openings, furniture) cut at 0.65 of the storey's height, for the picture only. The server has no renderer: the host's sceneViews renders it (the hosted app, through the user's open editor tab). Read-only. | { target?, interior?, from?, elevation?, eyeHeight?, position?, fov?, projection?, camera?, photo? } | image content plus { status, camera, size, tab, capturedAt }; refusals view_unavailable, no_project, photo_crop_unavailable, interior_level_invalid, interior_hidden, interior_transform_unsupported, interior_target_elsewhere; on the hosted server editor_tab_required, editor_tab_hidden |
search_assets | Search the host's item library (the built-in list on a standalone server), several queries in one call; a query matches name, id, category or tags. A query that finds nothing gets a hint to build the item with add_object. | { queries: [{ query, category? }] } | { groups: [{ query, total, results[] }], total, hint? }; refusal no_catalog |
search_materials | Search the material library by words, several queries in one call: building words as the library writes them (timber is wood, render is stucco), shades and surfaces. Read-only. | { queries: [{ query, surface? }] } | { groups: [{ query, results: [{ ref, label, kind, surfaces, color? }], missing? }] } |
paint | Give walls, columns, slabs, ceilings, fences, doors, windows or roofs a finish in one call, as the editor's Paint does: a colour (the nearest library colour), a library: or scene: ref, a native material kept as a scene material (reused when an equal one exists), or erase. role picks the surface (a wall's exterior/interior face, a slot, a roof's top/edge/wall); a wall face is painted whole, over its room's wall finish, its painted parts keeping theirs (named in note). | { targets[], role?, color?, material?, materialName?, erase? } (one finish) | { ok, painted[], finish, materialId?, material?, createdMaterial?, note?, achieved }; refusals target_not_found, unknown_role, unknown_material, materials_unavailable, shadowed_field, not_paintable |
create_story_shell | Create one level-owned story shell from a footprint: the perimeter walls. The floor plate and ceiling are derived from the enclosed rooms; createSlab / createCeiling / slabElevation are recorded as room intent. Use once per story. | { levelId, footprint, wallHeight?, wallThickness?, createSlab?, createCeiling? } | { wallIds, zoneIds, slabId, ceilingId, createdIds } |
create_stair | Create a straight stair as the editor's stair tool does: from a level to the next one above (made when there is none), owning the floor openings it cuts. (x, z) is the back-centre of the bottom step, rotation in degrees (0 climbs toward +Z). | { x, z, levelId?, toLevelId?, rotation?, width?, length?, height?, steps? } | { stairId, segmentId, upperLevelId, createdUpperLevel, stepCount, slabHoleCut, openingIds? }; refusals roof_level, not_above, level_not_found, slab_not_found / ceiling_not_found, slab_not_on_level / ceiling_not_on_level |
measure_stair | Read actual risers, going at the walking line, slope, uniformity, arrival, headroom against floors/ceilings/stair bodies, and design-target diagnostics. | { stairId, available?: { width, length } } | { measurements, layouts } |
fit_stair | Fit uniform risers or replace the chain with a straight/L/U preset with width-sized landings or quarter-turn winders in one undoable edit. | { stairId, fitRun?, targets?, layout?, turn?, width?, landingDepth?, turningStrategy?, innerGap?, walkingLineOffset?, division? } | { stairId, measurements } |
create_roof | Create a roof container and one roof segment. By default creates a dedicated roof level above the reference occupied level for solo/exploded views. | { levelId, width, depth, roofType?, roofHeight?, roofLevelId?, useDedicatedRoofLevel? } | { roofLevelId, createdRoofLevelId, roofId, roofSegmentId } |
create_room | Create a room from a polygon: one wall per edge (an edge a wall already runs along reuses it) and the room zone; its doors and windows can be declared in the same call by edge (wallIndex) and t, each placed with add_door's and add_window's rules or listed in skippedOpenings. The floor plate and ceiling are derived, never authored. outdoor: true makes a terrace: separators (the editor's Separator: a room boundary with no wall) where no wall runs, no walls of its own, no ceiling. | { name, polygon, levelId?, color?, wallHeight?, wallThickness?, outdoor?, doors?, windows? } | { zoneId, slabId, ceilingId, wallIds, reusedWalls, areaSqMeters, doorIds, windowIds, skippedOpenings? }; refusals cannot_enclose, outdoor_room_overlap |
add_door | Add a door to a straight wall at t (0..1 along it) with the editor's placement rules, or a passage with no leaf (openingKind: "opening"); it slides to stay on the wall and reports clamped. doorType, style and the outline (openingShape) match a reference, code builds what they cannot, and nodeId rebuilds a scripted door. | { wallId, t?, width?, height?, openingKind?, hingesSide?, swingDirection?, doorType?, style?, openingShape?, code?, nodeId?, force? } | { doorId, wallId, localX, t, clamped, achieved }; refusals wall_not_found, not_a_wall, curved_wall, wall_too_short, opening_overlap (unless force) |
add_window | Add a window as add_door places a door, with its sill height; windowType, columns / rows, style (a Fixed window's panes; refused on another type, style_needs_fixed_window) and the outline match a reference. | { wallId, t?, width?, height?, sillHeight?, windowType?, columns?, rows?, style?, openingShape?, code?, nodeId?, force? } | { windowId, wallId, localX, t, clamped, sillHeight, achieved }; the same refusals as add_door |
furnish_room | Furnish a room for its type from the host's item catalog: the main piece against the wall facing the door, the rest along a side wall. Nothing lands in a door's clear zone or on another item: a piece that does not fit is nudged, else skipped, and skipped says why. | { zoneId?, polygon?, levelId?, roomType, doorWallIndex? } | { placed, itemIds, skipped, doorWallIndex, doorsDetected }; refusals room_required, roof_level, level_not_found, no_catalog |
apply_patch | Batched create/update/delete/move, validated and dry-run before commit. Batch-first is the default: send all create/update/delete ops for a build step in one atomic call (stable order, later ops may reference earlier created ids); do not loop one-op calls. A create with an id already in the scene is refused (node_exists); delete it earlier in the same patch to replace it. Updates cannot change id or type (identity_change), object or children (immutable_field), move a node under a missing or childless parent (invalid_parent), or add schema issues (invalid_update); default gutters and downspouts a delete regenerates are addressable only in a later call (regenerated_default). Refusals are tool errors with JSON text { code, patchIndex, id, message }. | { patches: Patch[] } | { applied: number } |
add_level | Add an empty level to a building, as the editor does: above the highest, or below the lowest for a basement. Omit buildingId for the scene's only building. | { buildingId?, position?, name?, height? } | { levelId, buildingId, floorIndex, height }; refusals building_required, building_not_found, no_building |
add_wall | Add a wall to a level, straight or, with curveOffset, an arc. Omit levelId for the lowest storey. | { start, end, levelId?, thickness?, height?, curveOffset? } | { wallId, levelId, length }; refusals roof_level, wall_too_short, level_not_found |
place_items | Place catalog items in one call, each placed or refused on its own, at level (x, z): on the level's floor, or on the host each names (targetNodeId): a wall (y, the height of its bottom, required), a ceiling, or an item standing on the floor. A floor item in a door's clearance is refused blocks_door (naming the door and a spot that clears every door), one its room cannot hold in any turn too_large_for_room. | { items: [{ assetId, x, z, y?, targetNodeId?, rotation? }], levelId? } | { levelId, items: [{ ok, itemId?, hostId?, restingOn?, code? }] }; per-item refusals asset_not_found, outside_rooms, blocks_door, too_large_for_room, height_required, item_too_tall, unsupported_host, host_not_found, host_not_on_level |
place_design | Create one design (procedural item recipe, object or JSON string) that passes validate_design. Its mounting picks the host: level/slab/zone or a design surface (surfaceId), a straight wall face, or a ceiling. Create-only, one undo step, inline designs up to 24 KiB, with coded refusals. | { design, hostId, position, rotation?, side?, surfaceId?, parameters?, slots?, name?, id? } | { designId, parentId, surfaceId } |
set_zone | Create a zone/room polygon on a level. | { levelId, polygon, label, properties? } | { zoneId } |
duplicate_level | Copy a level as the editor does (units whose rooms are all on it included; plan references, scans and spawns left behind), above or below, shifting the floors past it. | { levelId, position?, name?, preset? } | { newLevelId, name, floorIndex, shiftedLevelIds, copied, skipped, newNodeIds[] } |
delete_node | Delete a node with everything under it, as the editor's Delete does. | { id } | { deletedIds: [] } |
clear_scene | Empty the project on purpose, back to the default site, building and level. The only way to empty a project: a write that would leave it empty is refused (scene_wipe_blocked) by a store that guards against accidental wipes, and the session keeps the project as stored. | { reason } | { cleared: { removed }, version, graphHash } |
undo | Step back through temporal history. | { steps? } | { undone: number } |
redo | Step forward through temporal history. | { steps? } | { redone: number } |
export_json | Serialize the scene graph as JSON. | { pretty? } | { json: string } |
export_glb | Stubbed: GLB export requires the browser renderer. | — | throws not_implemented |
validate_scene | Zod-validate every node and parent-child integrity. | — | { valid, errors: { nodeId, path, message }[] } |
validate_design | Read-only: validate a design (procedural item recipe, object or JSON string) and measure it. The authority over pascal://schema/design. | { design, parameters? } | { valid, diagnostics[], design, sweep, measurements } |
verify_scene | High-level check with validation status, per-level counts and roles, empty levels, and typed practical issues (storeys with no stair, openings off their wall, stairs off their slab, blocked doors…). | — | { valid, levels[], issues: { type, message }[], hasIssues } |
check_collisions | Find overlapping items and out-of-bounds placements. | { levelId? } | { collisions: { aId, bId, kind }[] } |
analyze_floorplan_image | Vision tool: extract walls, rooms, and approximate dimensions from a floorplan image. | { image, scaleHint? } | { walls, rooms, approximateDimensions, confidence } |
analyze_room_photo | Vision tool: extract approximate dimensions and fixtures from a room photo. | { image } | { approximateDimensions, identifiedFixtures, identifiedWindows } |