feat(envd): persist command output and add per-command log retrieval#2935
feat(envd): persist command output and add per-command log retrieval#2935mishushakov wants to merge 5 commits into
Conversation
Commands started via envd now get a unique cid that is returned in the
StartEvent and stamped on every stdout/stderr log line, so their output is
persisted through the existing Loki pipeline and capped per command. Adds
GET /v2/sandboxes/{sandboxID}/commands/{cid}/logs to retrieve a single
command's output, with the cid filter threaded through the local Loki query
and the remote edge contract.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR SummaryMedium Risk Overview Reviewed by Cursor Bugbot for commit 9eef414. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Code Review
In packages/api/internal/handlers/command_logs.go, the expression new(time.UnixMilli(*params.Cursor)) is invalid Go syntax because new expects a type rather than a value. This will cause a compilation error, which can be resolved by converting the timestamp to a time.Time value first and then taking its address.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| var cursor *time.Time | ||
| if params.Cursor != nil { | ||
| cursor = new(time.UnixMilli(*params.Cursor)) | ||
| } |
There was a problem hiding this comment.
The expression new(time.UnixMilli(*params.Cursor)) is invalid Go syntax because new expects a type rather than a value or function call. To resolve this compilation error, convert the timestamp to a time.Time value first and then assign its address to the cursor pointer.
| var cursor *time.Time | |
| if params.Cursor != nil { | |
| cursor = new(time.UnixMilli(*params.Cursor)) | |
| } | |
| var cursor *time.Time | |
| if params.Cursor != nil { | |
| t := time.UnixMilli(*params.Cursor) | |
| cursor = &t | |
| } |
❌ 3 Tests Failed:
View the top 1 failed test(s) by shortest run time
View the full list of 2 ❄️ flaky test(s)
To view more test analytics, go to the Test Analytics Dashboard |
The cid is stamped on process_start/process_end lifecycle lines too, so filtering by cid alone returned them alongside output. Add an event_type=process_output filter so the command-logs endpoint returns only stdout/stderr. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the envd-assigned cid (and its proto changes); commands are already
identified by the pid returned in StartEvent. Output lines are now stamped
with pid, and the retrieval endpoint becomes
GET /v2/sandboxes/{sandboxID}/commands/{pid}/logs with start/end query params.
The time window disambiguates a reused pid: within [start, end] a pid maps to
a single command execution. Filter stays scoped to event_type=process_output.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 28467c0. Configure here.

Commands started via envd previously had their stdout/stderr discarded once no client was streaming. This persists each command's output through the existing envd → Loki log pipeline as
process_outputlines, stamped with the command'spidand capped per command (with a truncation marker). A newGET /v2/sandboxes/{sandboxID}/commands/{pid}/logsendpoint retrieves a single command's output, filtered bypid+event_type=process_outputwithin astart/endtime window — the window disambiguates a reused pid, since within[start, end]a pid maps to one execution. Thepidis already returned inStartEvent, so no proto change is needed; the envd version is bumped (0.6.1 → 0.6.2) for the output-persistence behavior. PTY/interactive sessions are out of scope; includes unit tests for output line-buffering/cap and the pid query filter.🤖 Generated with Claude Code