Skip to content

Start Builders with no window when an agent connects - #19

Closed
oddessentials wants to merge 9 commits into
mainfrom
mcp-no-window-at-start
Closed

oddessentials wants to merge 9 commits into
mainfrom
mcp-no-window-at-start

Conversation

@oddessentials

Copy link
Copy Markdown
Owner

What changes

  • --headless -- --mcp now starts a windowless relay. It answers list_worlds and list_items itself and opens the Builders window on the first other tool call.
  • A new show_window tool opens the window or brings it to the front.
  • If the person closes the window, the next tool call opens a new one. A window that fails to start is reported and not relaunched for 10 seconds.
  • The relay's list_items reloads custom items another window changed.
  • When the agent disconnects, the relay tells the window with a notification instead of closing its pipe. Only a window the relay started acts on it, once.

The disconnect fix (refs #18)

The relay used to close the window's pipe while its reader thread was still reading it. On Windows, if the window wrote anything after that, every later read failed yet returned a byte, so the relay never quit, used a full CPU core and flooded stderr. The window had always saved and exited; the relay was what stayed behind.

Before the fix, on Windows, with a call in flight at disconnect: 6 of 26 runs hung.

Testing

  • tests/run.gd -- mcp: 221 passed, 0 failed.
  • Packaged Windows build, tests/mcp_smoke.mjs plain and --windowed: 11/11 each. The smoke test now disconnects with a call in flight.
  • Packaged Windows build, 50 in-flight disconnects with a headless window: 50 clean.
  • Packaged Windows build, 50 in-flight disconnects with a real window: no hangs and no stderr errors. In one run a process was still present about 0.3 seconds after the relay exited (exit 0, item saved); whether it would have exited by itself was not determined.
  • macOS: the last commit has not been run on a Mac. The macOS build job's smoke test covers it.

🤖 Generated with Claude Code

oddessentials and others added 9 commits November 11, 2026 17:31
The connect command now launches Builders headless. It answers the MCP
handshake, list_worlds and list_items itself, and starts the Builders
window only when a tool needs the editor or the agent calls the new
show_window tool. Closing the window keeps the agent connected; its next
call opens the window again.

Existing connections must be re-added with --headless to stop the window
appearing at every session start.

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

Only the window's first reply is dropped, and only when the relay sent it
an initialize, so a client id equal to the internal one still gets its
answer. show_window restores a minimized window and answers while a
render runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The relay closed the window's pipe while its reader thread was still
reading it. If the window wrote anything after that, every later read
failed yet returned a byte, so the relay never quit and flooded stderr.

The relay now sends the window a notification, which only a window the
relay started acts on, once. The reader ends when the window exits.

Refs #18

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Opening a Claude Code session must not open Builders. Keep the headless
relay, in low-processor mode, that answers list_worlds and list_items
itself, starts the window when a call needs the editor, and hands
disconnects to it.

Remove the show_window tool, the delay before relaunching a window that
failed to start, and reaping of exited window processes. Keep the full
page check after pushes to main, so the page can't go live before the
release it describes. Tell connected users how to replace a
registration without --headless.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On macOS and Linux, Godot collects a child's exit status only when its
process status is checked, so every window closed during a session stayed
a zombie until the relay exited. Keep its PID and check it each frame
until it has gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
macOS answers is_process_running for an app from NSRunningApplication
without calling waitpid, so a closed window could stay a zombie. Keep its
PID until get_process_exit_code reports it has exited, which collects it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant