skopiasetupllms.txt

The API

One JSON document describes a space. Every tool is a pure function over it: nothing is stored here, and no call remembers a previous one, so you carry the document from call to call and the same document always gives the same answer.

This page is the reference. Setup is how you connect a client to it; the front page is what it is for and when not to use it. Every number below is read off the engine that serves this page, so it cannot promise a limit the endpoint does not enforce.

The endpoint

Endpoint:  POST /v1            all eighteen tools
           POST /v1/core       build, check, draw and export to DXF
           POST /v1/elevation  elevations and components
           POST /v1/advisory   the reads that suggest and never decide

Protocol:  MCP, revision 2026-07-28 (Streamable HTTP). Clients on the
           initialize-era revisions — 2025-11-25, 2025-06-18, 2025-03-26,
           2024-11-05 — are served too: open with `initialize` and name
           your revision in MCP-Protocol-Version, and none of 2026-07-28's
           mirrored headers or _meta fields are asked of you.

A profile is the same server with a shorter tool list. It is a courtesy to a client with a crowded context, never a permission: a key minted against one reaches exactly the tools it names.

/v1/coreedit_layout, list_operations, validate_layout, render_layout, draw_sheet, export_dxf, list_fixtures
/v1/elevationproject_elevation, list_components, project_section, suggest_sections, join_drawings
/v1/advisorysuggest_joins, suggest_rotation, check_rules, missing_dimensions, overhead_report, roof_report

The tools

Eighteen, coarse and intention-shaped rather than one call per object. edit_layout takes a batch of operations and answers with the document and its findings; the advisory reads answer a question and change nothing.

edit_layoutApply operations to a layout document and get the updated document back.
list_operationsEvery operation edit_layout accepts, grouped by what it acts on.
validate_layoutTyped, permanent error codes naming which object offended: overlapping objects, an opening too near a corner, a boundary that crosses itself.
render_layoutThe layout as SVG.
project_elevationThe elevation of one side of the building, PROJECTED from the plan rather than drawn, which is why it cannot disagree with it.
project_sectionA section is the same projection as an elevation with the picture plane moved INSIDE the building.
suggest_sectionsCandidate cut lines with the evidence for choosing between them — how many walls each would cut, how many INTERNAL walls (counted apart: one says how much of the envelope the cut crosses, the other how many rooms it goes through), how many openings it would pass through as voids, which overhead members it would catch, and how much it would reveal beyond.
join_drawingsA house is storeys, and a section is across all of them.
draw_sheetONE sheet, TRUE TO SCALE: the SVG declares real paper millimetres and a viewBox of paper × scale, so a rule laid on the print agrees with the drawing rather than with whatever size a browser chose.
export_dxfThe drawings draw_sheet puts on paper, as ONE DXF for CAD — AutoCAD, Vectorworks, Revit, a CNC bed.
roof_reportA roof is OVER-DETERMINED: span, eaves, ridge and pitch are four numbers with one equation between them, so the plan plus any TWO of the heights fixes it.
list_componentsThe component types an elevation can hang on an opening, with their defaults.
list_fixturesWhat can stand in a room and be drawn as what it is: kitchen units and appliances, sanitaryware, a stair, beds, sofas, wardrobes — each at a typical trade size, with its plan symbol, its front and side, and its SECTION profile through either axis, from one description.
suggest_joinsObjects close enough and aligned enough to be joined, with the evidence for each.
suggest_rotationAnswers twice over, because the two answers usually disagree: the angle with the most clearance around it, and the angle that squares it with its neighbours and the room's own walls.
check_rulesRules are YOUR parameters, checked by a generic engine.
overhead_reportEvery member ABOVE the plan's cut plane — a beam over, today — and whether its heights are known.
missing_dimensionsGiven a layout and the dimensions actually MEASURED on site, says whether the shape is determined by those readings, and if not, which readings to go and take.

The document

