Skip to content

mcp: clear_scene, an agent empties a project on purpose - #1012

Merged
wass08 merged 6 commits into
pascalorg:mainfrom
AxiomeCG:fix/clear-scene
Oct 7, 2026
Merged

wass08 merged 6 commits into
pascalorg:mainfrom
AxiomeCG:fix/clear-scene

Conversation

@AxiomeCG

@AxiomeCG AxiomeCG commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer guide: clearing a project on purpose

Merge order: this PR first, then pascalorg/private-editor#848, which points its submodule here.

On editor main (2026-10-06): d92eb5a merges main a860e19 (#915, #1000, #996). The tool lists follow main's: read-tool-annotations.test.ts compares names with the policy lists, and the policy count is main's 73 plus clear_scene. fa483f1 is comment-only.

What changes for a user (an agent on the MCP or in the hosted chat):

  • clear_scene empties the project on purpose, back to the default scaffold: a site, a building and one level of the standard storey height. The agent calls it when the person asked to start over, and says what they asked in reason.
  • A store may refuse a write that would leave a populated project empty, which is far more often an accident (a client that never finished loading, a deletion of everything) than an intent. The hosted store does. The MCP now answers that refusal as scene_wipe_blocked with its code, instead of a generic failure, and the session goes back to the project as stored: before, it kept the refused write, so deleting the only room was refused yet the room was gone from the agent's session, and its next writes built on a scene the project didn't hold. The message fits a deliberate deletion as well as an accident: "This write would leave the project empty, so it was blocked and nothing changed. To empty the project on purpose, call clear_scene. To remove only part of it, such as its only room, build what replaces it first, then remove it."
  • A store with no such guard (the local SQLite store) saves as before; clear_scene works there too.

How to test:

  1. bun install && bun run ci on this branch.
  2. bun test packages/mcp/src/tools/clear-scene.test.ts: clear_scene empties a house and the next create_wall lands on the scaffold; an apply_patch deleting the site is refused scene_wipe_blocked, nothing is saved and the session keeps the house; delete_zone on a one-room project's room is refused, the session keeps the room, and the next create_wall leaves the store and the session equal.
  3. With pascalorg/private-editor#848: the hosted MCP and the chat, by hand and by agent (its QA).

What to read:

  • packages/core/src/agent-tools/clear-scene.ts: the contract;
  • packages/mcp/src/tools/clear-scene.ts: the tool;
  • packages/mcp/src/tools/live-sync.ts: allowSceneWipe passed to the store; on SceneWipeBlockedError the stored scene is loaded back into the session, then the refusal is answered. Other refused live-sync writes (a version conflict, a store failure) keep their behaviour.

What to skim: packages/mcp/src/storage/types.ts (allowSceneWipe, SceneWipeBlockedError, a SceneInvalidError so callers that know only that keep working), apply-patch.ts (a store's refusal returned with its code), the tool list and README row.

What to ignore: the tests, plugin-evals/tool-annotation-justifications.json and scripts/openai-tool-annotation-policy* (the new tool's annotations).


What does this PR do?

Adds clear_scene, one shared agent tool (core contract, in AGENT_TOOL_CONTRACTS), the only way for an agent to empty a project on purpose:

  • The MCP tool resets the scene to the host's default scaffold (setScene({}, []) then loadDefault()) and persists it through live sync with the new SceneSaveOptions.allowSceneWipe. It answers { cleared: { removed }, version, graphHash } with the usual live-sync fields. Destructive annotation.
  • SceneWipeBlockedError (a SceneInvalidError) is what a store throws when it refuses an emptying write without allowSceneWipe. Live sync loads the stored scene back into the session (as load_scene does), then answers the refusal scene_wipe_blocked with mutationApplied: false; when the stored scene can't be read back, it says to call load_scene before writing again. apply_patch returns that refusal with its code, as the shared tools return theirs.
  • The local SQLite store has no wipe guard; nothing changes there.

No schema change; old scenes load as before.

How to test

  1. bun install && bun run ci: lint, skills validation, type checks, tests and build pass.
  2. bun test packages/mcp/src/tools/clear-scene.test.ts packages/mcp/src/tools/read-tool-annotations.test.ts.
  3. Build the MCP and connect a client: tools/list has clear_scene with destructiveHint: true; on a project with walls, clear_scene { reason: "start over" } leaves the site, building and level.

Screenshots / screen recording

N/A: no visual change.

Checklist

  • I've tested this locally with bun dev
  • My code follows the existing code style (run bun check to verify)
  • I've updated relevant documentation (if applicable)
  • This PR targets the main branch

🤖 Generated with Claude Code


Note

High Risk
Destructive project-wide reset plus new persistence guard behavior on all mutating live-sync writes; incorrect wipe detection or failed session restore could block saves or desync agent sessions from stored projects.

Overview
Adds clear_scene as the shared agent/MCP tool for intentionally resetting a project to the default scaffold (site, building, one level), with a required reason and persistence via allowSceneWipe. Installed plugins are preserved; undo history is cleared.

Stores that guard against accidental wipes can refuse emptying writes without that flag via SceneWipeBlockedError. Live sync now reloads the stored graph into the session on that error and returns scene_wipe_blocked (pointing agents to clear_scene) instead of leaving a refused mutation in memory; apply_patch surfaces the same refusal shape as other agent refusals.

Docs, destructive tool annotations, and policy inventories are updated for the new tool (74-tool count).

Reviewed by Cursor Bugbot for commit b288c19. Bugbot is set up for automated code reviews on this repo. Configure here.

…pe is refused with its code

A store may refuse a write that would empty a populated project, which is
an accident far more often than an intent (a client that never finished
loading, a deletion of everything), and the hosted store does. An agent
then had no way to start over on purpose.

clear_scene, one contract in core: the scene goes back to the host's
default scaffold (a site, a building, a level) and is saved with
allowSceneWipe, a new save option. A store that refuses a wipe throws
SceneWipeBlockedError; live sync answers it as the refusal
scene_wipe_blocked, naming clear_scene, and apply_patch returns it with
its code as the shared tools do. A store with no guard saves as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pascal

pascal Bot commented Oct 6, 2026

Copy link
Copy Markdown

What this PR does

Adds clear_scene, a single agent tool that empties a project back to the default scaffold (site, building, one level) on purpose, and makes accidental wipes a named refusal instead of a generic error. The tool resets the scene and saves it with a new SceneSaveOptions.allowSceneWipe flag; a store that guards against emptying writes (the hosted one does, the local SQLite one doesn't) throws SceneWipeBlockedError, and live sync answers that as the refusal scene_wipe_blocked pointing the agent at clear_scene. apply_patch now returns store refusals with their code. No schema change. The description notes this lands before pascalorg/private-editor#848, which points its submodule here.

File Change What changed
packages/core/src/agent-tools/clear-scene.ts added The shared contract: name, title, description, reason input
packages/core/src/agent-tools/index.ts modified Exports the contract and adds it to AGENT_TOOL_CONTRACTS
packages/mcp/src/storage/types.ts modified allowSceneWipe on SceneSaveOptions; SceneWipeBlockedError extending SceneInvalidError
packages/mcp/src/tools/clear-scene.ts added The MCP tool: setScene({}, []) + loadDefault(), saved with allowSceneWipe, destructive annotation
packages/mcp/src/tools/live-sync.ts modified publishLiveSceneSnapshot takes allowSceneWipe; turns SceneWipeBlockedError into the scene_wipe_blocked refusal
packages/mcp/src/tools/apply-patch.ts modified Returns a store refusal with its code instead of a generic invalid-params error
packages/mcp/src/tools/index.ts modified Registers the new tool
packages/mcp/src/tools/clear-scene.test.ts added Clears a house onto the scaffold, next write lands; an accidental delete is refused and nothing saves
packages/mcp/src/tools/read-tool-annotations.test.ts modified Tool count 71 → 72, clear_scene in the destructive policy group
packages/mcp/README.md modified Tool table row for clear_scene
plugin-evals/tool-annotation-justifications.json modified Annotation justifications for the new tool
scripts/openai-tool-annotation-policy.ts modified clear_scene: policy(false, true, false)
scripts/openai-tool-annotation-policy.test.ts modified Expected inventory 71 → 72

Start with packages/mcp/src/storage/types.ts and live-sync.ts to see the refusal contract, then packages/mcp/src/tools/clear-scene.ts and its test; the annotation and README files are mechanical follow-on.

AxiomeCG and others added 3 commits October 6, 2026 21:34
… is stored

The store refused a write that would leave the project empty, but the
session had already applied it, so the agent's next writes built on a scene
the project did not hold: deleting the only room it built (delete_zone) was
refused, and the room was gone from the session only. Live sync now loads
the stored scene back into the session before it answers
scene_wipe_blocked, and the refusal fits a deletion as well as an
accident: "This write would leave the project empty, so it was blocked and
nothing changed. To empty the project on purpose, call clear_scene. To
remove only part of it, such as its only room, build what replaces it
first, then remove it." When the stored scene cannot be read back, it says
to call load_scene before writing again.

Other refused live-sync writes (a version conflict, a store failure) keep
their behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main wins: its annotation test compares the registered tools with the
policy lists, so this branch's tool count goes, and clear_scene stays in
the destructive list; the annotation packet's inventory is main's 73 plus
clear_scene.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@AxiomeCG
AxiomeCG marked this pull request as ready for review October 6, 2026 20:42

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread packages/mcp/src/tools/clear-scene.ts
Resetting to the host's scaffold with setScene and loadDefault dropped the
plugin install state on every host, so the saved, cleared project lost its
plugins, where the editor's own clear keeps them. The scaffold is applied
again with the plugin state before it is saved. As load_scene does, the
reset leaves no undo history in the session.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e616b48. Configure here.

Comment thread packages/mcp/src/tools/clear-scene.ts
Without installed plugins the reset kept its undo history, so an undo after
clear_scene landed on the empty intermediate (or the old scene) and the
next save persisted it, on a store with no wipe guard too. The history is
now cleared after every reset, as the editor's own clear does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wass08
wass08 merged commit 9d3b503 into pascalorg:main Oct 7, 2026
5 checks passed
AxiomeCG added a commit to AxiomeCG/editor that referenced this pull request Oct 7, 2026
… warning (pascalorg#1013) into the sync bundle

Union with main's clear_scene (pascalorg#1012): its contract and registration sit beside
the foundation's tools; live sync keeps the foundation's { status, project }
answer and main's deliberate wipe path; apply_patch answers a store's refusal
with its code, then rethrows MCP errors; the annotation count is computed from
the policy, which lists clear_scene.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants