Skip to content

feat: enable piping on the e2b cli#1127

Merged
matthewlouisbrockman merged 44 commits intomainfrom
cli-command-piping-eng-3460
Feb 12, 2026
Merged

feat: enable piping on the e2b cli#1127
matthewlouisbrockman merged 44 commits intomainfrom
cli-command-piping-eng-3460

Conversation

@matthewlouisbrockman
Copy link
Copy Markdown
Contributor

@matthewlouisbrockman matthewlouisbrockman commented Feb 11, 2026

Adds stdin piping support to e2b sandbox exec, so users can do:

echo "data" | e2b sandbox exec <id> -- cat
cat file.bin | e2b sandbox exec <id> -- python3 -c 'import sys; print(len(sys.stdin.buffer.read()))'

Included:

  • JS SDK updates:
    • closeStdin()
    • supportsStdinClose
  • CLI updates:
    • detects piped stdin
    • streams stdin in 64 KiB chunks
    • closes remote stdin on EOF
  • graceful fallback for older sandbox versions (requires envd >= 0.5.2, warn + ignore piped input)

Example Usage

non-piped exec still works

  e2b sandbox exec <sandbox_id> -- 'echo backend-non-pipe'

piped stdin path (supported envd) should deliver bytes

  echo "hello" | e2b sandbox exec <sandbox_id> -- 'wc -c'   # expect 6
  printf '\x00\x01\x02\xff' | $e2b sandbox exec <sandbox_id> -- 'wc -c'  # expect 4

optional: legacy template behavior should warn + ignore piped stdin

  echo "hello" | e2b sandbox exec <legacy_sandbox_id> -- 'wc -c' # expect 0 + "Ignoring piped stdin."

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 86d629264d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/cli/src/commands/sandbox/exec.ts Outdated
Comment thread packages/cli/src/commands/sandbox/exec.ts Outdated
@matthewlouisbrockman
Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@sitole sitole self-requested a review February 11, 2026 23:34
Comment thread .changeset/fiery-cooks-visit.md Outdated
@matthewlouisbrockman matthewlouisbrockman merged commit 87ceec2 into main Feb 12, 2026
16 of 17 checks passed
@matthewlouisbrockman matthewlouisbrockman deleted the cli-command-piping-eng-3460 branch February 12, 2026 00:18
Comment on lines +27 to +53
const userConfig = safeGetUserConfig() as UserConfigWithDomain | null
const domain =
process.env.E2B_DOMAIN ||
userConfig?.E2B_DOMAIN ||
userConfig?.domain ||
'e2b.app'
const apiKey = process.env.E2B_API_KEY || userConfig?.teamApiKey
const templateId =
process.env.E2B_PIPE_TEMPLATE_ID ||
process.env.E2B_TEMPLATE_ID ||
'base'
const isDebug = process.env.E2B_DEBUG !== undefined
const hasCreds = Boolean(apiKey)
const shouldSkip = !hasCreds || isDebug
const testIf = test.skipIf(shouldSkip)
const includeLargeBinary =
process.env.E2B_PIPE_INTEGRATION_STRICT === '1' ||
process.env.E2B_PIPE_INTEGRATION_BINARY === '1' ||
process.env.E2B_PIPE_SMOKE_STRICT === '1' || // Backward compatibility.
process.env.E2B_PIPE_SMOKE_BINARY === '1' || // Backward compatibility.
process.env.STRICT === '1'
const sandboxTimeoutMs = parseEnvInt('E2B_PIPE_SANDBOX_TIMEOUT_MS', 10_000)
const testTimeoutMs = parseEnvInt('E2B_PIPE_TEST_TIMEOUT_MS', 60_000)
const defaultCmdTimeoutMs = parseEnvInt(
'E2B_PIPE_CMD_TIMEOUT_MS',
Math.min(8_000, testTimeoutMs)
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please refactor this

}
}

async function killProcessBestEffort(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is unnecessary function

}
type FsLike = { fstatSync: (fd: number) => StatLike }

export const isPipedStdin = (fd = 0, fsModule: FsLike = fs as FsLike) => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a fan of passing around modules here (fs)

Comment on lines +239 to +275
function sandboxExistsInList(
output: string | Buffer | null | undefined,
sandboxId: string
): boolean {
const text = bufferToText(output).trim()
if (!text) {
return false
}

const parsed = JSON.parse(text) as Array<{ sandboxId?: string }>
return parsed.some((item) => item.sandboxId === sandboxId)
}

function bufferToText(value: Buffer | string | null | undefined): string {
if (!value) {
return ''
}
return typeof value === 'string' ? value : value.toString('utf8')
}

function parseEnvInt(name: string, fallback: number): number {
const raw = process.env[name]
if (!raw) {
return fallback
}
const parsed = Number.parseInt(raw, 10)
return Number.isFinite(parsed) ? parsed : fallback
}

function safeGetUserConfig(): ReturnType<typeof getUserConfig> | null {
try {
return getUserConfig()
} catch (err) {
console.warn(`Failed to read ~/.e2b/config.json: ${String(err)}`)
return null
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd avoid small helper functions unless you plan to re-use them anywhere else

@mishushakov
Copy link
Copy Markdown
Member

please lower the vibes a little bit on the tests. it's fine we just do integration tests on the CLI, no need for mock/units here.

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.

4 participants