Integer millimetres, and the origin at the bottom left

Every persisted coordinate, dimension and offset is a whole number of millimetres. Not metres, not pixels, not floats. Rounding happens once, at the boundary, on the way in, because floating-point drift in a layout that round-trips through an API is a wall that no longer closes some months later. The origin is bottom left and y is up, which is the surveying convention and the one the person holding the tape is thinking in. SVG is y-down, so the flip happens exactly once, at render, and never reaches stored data.

The room is a closed ring

The boundary is a ring of shared vertices: segment i runs from vertex i to vertex i+1. There is no closure tolerance and no way to express an open boundary, because the structure has nowhere to put a gap. Six independently-typed sides almost never close; a ring cannot fail to.

A segment is straight or a single circular arc, and the arc is one signed integer: how far the wall bows from its chord, in millimetres. Positive bows into the room, negative out, and depth zero is the straight case, so a curve flattening is not a discontinuity. Radius-driven arcs were rejected for the opposite reason: a radius goes to infinity as a curve straightens, and is almost never a whole number of millimetres.

Free point placement means a bowtie is expressible, so self-intersection is a refusal (boundary_self_intersects, naming both segments) rather than a structural impossibility. Arcs are capped at a semicircle.

Walls, and internal walls

The line you give is the internal face, the one a tape measure lands on. The wall is thickened outward from it, so thickening never moves the room or changes its area. A partition is the opposite and deliberately so: it has a room on both sides, so neither face is privileged and it straddles its line, half the thickness each way. A partition is a segment and never a ring, which is what lets it exist without trading away the closure guarantee above. Rooms, if you want them, are a read over partitions rather than a second stored thing to keep in step.

What stands in it

Drawings are projected, never redrawn

Elevations and sections come out of the plan document. A horizontal position on one is a reference to a plan feature, never a numberopening:3.jamb.left, vertex:4.outer, object:7.centre — so the plan and the section cannot disagree, because the disagreement is inexpressible. Heights are given, never derived: a cill height cannot be got from a plan, and a plausible 900 drawn on paper is indistinguishable from a measured one forever after, so an opening with no supplied height is refused by name.

A house is one ordinary document per storey against one shared datum, and a joined section is a read over both: aligned from two fixed points you name, with the junction checked rather than chosen. A drawing sits on an A-series sheet at a true scale, and one too big for its cell is refused with both numbers in the message. export_dxf hands the same drawings to CAD as real entities on named layers, in model space, in millimetres.

What it asks rather than guesses

missing_dimensions answers a survey that does not determine the shape with the readings to go and take, not with the number that would close the ring. The same stance holds for a roof with two of its four numbers, and for a height nobody measured. It could pick a plausible value and must not: 40° drawn because 40 is typical is indistinguishable, forever after, from 40° measured.

Limits

Every cap is a measured number — the cost of validating and rendering at that size — rather than an opinion about rooms.

1,000,000World millimetres either way from the origin. A room 2mm wide and a room 900km wide are both refused rather than drawn.
256Boundary vertices, so the same number of wall segments in the ring.
128Partitions internal walls. A segment each, never a ring.
128Openings doors and windows across the ring and the partitions.
64Zones labelled polygons.
64Zone vertices per zone.
2,000Objects raised from 512 by measurement, not opinion. An eighty-seat auditorium is eighty of these.
40Covers per object.
26Sections one per letter.
64Overhead beams and the like.
64Rooflights hosted by the roof, not by a wall.
1,000Wall thickness millimetres.
1,000,000,000Ids the highest id an object may carry.
16Labels characters.
16Numbers characters in an object number.
64References characters in a section reference.

The operation vocabulary

Fifty-seven named operations, one list shared by the editor, the undo stack, the API and edit_layout. There is nothing a pointer can do in the editor that a caller cannot, because a gesture resolves to one of these and this list is the API.

