> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ploterr.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent building workflow

> Validate an agent's building JSON, open an editable project, apply a door proposal, and save the design without losing history.

export const LiveExample = ({path, title = 'Live example', height = 460}) => {
  return <Frame>
      <iframe src={`https://floorkit-examples.ploterr.com/floorkit/${path}?embed=1`} ref={frame => {
    if (!frame || !['localhost', '127.0.0.1'].includes(window.location.hostname)) return;
    const local = `http://localhost:5555/${path}?embed=1`;
    if (frame.src !== local) frame.src = local;
  }} title={title} loading="lazy" allow="fullscreen" style={{
    width: '100%',
    height: `${height}px`,
    border: 0,
    display: 'block'
  }} />
    </Frame>;
};

An agent proposes data. Floorkit checks that data and builds the geometry. Your app then lets people edit the same project. This guide shows that boundary without choosing an AI provider.

## Before you start

* Complete the [quickstart](/floorkit/quickstart) in a browser app on `localhost`.
* Your app supplies the AI model, parses its response as JSON, and treats the result as `unknown`.
* Give the agent the [building model contract](/floorkit/concepts/building-model) and the requested dimensions, in metres.

Start the geometry kernel once when your app starts:

```typescript theme={null}
import {
  assertValidBuildingModel,
  Floorkit,
  ProjectManager,
  validateBuildingModel,
} from '@opengeometry/floorkit';
import wasmURL from 'opengeometry/opengeometry_bg.wasm?url';

export async function initialize(): Promise<void> {
  await new Floorkit().setupOpenGeometry(wasmURL);
}
```

A deployed app also needs a valid key before views and exports. See [Licensing](/floorkit/licensing).

## Ask for building data

For the room in the quickstart, give your agent a request such as:

```text theme={null}
Describe a room with a six-by-four-metre wall centre line and a three-metre storey height.
Use metre units, Y up, and [x, z] plan points. Do not repeat the first point of a closed wall.
Use building ID "building", storey ID "ground", and wall ID "outer-walls".
Add a door with ID "front-door", width 0.9 m, height 2.1 m, and offset 1.5 m along the wall.
Return building JSON using the Floorkit BuildingModel contract, not meshes or SVG.
```

The [quickstart](/floorkit/quickstart) supplies a complete valid document for this request. Use it as a known example before connecting your model provider.

## Return validation feedback

Validate the parsed result. Send the returned issues to your agent if the document is invalid.

```typescript theme={null}
export function checkCandidate(input: unknown) {
  const result = validateBuildingModel(input);
  return {
    ok: result.ok,
    errors: result.errors,
    warnings: result.warnings,
  };
}
```

Each issue has a `path`, a `code`, and a `message`. For example, an opening that extends past its wall is rejected. Ask the agent to correct the reported fields and validate again. Limit retries in your app and show unresolved errors to the person.

Do not accept a TypeScript cast as validation. Do not invent missing IDs, change units, or remove an invalid element silently to make the document pass.

## Open the proposed project

After initialization, this function checks unknown input and creates a project with a plan of its first storey:

```typescript theme={null}
export function openCandidate(input: unknown): ProjectManager {
  const buildingModel = assertValidBuildingModel(input);
  const storey = buildingModel.buildings[0]?.storeys[0];
  if (!storey) throw new Error('The proposal needs a building with a storey.');
  return new ProjectManager({
    schema: 'floorkit.project',
    version: 3,
    buildingModel,
    views: [
      {
        id: 'agent-plan',
        name: 'Agent plan',
        kind: 'plan',
        storeyId: storey.id,
        cutHeightAboveStorey: 1.2,
      },
    ],
    paper: { version: 1, unitSystem: 'metric', sheets: [] },
  });
}
```

A document that passes validation can still fail to build its geometry. Catch the error from `openCandidate` and keep the previous project open until the new one succeeds. A `BmBuildError` includes a path and a code; other build failures can be ordinary errors.

Add `manager.root` to your Three.js scene. For a plan that people can edit, call `await manager.mountPlanEditor(container, 'agent-plan')`. The container needs a width and height. See [Add a plan editor](/floorkit/guides/add-a-plan-editor).

## Apply a small edit proposal

Keep the current manager when the user asks to move a door. Your app chooses the door target from the current model or selection. The agent proposes only the new offset:

```json theme={null}
{ "offset": 2.5 }
```

Capture `manager.revision` before you send the request to the agent. Pass that number back when the response arrives. The host checks it before applying the edit:

```typescript theme={null}
export interface DoorTarget {
  buildingId: string;
  storeyId: string;
  wallId: string;
  openingId: string;
}

export function applyDoorProposal(
  manager: ProjectManager,
  target: DoorTarget,
  input: unknown,
  expectedRevision: number,
): number {
  if (manager.revision !== expectedRevision) {
    throw new Error('The project changed. Request a new proposal from the current state.');
  }
  if (
    typeof input !== 'object' ||
    input === null ||
    !('offset' in input) ||
    typeof input.offset !== 'number' ||
    !Number.isFinite(input.offset) ||
    Object.keys(input).length !== 1
  ) {
    throw new Error('The proposal must contain only a finite numeric offset.');
  }
  return manager.apply({
    kind: 'move-hosted-opening',
    ...target,
    offset: input.offset,
  });
}
```

For the quickstart model, the target is `building`, `ground`, `outer-walls`, and `front-door`. The offset is measured in metres along that wall from its first point. Floorkit checks that the door fits between the joints of the wall and does not overlap another opening. A refused move has an `opening-does-not-fit` issue with the offsets where the door fits. If a door of the opened model does not fit at its saved offset, `manager.session.currentBuild.warnings` has an `opening-does-not-fit` warning with the same numbers. Give the agent its `openingFit.nearestOffset`; do not compute the fit in your app.

The revision comparison above belongs to your host application: `ProjectManager.apply` takes one command, not an expected revision argument. There is no `await` between the comparison and the edit. If you use `BuildingSession` directly, its `apply` takes the originating session revision. See [Editing and history](/floorkit/concepts/editing-and-history#the-revision-number).

An accepted proposal is one step in the manager's history. Use `manager.undo()` and `manager.redo()` for that same history. A rejected command leaves the saved model unchanged. Use the error's path and code when available; do not replace the whole project to hide a rejected edit.

## Save and reopen

Save on a user action or a timer, rather than after every frame:

```typescript theme={null}
export function saveDesign(manager: ProjectManager): string {
  return manager.save();
}

export function reopenDesign(text: string): ProjectManager {
  return ProjectManager.open(text);
}
```

Your app stores the text. Reopening needs the kernel to be initialized and starts a new undo history. Before closing a project, remove its root from your scene and call `manager.dispose()`.

To produce drawings, [compose a sheet](/floorkit/guides/compose-a-sheet) and [export a PDF](/floorkit/guides/export-a-pdf). A GLB or PDF does not preserve the editable building document; keep the project file too.

## Let people continue editing

The plan and 3D editors use the same project as the agent. Both change the building through commands, so the person can inspect, adjust, undo, and save the result.

<LiveExample path="guides/add-a-plan-editor" />

This existing example shows the plan editor you can connect to the workflow. It does not call an AI model.

For agent documentation access, see [Build with agents](/floorkit/agents/index). For other application routes, see [What you can build](/floorkit/use-cases).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.