Conversation
Three separate problems, each of which made a git operation either fail
outright or succeed in a way the caller could not act on. Found while
building a non-interactive CLI on top of this namespace.
updateConfig sent its request to /v2/box/{id}/git-config, which the
coordinator does not serve. The identity endpoint is /v2/box/{id}/config/git,
so every call returned 404 and no git identity was ever set through either
SDK. A unit test had pinned the wrong URL, so the suite agreed with the bug.
exec results now carry exit_code. The API has always returned it (see
shared/types.go GitExecResponse), but the type declared only output, so a
caller could not tell a failed git command from a successful one. Exit 128,
the code for "not a repository", was indistinguishable from success. This is
additive: the field was already on the wire.
clone accepts folder, naming the directory the repository is cloned into.
Every other git operation derives its folder from the tracked cwd via cd(),
but for clone the folder is the destination and does not exist yet, so cd()
fails on it. There was no way to express "clone into my-app" at all.
Both SDKs are covered. The Python SDK gets the route fix and the clone
folder, and is bumped to 0.3.1 with a changelog entry, since it does not go
through changesets. Its git.exec still returns a bare string and drops the
exit code; changing that is a breaking API change and belongs on its own.
This was referenced Aug 27, 2026
exec.stream() could finish without ever yielding an exit chunk, leaving a caller unable to tell whether the command succeeded. The `event: exit` marker and its `data:` payload do not always arrive in the same network read. When the marker completed one read, the parser matched the payload line with a pattern that does not require the line to be complete, failed to parse it, and then returned — ending the stream with no exit chunk and discarding the rest, including the flush that would have recovered it. It now requires a terminated data line before parsing, and keeps reading when the payload has not fully arrived. The lenient match on the stream-end flush path is unchanged, so a final event without a trailing newline still parses. Found from the CLI, where a command that reports no exit status is treated as a failure: `box exec -- true` failed roughly twice in thirty runs. Against a real box, 60 consecutive streams now carry an exit chunk; before, about one in thirty did not.
CI runs prettier --check per package and the new split-chunk tests were not formatted, which failed the JS test jobs on both Node versions.
CahidArda
approved these changes
Aug 28, 2026
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.
Three separate problems in the git namespace, each of which made an operation either fail outright or succeed in a way the caller could not act on. All three surfaced while building a non-interactive CLI on top of this namespace, where the failures are much harder to miss than they are from a REPL.
1.
updateConfig()always returned 404It sent its request to
/v2/box/{id}/git-config, which the coordinator does not serve. The identity endpoint is/v2/box/{id}/config/git, so no git identity was ever set through either SDK — every commit fell back to whatever the box was created with.A unit test had pinned the wrong URL, so the suite agreed with the bug. That test is corrected here rather than deleted.
2.
exec()dropped git's exit codeGitExecResultdeclared onlyoutput, but the API has always returnedexit_code— seeGitExecResponseinshared/types.go, which the coordinator passes straight through. The field was on the wire and thrown away by the type.The practical cost: exit
128, git's code for "not a repository", was indistinguishable from success. A caller runninggit rev-parsein the wrong directory got an empty string and no way to know why.This is purely additive — the value was already being returned.
3.
clone()could not name its destinationEvery other git operation derives its folder from the tracked cwd via
cd(). Clone is different: its folder is the destination, and it does not exist yet, socd()fails on it. There was no way to express "clone this repo intomy-app" at all.GitCloneOptions.foldernow maps onto thefolderthe agent already accepts (CloneRepoinbox-agent/internal/docker/client.gouses it as the clone destination). An explicit folder wins over the tracked cwd; without one, behaviour is unchanged.Scope
Both SDKs. The Python SDK gets the route fix and the clone folder, and is bumped to 0.3.1 with a CHANGELOG entry, since it does not go through changesets and would otherwise never publish these fixes.
Python's
git.exec()still returns a barestrand drops the exit code. Fixing that changes a public return type, so it is deliberately left for its own breaking change rather than smuggled in here.Verification
exit_codeforwarding (0 and 128), and the clone destination including precedence overcd().scripts/generate_sync.py.clone -C my-applanding inmy-app/, and exit 128 surfacing from a non-repository directory.Release note
A CLI PR depends on this one at runtime, not just at the type level: against the current published SDK,
folderon clone is silently dropped. This should land and publish first.