place_corner · remove_last_corner · close_room · reopen_room · move_corner · bow_wall · set_wall_length · add_door · add_window · remove_opening · slide_opening · set_opening_width · swap_door_hinge · swap_door_swing · swap_door_leaves · set_opening_component · set_roof · remove_roof · add_partition · remove_partition · restore_partition · set_partition_thickness · add_beam · remove_overhead · label_overhead · add_section · remove_section · place_zone_corner · remove_last_zone_corner · close_zone · reopen_zone · add_zone · move_zone_edge · label_zone · remove_zone · move_zone_corner · remove_corner · move_wall · split_wall · chamfer_corner · restore_ring · add_table · add_object_block · remove_objects · restore_objects · remove_table · move_table · set_table_size · set_table_occupancy · assign_table · set_table_shape · rotate_table · add_fixture · set_fixture · add_rooflight · remove_rooflight · start_over

Refusals

Fifty-four stable codes, returned as data rather than thrown, each naming the offending segment, opening, zone or object rather than saying “invalid layout”. message is for a human reading logs and is not part of the contract; switch on code. A shipped code is permanent: we add freely and rename never. A refusal names everything wrong at once where it can, not the next thing wrong.

ring_malformed · ring_too_short · coordinate_not_integer_mm · segment_zero_length · depth_not_integer_mm · arc_exceeds_semicircle · boundary_self_intersects · schema_version_unsupported · document_malformed · document_too_large · coordinate_out_of_bounds · id_duplicate · zone_malformed · opening_off_wall · partition_malformed · partition_outside_boundary · opening_exceeds_wall · opening_too_near_corner · object_malformed · object_out_of_bounds · objects_overlap · too_many_overlaps · determinacy_not_rectilinear · dimension_malformed · dimension_not_axial · view_unknown · height_missing · elevation_ordinate_unreferenced · elevation_arc_unsupported · component_type_unknown · fixture_faces_wall · fixture_off_wall · fixture_access_blocked · fixture_type_unknown · overhead_kind_unknown · section_ref_duplicate · section_ref_unknown · section_mark_unknown · section_extent · paper_unknown · sheet_overflows · roof_kind_unknown · roof_eaves_malformed · rooflight_off_roof · roof_overdetermined · scale_unusable · storeys_malformed · storeys_misaligned · storeys_views_differ · storeys_junction_mismatch · clearance_violation · rule_kind_unknown · rule_malformed · op_unknown

Validation cost is bounded as well as complete. Overlap is a sweep over a spatial index rather than every object against every other, because an O(n²) check is a denial of service handed to the caller; and the overlap report is capped too, since n objects on one point overlap in n²/2 pairs. NaN, Infinity, -0, numbers past the safe integer range and rotations of a billion degrees all survive typeof x === 'number' and are all refused at the boundary.

Rendering

The renderer is a pure function of the parameters: byte-identical SVG for identical input, on every platform, so a render can be diffed in CI. Nothing reachable from a geometry path reads a clock or a random number, iteration order is defined, and a title block's date is a string the caller supplies rather than one the engine invents.

Colours arrive as a validated token map and an unknown token is refused rather than ignored. On paper the engine draws the register it was built to: solid ink poché, two tones, three line weights, one grotesque in tracked capitals. A style is never an argument to a tool, because a style that is an argument is a style every caller gets wrong differently.

What it is not

No levels, families, schedules, parametric constraint solvers, egress analysis or clash detection, and there never will be: if a feature only makes sense because a BIM package has it, it is out of scope. Editing is single-editor by decision — undo is a bounded stack of inverse commands, not a CRDT — and making it concurrent later is a rewrite of the mutation layer we would rather discuss than do quietly. A section does not yet cut a pitched roof, and half-hipped, mansard, gambrel and catslide roofs, dormers and chimneys are refused by name rather than guessed at.

The engine's source is not public. This endpoint is the interface, not the implementation, and it is free while it is a demand probe: it will be priced eventually and there will be notice first.