Skip to content

Add fold exec — run a command in a running machine - #3

Merged
blakebauman merged 1 commit into
feat/central-machine-logsfrom
feat/fold-exec
Jun 18, 2026
Merged

Add fold exec — run a command in a running machine#3
blakebauman merged 1 commit into
feat/central-machine-logsfrom
feat/fold-exec

Conversation

@blakebauman

Copy link
Copy Markdown
Owner

Context

Next operability gap after central logs (#2): there was no way to get into a deployed machine to inspect it — no exec, no ssh. For an agent runtime, "run a command inside my agent's machine" (ps, env, cat /data, curl localhost) is a core debugging primitive. This adds one-shot command exec.

Stacked on #2 (feat/central-machine-logs) because both extend the Runtime interface. Base will retarget to main once #2 merges; review the exec commit for this PR's changes in isolation.

What changed

  • Runtime gains Exec. The docker runtime implements it via docker exec (forwards stdin, surfaces the command's exit code). wasm (no shell), microVM, and firecracker return ErrExecUnsupported — microVM exec over vsock/ssh is roadmap.
  • Agent admin API serves POST /v1/machines/{id}/exec alongside the existing logs route, with a per-command timeout.
  • Control resolves the target machine (the named one, or the first running one), proxies to the owning host agent, and records an exec event + audit entry.
  • API: POST /v1/apps/{app}/exec, gated by the deploy scope.
  • CLI: fold exec [-a app] [--machine id] -- <cmd> prints combined output, forwards piped stdin, and exits with the command's exit code.

Scope

One-shot, buffered exec bounded by --timeout (default 60s). Interactive TTY sessions and long-lived streams (tail -f) are out of scope for this first version — they need bidirectional streaming (websocket/hijack) and can follow.

Tests

  • control: machine-target resolution — auto-picks a running+scheduled machine, rejects unscheduled/unknown ids, errors when none running
  • api: scope + validation — viewer JWT → 403, missing cmd → 400, valid request with no running machine → 502
  • agent: wasm Exec returns ErrExecUnsupported

Verification

  • gofmt -l clean · go vet ./... clean · go test ./... all pass · go build -tags firecracker ./... compiles
  • Manual (local docker deploy of hello-go): echo output, env/hostname (PORT=8080, m-0), stdin pipe (cat), and exit-code propagation (exit 7 → CLI exits 7) all verified

🤖 Generated with Claude Code

There was no way to get a shell into a deployed machine to inspect it —
a major DX gap for an agent runtime. This adds one-shot command exec.

- Runtime gains Exec; the docker runtime implements it via `docker exec`
  (stdin forwarded, exit code surfaced). wasm/microVM/firecracker return
  ErrExecUnsupported (no shell / vsock-or-ssh exec is roadmap).
- The host agent admin API serves POST /v1/machines/{id}/exec alongside
  the existing logs route, bounded by a per-command timeout.
- Control resolves the target machine (named, or the first running one),
  proxies to the host agent, and records an exec event + audit entry.
- API exposes POST /v1/apps/{app}/exec gated by the deploy scope.
- `fold exec [-a app] [--machine id] -- <cmd>` prints combined output,
  forwards piped stdin, and exits with the command's exit code.

Interactive TTY sessions and long-lived streams (tail -f) are out of
scope for this first version (one-shot, bounded by --timeout).

Tests: machine-target resolution (auto-pick running, reject unscheduled/
unknown), exec scope+validation (viewer 403, missing cmd 400, no running
machine 502), and the wasm-unsupported contract. Verified end-to-end with
a local deploy: output, env/hostname, stdin pipe, and exit-code 7.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@blakebauman
blakebauman merged commit 23e5c7d into feat/central-machine-logs Jun 18, 2026
0 of 2 checks passed
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