feat(cli): claw run hands the run to the server, starting one if needed - #92
Merged
Conversation
The CLI stops opening a project db for a run: it locates the workspace's server (ServerClient over ServerLocator), starts one detached when none answers, and POSTs the issue's start. One process writes the db. Autospawn rebuilds the launch command from PHP_BINARY and CLAW_SERVER_EXTENSION and detaches it with setsid --fork so it outlives the CLI and holds none of its stdio. Verified live: cold autospawn, warm reuse, 409 on an already-active run, and a create-then-run cycle.
spawnCommand returns argv rather than a shell string, so it carries no quoting to platform-mismatch. launchDetached branches: POSIX uses 'setsid --fork', Windows uses proc_open's create_new_console/bypass_shell; stdio goes to files (/dev/null or NUL) either way. POSIX re-verified live; Windows is written to the API but unverified on this machine.
EdmondDantes
force-pushed
the
feat/cli-thin-client-run
branch
from
July 27, 2026 18:24
9f57ff0 to
2b429f8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The second slice of TODO item 2.
claw runstops opening a project db and running the solver in its own process; it becomes a thin client that hands the run to the workspace's server — the one process allowed to write.ServerClient(src/ServerClient.php):running()— a live server's address, or null.ensure()— that address, starting a server when none answers and waiting for it to come up.startRun()—POST /api/projects/{key}/issues/{id}/start, mapping 202 → ok, 409 → "already active", anything else → an error the CLI surfaces.runIssue()now resolves the issue, thenensure()+startRun()— noConfig, no agent, noIssueRunnerin the CLI process.Autospawn (cross-platform)
When no server answers, the CLI starts one. The launch command is rebuilt from
PHP_BINARYandCLAW_SERVER_EXTENSION(the server extension, defaulting totrue_async_server.so; on Windows a.dll, so set the env var), because the CLI itself runs without the server extension.spawnCommand()returns an argv list, not a shell string, so it carries no quoting to platform-mismatch.launchDetached()then branches:setsid --forkgives the server its own session and returns at once (without--fork, setsid execs the server in place andproc_closeblocks for its whole life — found by the CLI hanging in the live test).proc_openwithcreate_new_console+bypass_shell, cutting the server from the CLI's console so it survives the exit.Either way stdio is pointed at files (
/dev/nullorNUL) so the server never inherits — or blocks — the pipe the CLI was invoked through. The loser of a bind race exits on the duplicate-guard from #91, and the readiness poll finds the winner.Verified live (POSIX)
Against the real server extension on a Linux/WSL machine:
starting one…→ run launched, CLI returns in the same second;runfinds the running server, no respawn;a run for this issue is already active;claw -iopens an issue,claw runstarts it on the server (run row created, statusrunning).Windows is written to the API but unverified — no machine to run it on here.
Behaviour changes (intended)
claw run. The approval prompt was a human-approval gate the project does not want; the live trace returns in the next slice (pollGET …/runs/{id}/trace?since=+ answer the gate overPOST …/answer).claw runnow needs a server — one running, or the server extension available to start one. This is the "server becomes required" cost item 2 records and accepts.Not in this PR
/startreturning the run id, and the polling tail that renders the trace and drives the human gate (next slice).claw -i/-cstill write locally; folding the remaining writers behind the server is later work.Stacking
Based on
feat/server-discovery-file(#91), which adds theServerLocatorthis builds on. Retarget tomainonce #91 merges.Checks
composer qagreen — cs, PHPStan level 8, Testo (452 tests). Newtests/ServerClientTest.phpcovers the start status mapping, the target URL,running()on an empty workspace, and the spawn-argv shape.