From 8e7f8c5f3b27092784582393691e204f0b954a5e Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Sun, 1 Nov 2026 18:24:35 +0100 Subject: [PATCH] fix(tooling): build first, then start the app, then list it The notes had agents start `crafter-build -r` in the background and run `crafter-debug ls --wait 60s` straight after. That raced the build: the first agent to follow them ran the plain build's stub, which said "no debug build yet" and exited, since the client `ls --wait` needs is one of the things the debug build compiles, and it polled by hand until the build was done. The race came from the order, so the order changes: build with the flag in the foreground, which ends once the app and the client are built, then start the app with -r in the background, then `ls --wait`, which now only waits for what it is for, the app registering. A launcher that polls for the build instead was tried and dropped: a shell loop that reruns itself each second, and waits out its whole --wait when no build is coming at all. The consumer notes, the client's guide and the README say so, and the stub and the not-yet-built launcher name the step that was skipped. Co-Authored-By: Claude Opus 5.5 --- README.md | 3 ++- implementations/Crafter.Debug.Cli-Client.cpp | 14 ++++++++------ tooling/AGENTS.consumer.md | 3 ++- tooling/interfaces/Crafter.Debug.Build.cppm | 4 ++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 5481d6b..247d77d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,8 @@ Runtime debugging for AI agents, and for people. An app built with Crafter.Debug Breakpoints and memory stay with a debugger; `crafter-debug debugger` prints how to attach one. ```console -$ crafter-build --debug-api -r & # the app's debug build, in the background +$ crafter-build --debug-api # the app's debug build, and the client with it +$ crafter-build --debug-api -r & # the app, in the background $ ./build/crafter-debug ls --wait 60s game id 4f1c09a2b7e3d851 pid 3 (sandbox 48211) up 4s port 41207 $ ./build/crafter-debug call Lobby_Start && ./build/crafter-debug wait --frames 30 diff --git a/implementations/Crafter.Debug.Cli-Client.cpp b/implementations/Crafter.Debug.Cli-Client.cpp index 3cbb467..bc4d041 100644 --- a/implementations/Crafter.Debug.Cli-Client.cpp +++ b/implementations/Crafter.Debug.Cli-Client.cpp @@ -974,13 +974,15 @@ memory are a debugger's job; `crafter-debug debugger` prints how to attach one. ## The loop -1. Build and start the app from its debug build, in the background (it does - not exit): `crafter-build --debug-api -r` (use the project's own flag). -2. `./build/crafter-debug ls --wait 60s` until it is listed. -3. `cmds` and `help ` to see what it offers, `get '*'` for its state. -4. Act and observe: `call`, `set`, `pause --when`, `wait`, `step`, `trace`, +1. Build with the debug flag, in the foreground: `crafter-build --debug-api` + (use the project's own flag). That build compiles this client too. +2. Start the app in the background, since it does not exit: + `crafter-build --debug-api -r`. +3. `./build/crafter-debug ls --wait 60s` until it is listed. +4. `cmds` and `help ` to see what it offers, `get '*'` for its state. +5. Act and observe: `call`, `set`, `pause --when`, `wait`, `step`, `trace`, `log --level warn`, `screenshot` (open the PNG it prints with Read). -5. `quit` when done. Killing the background task may leave the app running +6. `quit` when done. Killing the background task may leave the app running if crafter-build's alias lacks --die-with-parent; `ls` shows leftovers. ## Commands diff --git a/tooling/AGENTS.consumer.md b/tooling/AGENTS.consumer.md index 3d4e544..f44536b 100644 --- a/tooling/AGENTS.consumer.md +++ b/tooling/AGENTS.consumer.md @@ -4,7 +4,8 @@ This app can be driven while it runs: call its commands, read and set its state, ### Driving it -- Start the debug build in the background, since it does not exit: `crafter-build -r`. +- Build with the debug flag first, in the foreground: `crafter-build `. That build also compiles the client `./build/crafter-debug` runs. The first one takes a few minutes. +- Then start the app in the background, since it does not exit: `crafter-build -r`. - From the project directory, use `./build/crafter-debug`: - `ls --wait 60s` until it is listed; `status`, `cmds`, `help `, `get '*'` - `call key=value ...`, `set ` diff --git a/tooling/interfaces/Crafter.Debug.Build.cppm b/tooling/interfaces/Crafter.Debug.Build.cppm index 0c2aee6..00b8b43 100644 --- a/tooling/interfaces/Crafter.Debug.Build.cppm +++ b/tooling/interfaces/Crafter.Debug.Build.cppm @@ -87,7 +87,7 @@ namespace Crafter::Debug { "# project with {0}: runs the crafter-debug client that build compiled.\n" "client={1}\n" "if [ ! -x \"$client\" ]; then\n" - " echo \"crafter-debug: the client is not built yet; build with: crafter-build {0}\" >&2\n" + " echo \"crafter-debug: the client is not built yet; let crafter-build {0} finish first, which builds it with the app\" >&2\n" " exit 2\n" "fi\n", flag, ShellQuote(client.string())); @@ -113,7 +113,7 @@ namespace Crafter::Debug { return std::format( "#!/bin/sh\n" "# Written by Crafter.Debug (Debug::Use): this project has no debug build yet.\n" - "echo \"crafter-debug: no debug build yet; build with: crafter-build {}\" >&2\n" + "echo \"crafter-debug: no debug build yet; build with: crafter-build {0}, then start the app in the background with: crafter-build {0} -r\" >&2\n" "exit 2\n", flag); }