← WebMCP Directory

Tool tree

floorplay-zeta.vercel.app

AI & AgentsTools verified
Website
Floorplay
Explore capabilities
    get_roomAnswer

    Read the current room: shell, openings (with compass facing), brief, placed items with positions and light scores, the user's selection, open proposals, metrics and violations. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.

    View tool JSON
    {
      "name": "get_room",
      "kind": "answer",
      "impl": "imperative",
      "description": "Read the current room: shell, openings (with compass facing), brief, placed items with positions and light scores, the user's selection, open proposals, metrics and violations. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    get_catalogAnswer

    List furniture available to place, with dimensions in cm, price in USD, clearance rules, the room kinds each item suits, its alternative `colors` and, for wall-mounted things, the `mountHeight` it hangs at. Filter by category, room kind, maximum footprint, maximum price or a name query. Items added with add_catalog_item are included. Returns at most 60 items, cheapest first; narrow the filters if `truncated` is true.

    View tool JSON
    {
      "name": "get_catalog",
      "kind": "answer",
      "impl": "imperative",
      "description": "List furniture available to place, with dimensions in cm, price in USD, clearance rules, the room kinds each item suits, its alternative `colors` and, for wall-mounted things, the `mountHeight` it hangs at. Filter by category, room kind, maximum footprint, maximum price or a name query. Items added with add_catalog_item are included. Returns at most 60 items, cheapest first; narrow the filters if `truncated` is true.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "category": {
            "type": "string",
            "description": "Furniture category",
            "enum": [
              "bed",
              "sofa",
              "armchair",
              "desk",
              "chair",
              "table",
              "wardrobe",
              "shelf",
              "dresser",
              "nightstand",
              "rug",
              "lamp",
              "plant",
              "tv",
              "kitchen",
              "appliance",
              "storage",
              "decor",
              "wall",
              "other"
            ]
          },
          "room": {
            "type": "string",
            "description": "Kind of room the item suits",
            "enum": [
              "living",
              "kitchen",
              "bedroom",
              "hall",
              "office",
              "dining",
              "kids",
              "studio"
            ]
          },
          "maxWidth": {
            "type": "integer",
            "description": "Maximum width (cm)"
          },
          "maxDepth": {
            "type": "integer",
            "description": "Maximum depth (cm)"
          },
          "maxPrice": {
            "type": "number",
            "description": "Maximum price in USD"
          },
          "query": {
            "type": "string",
            "description": "Case-insensitive substring of the name or category"
          }
        }
      }
    }
    suggest_positionsAction

    Best positions for a catalog item given the room, walls, door, window and daylight. Call this before place_item for beds, desks, sofas, wardrobes and shelves. Each suggestion is a valid placement with a reason and a score. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.

    View tool JSON
    {
      "name": "suggest_positions",
      "kind": "act",
      "impl": "imperative",
      "description": "Best positions for a catalog item given the room, walls, door, window and daylight. Call this before place_item for beds, desks, sofas, wardrobes and shelves. Each suggestion is a valid placement with a reason and a score. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "catalogId": {
            "type": "string",
            "description": "Catalog id from get_catalog"
          },
          "near": {
            "type": "string",
            "description": "Prefer positions close to this feature",
            "enum": [
              "window",
              "door",
              "corner",
              "any"
            ]
          },
          "count": {
            "type": "integer",
            "description": "How many suggestions to return, default 5",
            "minimum": 1,
            "maximum": 10
          },
          "hour": {
            "type": "integer",
            "description": "Hour of day used for the light score, 6 to 20. Defaults to 9",
            "minimum": 6,
            "maximum": 20
          }
        },
        "required": [
          "catalogId"
        ]
      }
    }
    evaluate_layoutAction

    Score a candidate set of changes WITHOUT applying them. Returns metrics, violations and the delta versus the current room. Use it to iterate privately before place_item or propose_layout. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.

    View tool JSON
    {
      "name": "evaluate_layout",
      "kind": "act",
      "impl": "imperative",
      "description": "Score a candidate set of changes WITHOUT applying them. Returns metrics, violations and the delta versus the current room. Use it to iterate privately before place_item or propose_layout. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "placements": {
            "type": "array",
            "description": "Changes to apply in order",
            "items": {
              "type": "object",
              "properties": {
                "action": {
                  "type": "string",
                  "description": "place | move | remove | swap",
                  "enum": [
                    "place",
                    "move",
                    "remove",
                    "swap"
                  ]
                },
                "catalogId": {
                  "type": "string",
                  "description": "Catalog id (place, swap)"
                },
                "id": {
                  "type": "string",
                  "description": "Existing item id (move, remove, swap). For place, optional id to assign"
                },
                "x": {
                  "type": "integer",
                  "description": "Center x (place, move) (cm)"
                },
                "y": {
                  "type": "integer",
                  "description": "Center y (place, move) (cm)"
                },
                "rotation": {
                  "type": "integer",
                  "description": "Rotation in degrees clockwise",
                  "enum": [
                    0,
                    90,
                    180,
                    270
                  ]
                }
              },
              "required": [
                "action"
              ]
            }
          }
        },
        "required": [
          "placements"
        ]
      }
    }
    get_daylightAnswer

    Approximate daylight at a given hour (6 to 20): light score 0..1 per item and the brightest free spots for morning (09:00) and afternoon (16:00). Use it to place a desk in morning light or a bed away from glare.

    View tool JSON
    {
      "name": "get_daylight",
      "kind": "answer",
      "impl": "imperative",
      "description": "Approximate daylight at a given hour (6 to 20): light score 0..1 per item and the brightest free spots for morning (09:00) and afternoon (16:00). Use it to place a desk in morning light or a bed away from glare.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "hour": {
            "type": "integer",
            "description": "Hour of day, 6 to 20. Defaults to the current slider value",
            "minimum": 6,
            "maximum": 20
          }
        }
      }
    }
    list_templatesAnswer

    Ready-made rooms you can start from, with their key, dimensions, item count and budget. Call this before load_template to learn the keys.

    View tool JSON
    {
      "name": "list_templates",
      "kind": "answer",
      "impl": "imperative",
      "description": "Ready-made rooms you can start from, with their key, dimensions, item count and budget. Call this before load_template to learn the keys.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    suggest_paletteAction

    Three color schemes for the current room, warm, cool and neutral, derived from what is already in it. Each returns a wall color, a floor finish, three accent tones and the exact set_item_color changes that would carry it out. Use it when the user asks how the room could look, then apply one with set_finish and set_item_color.

    View tool JSON
    {
      "name": "suggest_palette",
      "kind": "act",
      "impl": "imperative",
      "description": "Three color schemes for the current room, warm, cool and neutral, derived from what is already in it. Each returns a wall color, a floor finish, three accent tones and the exact set_item_color changes that would carry it out. Use it when the user asks how the room could look, then apply one with set_finish and set_item_color.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    get_ledgerAnswer

    Recent actions by the user and by you, newest last, with the number of violations after each.

    View tool JSON
    {
      "name": "get_ledger",
      "kind": "answer",
      "impl": "imperative",
      "description": "Recent actions by the user and by you, newest last, with the number of violations after each.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "description": "How many entries, default 20",
            "minimum": 1,
            "maximum": 200
          }
        }
      }
    }
    suggest_furnitureAction

    Turn the brief into a priced shopping list that fits the room and the budget: which catalog items cover each need (sleep, work, host, storage, dine, read, kids, kitchen, hall), the total, what remains, needs that could not be met, and cheaper or pricier alternatives per pick. Call it before propose_layout so the budget shapes the layout. Defaults to the room brief; pass budget or needs to explore.

    View tool JSON
    {
      "name": "suggest_furniture",
      "kind": "act",
      "impl": "imperative",
      "description": "Turn the brief into a priced shopping list that fits the room and the budget: which catalog items cover each need (sleep, work, host, storage, dine, read, kids, kitchen, hall), the total, what remains, needs that could not be met, and cheaper or pricier alternatives per pick. Call it before propose_layout so the budget shapes the layout. Defaults to the room brief; pass budget or needs to explore.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "budget": {
            "type": "number",
            "description": "Budget in USD; defaults to the brief",
            "minimum": 0
          },
          "needs": {
            "type": "array",
            "description": "Needs to cover; defaults to the brief",
            "items": {
              "type": "string",
              "description": "Need, e.g. \"work from home\""
            }
          }
        }
      }
    }
    list_roomsAnswer

    Every room in this session, with its id, dimensions in cm and item count. The one flagged `current: true` is what get_room and every editing tool acts on. Use it before switch_room, delete_room or when the user names a room you have not seen.

    View tool JSON
    {
      "name": "list_rooms",
      "kind": "answer",
      "impl": "imperative",
      "description": "Every room in this session, with its id, dimensions in cm and item count. The one flagged `current: true` is what get_room and every editing tool acts on. Use it before switch_room, delete_room or when the user names a room you have not seen.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    get_guideAnswer

    How to design a room with these tools: the recommended order of calls, the coordinate conventions, and the habits that avoid rework. Call it once at the start of a design task.

    View tool JSON
    {
      "name": "get_guide",
      "kind": "answer",
      "impl": "imperative",
      "description": "How to design a room with these tools: the recommended order of calls, the coordinate conventions, and the habits that avoid rework. Call it once at the start of a design task.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    set_room_shellAction

    Set the room dimensions in cm and optionally which wall faces north. Existing items are kept and re-validated.

    View tool JSON
    {
      "name": "set_room_shell",
      "kind": "act",
      "impl": "imperative",
      "description": "Set the room dimensions in cm and optionally which wall faces north. Existing items are kept and re-validated.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "width": {
            "type": "integer",
            "description": "Room width (x) (cm)"
          },
          "depth": {
            "type": "integer",
            "description": "Room depth (y) (cm)"
          },
          "height": {
            "type": "integer",
            "description": "Ceiling height (cm)"
          },
          "northWall": {
            "type": "string",
            "description": "Which wall, named by where it sits on the plan: top, right, bottom or left. These are positions on the drawing the user is looking at, not compass directions — say \"the top wall\" back to them, not \"the north wall\"",
            "enum": [
              "top",
              "right",
              "bottom",
              "left"
            ]
          }
        },
        "required": [
          "width",
          "depth",
          "height"
        ]
      }
    }
    add_openingAction

    Add a door or window to a wall. offset is measured from the left end of the top/bottom walls or the top end of the left/right walls. Doors default to 200 cm high swinging inward; windows default to 120 cm high with a 90 cm sill.

    View tool JSON
    {
      "name": "add_opening",
      "kind": "act",
      "impl": "imperative",
      "description": "Add a door or window to a wall. offset is measured from the left end of the top/bottom walls or the top end of the left/right walls. Doors default to 200 cm high swinging inward; windows default to 120 cm high with a 90 cm sill.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "description": "door or window",
            "enum": [
              "door",
              "window"
            ]
          },
          "wall": {
            "type": "string",
            "description": "Which wall, named by where it sits on the plan: top, right, bottom or left. These are positions on the drawing the user is looking at, not compass directions — say \"the top wall\" back to them, not \"the north wall\"",
            "enum": [
              "top",
              "right",
              "bottom",
              "left"
            ]
          },
          "offset": {
            "type": "integer",
            "description": "Distance along the wall (cm)"
          },
          "width": {
            "type": "integer",
            "description": "Opening width (cm)"
          },
          "height": {
            "type": "integer",
            "description": "Opening height (cm)"
          },
          "sill": {
            "type": "integer",
            "description": "Window sill height (cm)"
          },
          "swing": {
            "type": "string",
            "description": "Door swing",
            "enum": [
              "in",
              "out"
            ]
          },
          "hinge": {
            "type": "string",
            "description": "Hinge side",
            "enum": [
              "start",
              "end"
            ]
          }
        },
        "required": [
          "kind",
          "wall",
          "offset",
          "width"
        ]
      }
    }
    remove_openingAction

    Remove a door or window by id (ids come from get_room).

    View tool JSON
    {
      "name": "remove_opening",
      "kind": "act",
      "impl": "imperative",
      "description": "Remove a door or window by id (ids come from get_room).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Opening id"
          }
        },
        "required": [
          "id"
        ]
      }
    }
    move_openingAction

    Move a door or window along its wall, or to another wall, by id (ids come from get_room). offset is measured from the left end of the top/bottom walls or the top end of the left/right walls. It must stay within the wall and clear of other openings. A door that is a doorway between two rooms cannot be moved this way: remove_doorway and cut_doorway instead.

    View tool JSON
    {
      "name": "move_opening",
      "kind": "act",
      "impl": "imperative",
      "description": "Move a door or window along its wall, or to another wall, by id (ids come from get_room). offset is measured from the left end of the top/bottom walls or the top end of the left/right walls. It must stay within the wall and clear of other openings. A door that is a doorway between two rooms cannot be moved this way: remove_doorway and cut_doorway instead.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Opening id"
          },
          "offset": {
            "type": "integer",
            "description": "New distance along the wall (cm)"
          },
          "wall": {
            "type": "string",
            "description": "Wall to carry it to; defaults to the wall it is on",
            "enum": [
              "top",
              "right",
              "bottom",
              "left"
            ]
          }
        },
        "required": [
          "id",
          "offset"
        ]
      }
    }
    set_briefAction

    Update the design brief: budget in USD, needs (short phrases) and free-text notes. Omitted fields are kept.

    View tool JSON
    {
      "name": "set_brief",
      "kind": "act",
      "impl": "imperative",
      "description": "Update the design brief: budget in USD, needs (short phrases) and free-text notes. Omitted fields are kept.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "budget": {
            "type": "number",
            "description": "Budget in USD",
            "minimum": 0
          },
          "needs": {
            "type": "array",
            "description": "What the room must support",
            "items": {
              "type": "string",
              "description": "Need"
            }
          },
          "notes": {
            "type": "string",
            "description": "Free text"
          }
        }
      }
    }
    place_itemAction

    Place one catalog item by its center. Applies immediately; undo_last_action takes it back. and reports any violations plus the nearest clear position. Prefer suggest_positions for beds, desks, sofas, wardrobes and shelves. Positions within 15 cm of a wall are snapped flush and wall furniture is turned to face the room; the result reports snapped: true. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.

    View tool JSON
    {
      "name": "place_item",
      "kind": "act",
      "impl": "imperative",
      "description": "Place one catalog item by its center. Applies immediately; undo_last_action takes it back. and reports any violations plus the nearest clear position. Prefer suggest_positions for beds, desks, sofas, wardrobes and shelves. Positions within 15 cm of a wall are snapped flush and wall furniture is turned to face the room; the result reports snapped: true. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "catalogId": {
            "type": "string",
            "description": "Catalog id from get_catalog"
          },
          "x": {
            "type": "integer",
            "description": "Center x (cm)"
          },
          "y": {
            "type": "integer",
            "description": "Center y (cm)"
          },
          "rotation": {
            "type": "integer",
            "description": "Rotation in degrees clockwise",
            "enum": [
              0,
              90,
              180,
              270
            ]
          }
        },
        "required": [
          "catalogId",
          "x",
          "y"
        ]
      }
    }
    move_itemAction

    Move an existing item to a new center, optionally rotating it. Locked items cannot be moved. Prefer suggest_positions for beds, desks, sofas, wardrobes and shelves. Positions within 15 cm of a wall are snapped flush and wall furniture is turned to face the room; the result reports snapped: true. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.

    View tool JSON
    {
      "name": "move_item",
      "kind": "act",
      "impl": "imperative",
      "description": "Move an existing item to a new center, optionally rotating it. Locked items cannot be moved. Prefer suggest_positions for beds, desks, sofas, wardrobes and shelves. Positions within 15 cm of a wall are snapped flush and wall furniture is turned to face the room; the result reports snapped: true. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Item id"
          },
          "x": {
            "type": "integer",
            "description": "Center x (cm)"
          },
          "y": {
            "type": "integer",
            "description": "Center y (cm)"
          },
          "rotation": {
            "type": "integer",
            "description": "Rotation in degrees clockwise",
            "enum": [
              0,
              90,
              180,
              270
            ]
          }
        },
        "required": [
          "id",
          "x",
          "y"
        ]
      }
    }
    rotate_itemAction

    Rotate an existing item in place to 0, 90, 180 or 270 degrees clockwise. At 0 the front faces the bottom wall.

    View tool JSON
    {
      "name": "rotate_item",
      "kind": "act",
      "impl": "imperative",
      "description": "Rotate an existing item in place to 0, 90, 180 or 270 degrees clockwise. At 0 the front faces the bottom wall.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Item id"
          },
          "rotation": {
            "type": "integer",
            "description": "Rotation in degrees clockwise",
            "enum": [
              0,
              90,
              180,
              270
            ]
          }
        },
        "required": [
          "id",
          "rotation"
        ]
      }
    }
    fix_itemAction

    Move one item to the nearest position that clears its blocking violations, keeping its rotation. Use it when place_item or move_item reports an overlap, a blocked door or window, or too little clearance.

    View tool JSON
    {
      "name": "fix_item",
      "kind": "act",
      "impl": "imperative",
      "description": "Move one item to the nearest position that clears its blocking violations, keeping its rotation. Use it when place_item or move_item reports an overlap, a blocked door or window, or too little clearance.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Item id"
          }
        },
        "required": [
          "id"
        ]
      }
    }
    remove_itemAction

    Remove an item from the room. Locked items cannot be removed.

    View tool JSON
    {
      "name": "remove_item",
      "kind": "act",
      "impl": "imperative",
      "description": "Remove an item from the room. Locked items cannot be removed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Item id"
          }
        },
        "required": [
          "id"
        ]
      }
    }
    clear_itemsAction

    Empty the room in one ledger entry, so a single undo puts everything back. Locked items are left where they are; the result lists what remains. Ask the user before calling it on a room they have worked on.

    View tool JSON
    {
      "name": "clear_items",
      "kind": "act",
      "impl": "imperative",
      "description": "Empty the room in one ledger entry, so a single undo puts everything back. Locked items are left where they are; the result lists what remains. Ask the user before calling it on a room they have worked on.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    swap_itemAction

    Replace an item with a different catalog item, keeping its position and rotation. Useful for cheaper or smaller alternatives.

    View tool JSON
    {
      "name": "swap_item",
      "kind": "act",
      "impl": "imperative",
      "description": "Replace an item with a different catalog item, keeping its position and rotation. Useful for cheaper or smaller alternatives.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Item id"
          },
          "catalogId": {
            "type": "string",
            "description": "Replacement catalog id"
          }
        },
        "required": [
          "id",
          "catalogId"
        ]
      }
    }
    set_item_lockedAction

    Lock an item so nobody can move, swap or remove it (for example when the user says "keep the sofa"), or unlock it.

    View tool JSON
    {
      "name": "set_item_locked",
      "kind": "act",
      "impl": "imperative",
      "description": "Lock an item so nobody can move, swap or remove it (for example when the user says \"keep the sofa\"), or unlock it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Item id"
          },
          "locked": {
            "type": "boolean",
            "description": "true to lock"
          }
        },
        "required": [
          "id",
          "locked"
        ]
      }
    }
    add_catalog_itemAction

    Add a product you researched to the catalog so it can be placed: name, category, dimensions in cm, price in USD, optional color and URL. Clearance rules are inferred from the category.

    View tool JSON
    {
      "name": "add_catalog_item",
      "kind": "act",
      "impl": "imperative",
      "description": "Add a product you researched to the catalog so it can be placed: name, category, dimensions in cm, price in USD, optional color and URL. Clearance rules are inferred from the category.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Product name"
          },
          "category": {
            "type": "string",
            "description": "Furniture category",
            "enum": [
              "bed",
              "sofa",
              "armchair",
              "desk",
              "chair",
              "table",
              "wardrobe",
              "shelf",
              "dresser",
              "nightstand",
              "rug",
              "lamp",
              "plant",
              "tv",
              "kitchen",
              "appliance",
              "storage",
              "decor",
              "wall",
              "other"
            ]
          },
          "width": {
            "type": "integer",
            "description": "Width (cm)"
          },
          "depth": {
            "type": "integer",
            "description": "Depth (cm)"
          },
          "height": {
            "type": "integer",
            "description": "Height (cm)"
          },
          "price": {
            "type": "number",
            "description": "Price in USD",
            "minimum": 0
          },
          "color": {
            "type": "string",
            "description": "Hex color like #aabbcc"
          },
          "url": {
            "type": "string",
            "description": "Product page URL"
          }
        },
        "required": [
          "name",
          "category",
          "width",
          "depth",
          "height",
          "price"
        ]
      }
    }
    load_templateAction

    Start a new room from a ready-made layout; use list_templates for keys. The room is created, furnished, switched to and returned. It never replaces the current room, and it applies straight away rather than becoming a proposal. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.

    View tool JSON
    {
      "name": "load_template",
      "kind": "act",
      "impl": "imperative",
      "description": "Start a new room from a ready-made layout; use list_templates for keys. The room is created, furnished, switched to and returned. It never replaces the current room, and it applies straight away rather than becoming a proposal. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "Template key from list_templates",
            "enum": [
              "living",
              "kitchen",
              "bedroom",
              "hall",
              "office",
              "dining",
              "kids",
              "studio"
            ]
          },
          "name": {
            "type": "string",
            "description": "Name for the new room, defaults to the template name"
          }
        },
        "required": [
          "key"
        ]
      }
    }
    create_roomAction

    Create a new empty room and switch to it. The current room is kept and can be returned to with switch_room. Sides must be between 100 and 3000 cm. Creating a room writes no ledger entry, so the result reports status "applied" with the new room's own violations and metrics. Use load_template instead to start from a furnished layout.

    View tool JSON
    {
      "name": "create_room",
      "kind": "act",
      "impl": "imperative",
      "description": "Create a new empty room and switch to it. The current room is kept and can be returned to with switch_room. Sides must be between 100 and 3000 cm. Creating a room writes no ledger entry, so the result reports status \"applied\" with the new room's own violations and metrics. Use load_template instead to start from a furnished layout.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Room name"
          },
          "width": {
            "type": "integer",
            "description": "Room width (x) (cm)"
          },
          "depth": {
            "type": "integer",
            "description": "Room depth (y) (cm)"
          },
          "height": {
            "type": "integer",
            "description": "Ceiling height (cm)"
          },
          "northWall": {
            "type": "string",
            "description": "Which wall, named by where it sits on the plan: top, right, bottom or left. These are positions on the drawing the user is looking at, not compass directions — say \"the top wall\" back to them, not \"the north wall\"",
            "enum": [
              "top",
              "right",
              "bottom",
              "left"
            ]
          }
        },
        "required": [
          "name",
          "width",
          "depth",
          "height"
        ]
      }
    }
    switch_roomAction

    Make another room the current one, so get_room and every editing tool acts on it. Ids come from list_rooms. Nothing is lost: the room you leave keeps its items and its ledger. Writes no ledger entry, so the result reports status "applied" with the arriving room's violations and metrics.

    View tool JSON
    {
      "name": "switch_room",
      "kind": "act",
      "impl": "imperative",
      "description": "Make another room the current one, so get_room and every editing tool acts on it. Ids come from list_rooms. Nothing is lost: the room you leave keeps its items and its ledger. Writes no ledger entry, so the result reports status \"applied\" with the arriving room's violations and metrics.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Room id from list_rooms"
          }
        },
        "required": [
          "id"
        ]
      }
    }
    rename_roomAction

    Rename the current room. Writes no ledger entry, so the result reports status "applied" with the room's violations and metrics as they stand.

    View tool JSON
    {
      "name": "rename_room",
      "kind": "act",
      "impl": "imperative",
      "description": "Rename the current room. Writes no ledger entry, so the result reports status \"applied\" with the room's violations and metrics as they stand.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "New room name"
          }
        },
        "required": [
          "name"
        ]
      }
    }
    delete_roomSensitive Action

    Delete a room and everything in it, including its ledger. This cannot be undone, so confirm with the user first. The last remaining room cannot be deleted. Writes no ledger entry, so the result reports status "applied" with the room that is current afterwards.

    View tool JSON
    {
      "name": "delete_room",
      "kind": "transact",
      "impl": "imperative",
      "description": "Delete a room and everything in it, including its ledger. This cannot be undone, so confirm with the user first. The last remaining room cannot be deleted. Writes no ledger entry, so the result reports status \"applied\" with the room that is current afterwards.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Room id from list_rooms"
          }
        },
        "required": [
          "id"
        ]
      }
    }
    set_item_colorAction

    Repaint one placed item in one of the alternative finishes get_catalog lists under `colors`, or pass null (or omit color) to put it back to its catalog color. Use it to carry out a scheme from suggest_palette.

    View tool JSON
    {
      "name": "set_item_color",
      "kind": "act",
      "impl": "imperative",
      "description": "Repaint one placed item in one of the alternative finishes get_catalog lists under `colors`, or pass null (or omit color) to put it back to its catalog color. Use it to carry out a scheme from suggest_palette.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Item id"
          },
          "color": {
            "type": "string",
            "description": "New color as hex, like #aabbcc",
            "nullable": true
          }
        },
        "required": [
          "id"
        ]
      }
    }
    set_finishAction

    Paint the walls and lay the floor: wall takes a hex color, floor one of oak, walnut, ash, grey or tile. Omitted fields keep what the room has. Applies straight away in both views.

    View tool JSON
    {
      "name": "set_finish",
      "kind": "act",
      "impl": "imperative",
      "description": "Paint the walls and lay the floor: wall takes a hex color, floor one of oak, walnut, ash, grey or tile. Omitted fields keep what the room has. Applies straight away in both views.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "wall": {
            "type": "string",
            "description": "Wall color as hex, like #aabbcc"
          },
          "floor": {
            "type": "string",
            "description": "Floor material",
            "enum": [
              "oak",
              "walnut",
              "ash",
              "grey",
              "tile"
            ]
          }
        }
      }
    }
    apply_paletteAction

    Carry out one of the schemes suggest_palette offers, in one ledger entry: the wall color, the floor finish and every item recolor together. Call suggest_palette first if the user should see the three options before you pick. Applies straight away rather than becoming a proposal, because color is easy to change back.

    View tool JSON
    {
      "name": "apply_palette",
      "kind": "act",
      "impl": "imperative",
      "description": "Carry out one of the schemes suggest_palette offers, in one ledger entry: the wall color, the floor finish and every item recolor together. Call suggest_palette first if the user should see the three options before you pick. Applies straight away rather than becoming a proposal, because color is easy to change back.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Which scheme from suggest_palette",
            "enum": [
              "warm",
              "cool",
              "neutral"
            ]
          }
        },
        "required": [
          "name"
        ]
      }
    }
    propose_layoutAction

    Propose a batch of changes as ghosts on the plan with a label, without applying them. The user sees a card with the metrics delta and can accept or reject. Call it several times with different labels to offer layout variants. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.

    View tool JSON
    {
      "name": "propose_layout",
      "kind": "act",
      "impl": "imperative",
      "description": "Propose a batch of changes as ghosts on the plan with a label, without applying them. The user sees a card with the metrics delta and can accept or reject. Call it several times with different labels to offer layout variants. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "Short name for this option, e.g. \"Bed by the window\""
          },
          "placements": {
            "type": "array",
            "description": "Changes to apply in order",
            "items": {
              "type": "object",
              "properties": {
                "action": {
                  "type": "string",
                  "description": "place | move | remove | swap",
                  "enum": [
                    "place",
                    "move",
                    "remove",
                    "swap"
                  ]
                },
                "catalogId": {
                  "type": "string",
                  "description": "Catalog id (place, swap)"
                },
                "id": {
                  "type": "string",
                  "description": "Existing item id (move, remove, swap). For place, optional id to assign"
                },
                "x": {
                  "type": "integer",
                  "description": "Center x (place, move) (cm)"
                },
                "y": {
                  "type": "integer",
                  "description": "Center y (place, move) (cm)"
                },
                "rotation": {
                  "type": "integer",
                  "description": "Rotation in degrees clockwise",
                  "enum": [
                    0,
                    90,
                    180,
                    270
                  ]
                }
              },
              "required": [
                "action"
              ]
            }
          }
        },
        "required": [
          "label",
          "placements"
        ]
      }
    }
    apply_layoutAction

    Apply a whole layout at once: places, moves, removes and swaps in the order given, as a single ledger entry, so one undo takes the whole idea back. Use propose_layout instead when the user should choose between options, and evaluate_layout first to check the result before anyone sees it. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.

    View tool JSON
    {
      "name": "apply_layout",
      "kind": "act",
      "impl": "imperative",
      "description": "Apply a whole layout at once: places, moves, removes and swaps in the order given, as a single ledger entry, so one undo takes the whole idea back. Use propose_layout instead when the user should choose between options, and evaluate_layout first to check the result before anyone sees it. Coordinates are integer centimeters. Origin is the top-left corner of the room; x grows to the right, y grows downward. Items are placed by their center. rotation is 0, 90, 180 or 270 degrees clockwise; at 0 the item front faces +y (the bottom wall). Call get_room first to learn dimensions, openings and current items.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "placements": {
            "type": "array",
            "description": "Changes to apply in order",
            "items": {
              "type": "object",
              "properties": {
                "action": {
                  "type": "string",
                  "description": "place | move | remove | swap",
                  "enum": [
                    "place",
                    "move",
                    "remove",
                    "swap"
                  ]
                },
                "catalogId": {
                  "type": "string",
                  "description": "Catalog id (place, swap)"
                },
                "id": {
                  "type": "string",
                  "description": "Existing item id (move, remove, swap). For place, optional id to assign"
                },
                "x": {
                  "type": "integer",
                  "description": "Center x (place, move) (cm)"
                },
                "y": {
                  "type": "integer",
                  "description": "Center y (place, move) (cm)"
                },
                "rotation": {
                  "type": "integer",
                  "description": "Rotation in degrees clockwise",
                  "enum": [
                    0,
                    90,
                    180,
                    270
                  ]
                }
              },
              "required": [
                "action"
              ]
            }
          }
        },
        "required": [
          "placements"
        ]
      }
    }
    set_daylight_hourAction

    Move the daylight time slider (6 to 20) so the user sees light at that hour in both views. Returns light per item.

    View tool JSON
    {
      "name": "set_daylight_hour",
      "kind": "act",
      "impl": "imperative",
      "description": "Move the daylight time slider (6 to 20) so the user sees light at that hour in both views. Returns light per item.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "hour": {
            "type": "integer",
            "description": "Hour of day",
            "minimum": 6,
            "maximum": 20
          }
        },
        "required": [
          "hour"
        ]
      }
    }
    set_cameraAction

    Move the 3D camera. Use a preset (overview, from_door, at_desk, on_bed, at_window) or give x, y and yaw (degrees clockwise, 0 faces the top wall) for a walking viewpoint at eye height. Returns the items visible from there, nearest first.

    View tool JSON
    {
      "name": "set_camera",
      "kind": "act",
      "impl": "imperative",
      "description": "Move the 3D camera. Use a preset (overview, from_door, at_desk, on_bed, at_window) or give x, y and yaw (degrees clockwise, 0 faces the top wall) for a walking viewpoint at eye height. Returns the items visible from there, nearest first.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "preset": {
            "type": "string",
            "description": "Named viewpoint",
            "enum": [
              "overview",
              "from_door",
              "at_desk",
              "on_bed",
              "at_window"
            ]
          },
          "x": {
            "type": "integer",
            "description": "Camera x (cm)"
          },
          "y": {
            "type": "integer",
            "description": "Camera y (cm)"
          },
          "yaw": {
            "type": "integer",
            "description": "Yaw in degrees",
            "minimum": 0,
            "maximum": 359
          }
        }
      }
    }
    undo_last_actionAction

    Revert the most recent action in the ledger (yours or the user's). The revert is itself recorded.

    View tool JSON
    {
      "name": "undo_last_action",
      "kind": "act",
      "impl": "imperative",
      "description": "Revert the most recent action in the ledger (yours or the user's). The revert is itself recorded.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    revert_to_entryAction

    Rewind the room to how it stood just after one ledger entry, undoing everything after it in one go. Ids come from get_ledger. The rewind is itself recorded, so it can be undone in turn.

    View tool JSON
    {
      "name": "revert_to_entry",
      "kind": "act",
      "impl": "imperative",
      "description": "Rewind the room to how it stood just after one ledger entry, undoing everything after it in one go. Ids come from get_ledger. The rewind is itself recorded, so it can be undone in turn.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "ledgerId": {
            "type": "string",
            "description": "Ledger entry id from get_ledger"
          }
        },
        "required": [
          "ledgerId"
        ]
      }
    }
    select_itemAction

    Select an item so the user sees it highlighted on the plan and in 3D with its properties open, or pass null to clear the selection. Use it to point at what you are talking about. Selecting also turns on the selection-scoped tools (move_selected, replace_selected, remove_selected, find_alternatives_for_selected). Writes no ledger entry, so the result reports status "applied" with the room's violations and metrics as they stand.

    View tool JSON
    {
      "name": "select_item",
      "kind": "act",
      "impl": "imperative",
      "description": "Select an item so the user sees it highlighted on the plan and in 3D with its properties open, or pass null to clear the selection. Use it to point at what you are talking about. Selecting also turns on the selection-scoped tools (move_selected, replace_selected, remove_selected, find_alternatives_for_selected). Writes no ledger entry, so the result reports status \"applied\" with the room's violations and metrics as they stand.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Item id, or null to clear the selection",
            "nullable": true
          }
        }
      }
    }
    set_viewAction

    Turn the daylight tint and the 3D shadows on or off. Switch the tint off when the user wants to read the plan itself, and the shadows off when the 3D view is slow. Omitted fields keep what is set. Writes no ledger entry, so the result reports status "applied" with the room's violations and metrics as they stand.

    View tool JSON
    {
      "name": "set_view",
      "kind": "act",
      "impl": "imperative",
      "description": "Turn the daylight tint and the 3D shadows on or off. Switch the tint off when the user wants to read the plan itself, and the shadows off when the 3D view is slow. Omitted fields keep what is set. Writes no ledger entry, so the result reports status \"applied\" with the room's violations and metrics as they stand.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "showDaylight": {
            "type": "boolean",
            "description": "Draw the daylight tint over the plan"
          },
          "showShadows": {
            "type": "boolean",
            "description": "Cast and catch shadows in the 3D view"
          }
        }
      }
    }
    get_elevationAnswer

    One wall seen straight on: its paint, its length and height, the doors and windows in it, everything hanging on it with its offset and mount height, and the floor-standing furniture within 100 cm of it. Walls are named by where they sit on the plan — top, right, bottom, left — and that is how the user sees them on screen, so name them that way in your reply. `facing` gives the compass direction if you need it, but it moves whenever north moves and it is not what the user is looking at. `describe` is the label the app itself puts on this wall. Read this before hanging anything, so a picture goes above the sofa rather than through it. offset is the distance along the wall to the near edge of the thing, measured from the left end of the top and bottom walls and from the top end of the left and right walls — the same ruler add_opening uses.

    View tool JSON
    {
      "name": "get_elevation",
      "kind": "answer",
      "impl": "imperative",
      "description": "One wall seen straight on: its paint, its length and height, the doors and windows in it, everything hanging on it with its offset and mount height, and the floor-standing furniture within 100 cm of it. Walls are named by where they sit on the plan — top, right, bottom, left — and that is how the user sees them on screen, so name them that way in your reply. `facing` gives the compass direction if you need it, but it moves whenever north moves and it is not what the user is looking at. `describe` is the label the app itself puts on this wall. Read this before hanging anything, so a picture goes above the sofa rather than through it. offset is the distance along the wall to the near edge of the thing, measured from the left end of the top and bottom walls and from the top end of the left and right walls — the same ruler add_opening uses.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "wall": {
            "type": "string",
            "description": "Which wall, named by where it sits on the plan: top, right, bottom or left. These are positions on the drawing the user is looking at, not compass directions — say \"the top wall\" back to them, not \"the north wall\"",
            "enum": [
              "top",
              "right",
              "bottom",
              "left"
            ]
          }
        },
        "required": [
          "wall"
        ]
      }
    }
    list_wall_palettesAnswer

    Regional wall colors: eleven regions, six named paints each, every one chosen to read as a whole wall. Use it to answer "paint this room like a Kyoto tea house" with a real color rather than an invented hex, then pass the hex to set_wall_color.

    View tool JSON
    {
      "name": "list_wall_palettes",
      "kind": "answer",
      "impl": "imperative",
      "description": "Regional wall colors: eleven regions, six named paints each, every one chosen to read as a whole wall. Use it to answer \"paint this room like a Kyoto tea house\" with a real color rather than an invented hex, then pass the hex to set_wall_color.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    get_styleAnswer

    Every finish in the room at once: the room default and any per-wall overrides, what each of the four walls actually resolves to and which named paint that is, the floor materials on offer, and the eleven regional palettes. Read it before repainting, so "make the other walls match" and "what colour is this" have an answer.

    View tool JSON
    {
      "name": "get_style",
      "kind": "answer",
      "impl": "imperative",
      "description": "Every finish in the room at once: the room default and any per-wall overrides, what each of the four walls actually resolves to and which named paint that is, the floor materials on offer, and the eleven regional palettes. Read it before repainting, so \"make the other walls match\" and \"what colour is this\" have an answer.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    set_wall_colorAction

    Paint the walls. Walls are named by where they sit on the plan — top, right, bottom, left — which is how the user sees them on screen, so ask for and confirm "the top wall", never "the north wall". With a wall named, only that wall changes and the other three keep whatever they had. Without one, every wall goes back to a single color and any per-wall overrides are cleared. Name the paint with swatch, as "Region/Name" from list_wall_palettes — "Japan/Aizome indigo" — or pass any hex as color.

    View tool JSON
    {
      "name": "set_wall_color",
      "kind": "act",
      "impl": "imperative",
      "description": "Paint the walls. Walls are named by where they sit on the plan — top, right, bottom, left — which is how the user sees them on screen, so ask for and confirm \"the top wall\", never \"the north wall\". With a wall named, only that wall changes and the other three keep whatever they had. Without one, every wall goes back to a single color and any per-wall overrides are cleared. Name the paint with swatch, as \"Region/Name\" from list_wall_palettes — \"Japan/Aizome indigo\" — or pass any hex as color.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "wall": {
            "type": "string",
            "description": "Which wall, named by where it sits on the plan: top, right, bottom or left. These are positions on the drawing the user is looking at, not compass directions — say \"the top wall\" back to them, not \"the north wall\"",
            "enum": [
              "top",
              "right",
              "bottom",
              "left"
            ]
          },
          "color": {
            "type": "string",
            "description": "Wall paint as hex, like #aabbcc"
          },
          "swatch": {
            "type": "string",
            "description": "A named paint as \"Region/Name\", from list_wall_palettes or get_style. An alternative to color"
          }
        }
      }
    }
    place_on_wallAction

    Hang a wall-mounted item — a print, a mirror, a wall shelf, hooks, a clock, curtains — flush on a wall at a given offset. Only items in the catalog's `wall` category can be hung; everything else stands on the floor and belongs to place_item. The x and y are worked out for you. offset is the distance along the wall to the near edge of the thing, measured from the left end of the top and bottom walls and from the top end of the left and right walls — the same ruler add_opening uses.

    View tool JSON
    {
      "name": "place_on_wall",
      "kind": "act",
      "impl": "imperative",
      "description": "Hang a wall-mounted item — a print, a mirror, a wall shelf, hooks, a clock, curtains — flush on a wall at a given offset. Only items in the catalog's `wall` category can be hung; everything else stands on the floor and belongs to place_item. The x and y are worked out for you. offset is the distance along the wall to the near edge of the thing, measured from the left end of the top and bottom walls and from the top end of the left and right walls — the same ruler add_opening uses.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "catalogId": {
            "type": "string",
            "description": "Catalog id of a wall-category item, from get_catalog"
          },
          "wall": {
            "type": "string",
            "description": "Which wall, named by where it sits on the plan: top, right, bottom or left. These are positions on the drawing the user is looking at, not compass directions — say \"the top wall\" back to them, not \"the north wall\"",
            "enum": [
              "top",
              "right",
              "bottom",
              "left"
            ]
          },
          "offset": {
            "type": "integer",
            "description": "Distance along the wall to the item near edge (cm)"
          },
          "mountHeight": {
            "type": "integer",
            "description": "Height from the floor to the bottom of the item. Defaults to the catalog mount height (cm)"
          }
        },
        "required": [
          "catalogId",
          "wall",
          "offset"
        ]
      }
    }
    get_shopping_listAnswer

    Everything placed in the room, grouped by catalog id into the list you would take shopping: quantity, unit price, line total, whether it is still to buy, and where it is coming from when someone has said. Sourcing is your job, not the user's: for every line without a source, search for the piece — online or near where the user lives, asking for their city if you need it — and record the shop and the listing with set_purchase_status, passing the catalogId. unsourced counts the lines still waiting for that. Every line carries a searchQuery you can hand straight to a shop or a search, and the room brief is included so you can respect the budget and the notes. status is one of to-buy, owned, ordered. Absent means to-buy: everything in a freshly drawn room is still to buy.

    View tool JSON
    {
      "name": "get_shopping_list",
      "kind": "answer",
      "impl": "imperative",
      "description": "Everything placed in the room, grouped by catalog id into the list you would take shopping: quantity, unit price, line total, whether it is still to buy, and where it is coming from when someone has said. Sourcing is your job, not the user's: for every line without a source, search for the piece — online or near where the user lives, asking for their city if you need it — and record the shop and the listing with set_purchase_status, passing the catalogId. unsourced counts the lines still waiting for that. Every line carries a searchQuery you can hand straight to a shop or a search, and the room brief is included so you can respect the budget and the notes. status is one of to-buy, owned, ordered. Absent means to-buy: everything in a freshly drawn room is still to buy.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    set_purchase_statusAnswer

    Record where a piece is coming from and whether it still needs buying. Pass catalogId to mark every copy of that piece at once — the usual case, since two identical chairs are bought together — or id to mark one placement. source is the shop, url the listing; both are optional and both are kept when you only change the status. status is one of to-buy, owned, ordered. Absent means to-buy: everything in a freshly drawn room is still to buy.

    View tool JSON
    {
      "name": "set_purchase_status",
      "kind": "answer",
      "impl": "imperative",
      "description": "Record where a piece is coming from and whether it still needs buying. Pass catalogId to mark every copy of that piece at once — the usual case, since two identical chairs are bought together — or id to mark one placement. source is the shop, url the listing; both are optional and both are kept when you only change the status. status is one of to-buy, owned, ordered. Absent means to-buy: everything in a freshly drawn room is still to buy.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "catalogId": {
            "type": "string",
            "description": "Catalog id, from get_shopping_list. Marks every placement of that piece"
          },
          "id": {
            "type": "string",
            "description": "A single placed item id, when only one of several copies is meant"
          },
          "status": {
            "type": "string",
            "description": "Where this piece stands",
            "enum": [
              "to-buy",
              "owned",
              "ordered"
            ]
          },
          "source": {
            "type": "string",
            "description": "The shop it is coming from, as a person would say it: \"IKEA Kungens Kurva\""
          },
          "url": {
            "type": "string",
            "description": "A link to the listing"
          }
        },
        "required": [
          "status"
        ]
      }
    }
    get_homeAnswer

    The floor plan the current room stands on: every room with its offset and size, the doorways between them, the bounding box, which room the front door is in, any room you cannot walk to from it, and totals for area, items and budget. Read it before moving a room or cutting a doorway, so the offsets you pass are relative to the same plan. `home` comes back null when the current room stands on no plan. Offsets are integer centimetres on the shared plan: x and y are the room's top-left corner, x growing right and y growing down. Rooms must touch edge to edge without overlapping — a placement within 20 cm of a neighbour's edge is pulled flush to it, which is how two rooms come to share a wall.

    View tool JSON
    {
      "name": "get_home",
      "kind": "answer",
      "impl": "imperative",
      "description": "The floor plan the current room stands on: every room with its offset and size, the doorways between them, the bounding box, which room the front door is in, any room you cannot walk to from it, and totals for area, items and budget. Read it before moving a room or cutting a doorway, so the offsets you pass are relative to the same plan. `home` comes back null when the current room stands on no plan. Offsets are integer centimetres on the shared plan: x and y are the room's top-left corner, x growing right and y growing down. Rooms must touch edge to edge without overlapping — a placement within 20 cm of a neighbour's edge is pulled flush to it, which is how two rooms come to share a wall.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    list_home_templatesAnswer

    The ready-made homes create_home can build: a key, a name, a blurb, the rooms with their offsets and sizes on the shared plan, and how many doorways come already cut between them. Rooms come furnished from the room templates, so a template home is a flat you can walk through the moment it is built.

    View tool JSON
    {
      "name": "list_home_templates",
      "kind": "answer",
      "impl": "imperative",
      "description": "The ready-made homes create_home can build: a key, a name, a blurb, the rooms with their offsets and sizes on the shared plan, and how many doorways come already cut between them. Rooms come furnished from the room templates, so a template home is a flat you can walk through the moment it is built.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    create_homeAction

    Start a floor plan. With a template key from list_home_templates the rooms are built furnished, stood on the plan and joined by their doorways, and the app switches to the room the front door is in. Without one you get an empty plan to put rooms on with add_room_to_home. Existing rooms are never disturbed: a room joins a home only when you add it.

    View tool JSON
    {
      "name": "create_home",
      "kind": "act",
      "impl": "imperative",
      "description": "Start a floor plan. With a template key from list_home_templates the rooms are built furnished, stood on the plan and joined by their doorways, and the app switches to the room the front door is in. Without one you get an empty plan to put rooms on with add_room_to_home. Existing rooms are never disturbed: a room joins a home only when you add it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name for the home, as a person would say it: \"Flat 3\""
          },
          "template": {
            "type": "string",
            "description": "Ready-made home key from list_home_templates",
            "enum": [
              "one-bedroom",
              "studio-hall"
            ]
          }
        }
      }
    }
    add_room_to_homeAction

    Stand a room on the floor plan. Pass roomId for a room that already exists, from list_rooms, or templateKey to build a furnished one from a room template first. The room goes on the plan the current room stands on; when it stands on none, a plan named after it is started and it is placed at the origin, so "put a kitchen to the right of this room" works from a single room. Offsets are integer centimetres on the shared plan: x and y are the room's top-left corner, x growing right and y growing down. Rooms must touch edge to edge without overlapping — a placement within 20 cm of a neighbour's edge is pulled flush to it, which is how two rooms come to share a wall. An overlap is refused with the room it ran into named and an offset that would work.

    View tool JSON
    {
      "name": "add_room_to_home",
      "kind": "act",
      "impl": "imperative",
      "description": "Stand a room on the floor plan. Pass roomId for a room that already exists, from list_rooms, or templateKey to build a furnished one from a room template first. The room goes on the plan the current room stands on; when it stands on none, a plan named after it is started and it is placed at the origin, so \"put a kitchen to the right of this room\" works from a single room. Offsets are integer centimetres on the shared plan: x and y are the room's top-left corner, x growing right and y growing down. Rooms must touch edge to edge without overlapping — a placement within 20 cm of a neighbour's edge is pulled flush to it, which is how two rooms come to share a wall. An overlap is refused with the room it ran into named and an offset that would work.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "roomId": {
            "type": "string",
            "description": "An existing room to stand on the plan, from list_rooms"
          },
          "templateKey": {
            "type": "string",
            "description": "Build a new furnished room from this room template instead of using roomId; keys from list_templates",
            "enum": [
              "living",
              "kitchen",
              "bedroom",
              "hall",
              "office",
              "dining",
              "kids",
              "studio"
            ]
          },
          "x": {
            "type": "integer",
            "description": "The room's left edge on the plan (cm)"
          },
          "y": {
            "type": "integer",
            "description": "The room's top edge on the plan (cm)"
          },
          "name": {
            "type": "string",
            "description": "Name for the new room, when templateKey is used. Defaults to the template name"
          }
        },
        "required": [
          "x",
          "y"
        ]
      }
    }
    move_roomAction

    Move a room to another offset on the floor plan it already stands on. Offsets are integer centimetres on the shared plan: x and y are the room's top-left corner, x growing right and y growing down. Rooms must touch edge to edge without overlapping — a placement within 20 cm of a neighbour's edge is pulled flush to it, which is how two rooms come to share a wall. An overlap is refused with the room it ran into named and an offset that would work. Doorways keep the offsets they were cut at, so any doorway the move pulls out of line is taken out of both rooms and named in removedDoorways; cut_doorway puts one back at the new offsets.

    View tool JSON
    {
      "name": "move_room",
      "kind": "act",
      "impl": "imperative",
      "description": "Move a room to another offset on the floor plan it already stands on. Offsets are integer centimetres on the shared plan: x and y are the room's top-left corner, x growing right and y growing down. Rooms must touch edge to edge without overlapping — a placement within 20 cm of a neighbour's edge is pulled flush to it, which is how two rooms come to share a wall. An overlap is refused with the room it ran into named and an offset that would work. Doorways keep the offsets they were cut at, so any doorway the move pulls out of line is taken out of both rooms and named in removedDoorways; cut_doorway puts one back at the new offsets.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "roomId": {
            "type": "string",
            "description": "Room id, from get_home or list_rooms"
          },
          "x": {
            "type": "integer",
            "description": "The room's left edge on the plan (cm)"
          },
          "y": {
            "type": "integer",
            "description": "The room's top edge on the plan (cm)"
          }
        },
        "required": [
          "roomId",
          "x",
          "y"
        ]
      }
    }
    remove_room_from_homeAction

    Take a room off the floor plan. The room itself survives with everything in it and can be worked on alone or added to another plan; only its place on this one goes. Its doorways go with it, which removes the matching opening from the rooms on the other side, so each of those rooms gets a ledger entry.

    View tool JSON
    {
      "name": "remove_room_from_home",
      "kind": "act",
      "impl": "imperative",
      "description": "Take a room off the floor plan. The room itself survives with everything in it and can be worked on alone or added to another plan; only its place on this one goes. Its doorways go with it, which removes the matching opening from the rooms on the other side, so each of those rooms gets a ledger entry.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "roomId": {
            "type": "string",
            "description": "Room id, from get_home or list_rooms"
          }
        },
        "required": [
          "roomId"
        ]
      }
    }
    cut_doorwayAction

    Open a doorway through the wall two rooms share, so you can walk from one into the other. A doorway needs a wall the two rooms actually share, and it is one hole in both of them: cutting it writes an opening and a ledger entry in each room, and remove_doorway takes both away again. offset is measured inside the room you name — from the left end of its top and bottom walls, from the top end of its left and right walls, the same ruler add_opening uses. Width defaults to 80 cm and kind to a door, which hangs a leaf swinging into the room you name; a passage is the same hole with no leaf. Name otherRoomId when more than one room lies behind that wall. A refusal lists the shared walls you can actually cut into, with the span of each in that room's own coordinates.

    View tool JSON
    {
      "name": "cut_doorway",
      "kind": "act",
      "impl": "imperative",
      "description": "Open a doorway through the wall two rooms share, so you can walk from one into the other. A doorway needs a wall the two rooms actually share, and it is one hole in both of them: cutting it writes an opening and a ledger entry in each room, and remove_doorway takes both away again. offset is measured inside the room you name — from the left end of its top and bottom walls, from the top end of its left and right walls, the same ruler add_opening uses. Width defaults to 80 cm and kind to a door, which hangs a leaf swinging into the room you name; a passage is the same hole with no leaf. Name otherRoomId when more than one room lies behind that wall. A refusal lists the shared walls you can actually cut into, with the span of each in that room's own coordinates.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "roomId": {
            "type": "string",
            "description": "The room to cut from, from get_home. The door swings into this one"
          },
          "wall": {
            "type": "string",
            "description": "Which wall, named by where it sits on the plan: top, right, bottom or left. These are positions on the drawing the user is looking at, not compass directions — say \"the top wall\" back to them, not \"the north wall\"",
            "enum": [
              "top",
              "right",
              "bottom",
              "left"
            ]
          },
          "offset": {
            "type": "integer",
            "description": "Distance along the wall to the near edge of the doorway (cm)"
          },
          "width": {
            "type": "integer",
            "description": "Doorway width, default 80 (cm)"
          },
          "kind": {
            "type": "string",
            "description": "door hangs a leaf that swings into roomId; passage is an open hole",
            "enum": [
              "door",
              "passage"
            ]
          },
          "otherRoomId": {
            "type": "string",
            "description": "Which neighbour to open into, when more than one room lies behind that wall"
          }
        },
        "required": [
          "roomId",
          "wall",
          "offset"
        ]
      }
    }
    remove_doorwayAction

    Close a doorway again, taking the opening out of both rooms at once and writing a ledger entry in each. Ids come from get_home. Undoing only one room's entry would leave a door onto a blank wall next door, so use this rather than undo when you want the wall back.

    View tool JSON
    {
      "name": "remove_doorway",
      "kind": "act",
      "impl": "imperative",
      "description": "Close a doorway again, taking the opening out of both rooms at once and writing a ledger entry in each. Ids come from get_home. Undoing only one room's entry would leave a door onto a blank wall next door, so use this rather than undo when you want the wall back.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Doorway id, from get_home"
          }
        },
        "required": [
          "id"
        ]
      }
    }
    apply_proposalAction

    Apply one open proposal by id, applying its ghosted changes to the room. Only call this when the user has explicitly chosen that option. Open proposals and their ids are listed by get_room.

    View tool JSON
    {
      "name": "apply_proposal",
      "kind": "act",
      "impl": "imperative",
      "description": "Apply one open proposal by id, applying its ghosted changes to the room. Only call this when the user has explicitly chosen that option. Open proposals and their ids are listed by get_room.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "proposalId": {
            "type": "string",
            "description": "Proposal id"
          }
        },
        "required": [
          "proposalId"
        ]
      }
    }
    withdraw_proposalAction

    Withdraw one of your open proposals by id.

    View tool JSON
    {
      "name": "withdraw_proposal",
      "kind": "act",
      "impl": "imperative",
      "description": "Withdraw one of your open proposals by id.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "proposalId": {
            "type": "string",
            "description": "Proposal id"
          }
        },
        "required": [
          "proposalId"
        ]
      }
    }
    apply_all_proposalsAction

    Apply every open proposal atomically, in order, as one ledger entry. Only when the user asked for all of them.

    View tool JSON
    {
      "name": "apply_all_proposals",
      "kind": "act",
      "impl": "imperative",
      "description": "Apply every open proposal atomically, in order, as one ledger entry. Only when the user asked for all of them.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    run_layout_scriptAction

    Run a JavaScript function body you write, in a sandboxed worker with no DOM access, to search for a layout programmatically. The body receives `api` with: api.room (shell, openings, items, brief), api.catalog (array of items with dimensions and prices), api.evaluate(placements) → { metrics, violations }, api.nearestValid(catalogId, x, y, rotation) → {x,y} | null, api.bestSpots(hour, count). It must `return` an array of placements ({ action: "place"|"move"|"remove"|"swap", catalogId, id, x, y, rotation }). The result becomes a labeled proposal for the user to accept. 2 second time limit.

    View tool JSON
    {
      "name": "run_layout_script",
      "kind": "act",
      "impl": "imperative",
      "description": "Run a JavaScript function body you write, in a sandboxed worker with no DOM access, to search for a layout programmatically. The body receives `api` with: api.room (shell, openings, items, brief), api.catalog (array of items with dimensions and prices), api.evaluate(placements) → { metrics, violations }, api.nearestValid(catalogId, x, y, rotation) → {x,y} | null, api.bestSpots(hour, count). It must `return` an array of placements ({ action: \"place\"|\"move\"|\"remove\"|\"swap\", catalogId, id, x, y, rotation }). The result becomes a labeled proposal for the user to accept. 2 second time limit.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "Name for the resulting proposal"
          },
          "code": {
            "type": "string",
            "description": "JavaScript function body"
          }
        },
        "required": [
          "label",
          "code"
        ]
      }
    }