POST /v1/agents/runtime/{runtime_id}/commands/run
run_cmd / runCmd accepts either a single shell string or a command plus an explicit args list:
sandbox.run_cmd(command="echo hello; sleep 1; echo world")
sandbox.run_cmd(command="ls", args=["-la", "/workspace"])
await sandbox.runCmd('echo hello; sleep 1; echo world');
await sandbox.runCmd('ls', { args: ['-la', '/workspace'] });
CLI timeout is in seconds (
--timeout 300). The REST API timeout field is in milliseconds (300000). The Python SDK takes seconds and converts for you.Basic Usage
from gravixlayer import GravixLayer
client = GravixLayer() # defaults to cloud="aws", region="us-east-1"
sandbox = client.runtime.create() # defaults to template="base-small"
# Single-string form
result = sandbox.run_cmd(command="ls -la /workspace")
print(result.stdout)
print(result.exit_code)
# Equivalent command + args form
result = sandbox.run_cmd(command="ls", args=["-la", "/workspace"])
print(result.stdout)
sandbox.kill()
import { GravixLayer } from 'gravixlayer';
const client = new GravixLayer(); // defaults to cloud="aws", region="us-east-1"
const sandbox = await client.runtime.create(); // defaults to template="base-small"
// Single-string form
const listed = await sandbox.runCmd('ls -la /workspace');
console.log(listed.stdout);
console.log(listed.exitCode);
const viaArgs = await sandbox.runCmd('ls', { args: ['-la', '/workspace'] });
console.log(viaArgs.stdout);
await sandbox.kill();
# Requires: GRAVIXLAYER_API_KEY, RT (running runtime id)
gravixlayer runtime exec "$RT" --workdir /workspace --timeout 300 -- ls -la /workspace
curl -sS -X POST "https://api.gravixlayer.ai/v1/agents/runtime/$RT/commands/run" \
-H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "ls",
"args": ["-la", "/workspace"],
"working_dir": "/workspace",
"timeout": 300000
}'
Install Packages
Guest egress is deny-by-default, sopip install needs a network policy. The example uses allow_all for a short demo; prefer an allowlist for PyPI in production.
import uuid
from gravixlayer import GravixLayer
client = GravixLayer() # defaults to cloud="aws", region="us-east-1"
policy = client.network_policies.create(
name=f"pypi-{uuid.uuid4().hex[:8]}",
egress_mode="allow_all",
description="Temporary egress for pip",
)
sandbox = client.runtime.create(network_policy_ids=[policy.id]) # defaults to template="base-small"
sandbox.run_cmd(command="pip", args=["install", "pandas", "--quiet"])
result = sandbox.run_cmd(
command="python",
args=["-c", "import pandas; print(pandas.__version__)"],
)
print(result.stdout)
sandbox.kill()
client.network_policies.delete(policy.id)
import { GravixLayer } from 'gravixlayer';
const client = new GravixLayer(); // defaults to cloud="aws", region="us-east-1"
const policy = await client.networkPolicies.create(`pypi-${Date.now()}`, {
egressMode: 'allow_all',
description: 'Temporary egress for pip',
});
const sandbox = await client.runtime.create({ networkPolicyIds: [policy.id] }); // defaults to template="base-small"
await sandbox.runCmd('pip', { args: ['install', 'pandas', '--quiet'] });
const result = await sandbox.runCmd('python', {
args: ['-c', 'import pandas; print(pandas.__version__)'],
});
console.log(result.stdout);
await sandbox.kill();
await client.networkPolicies.delete(policy.id);
gravixlayer runtime exec "$RT" -- pip install pandas --quiet
gravixlayer runtime exec "$RT" -- python -c 'import pandas; print(pandas.__version__)'
curl -X POST "https://api.gravixlayer.ai/v1/agents/runtime/$RT/commands/run" \
-H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "pip",
"args": ["install", "pandas", "--quiet"]
}'
Run Shell Scripts
from gravixlayer import GravixLayer
client = GravixLayer() # defaults to cloud="aws", region="us-east-1"
sandbox = client.runtime.create() # defaults to template="base-small"
# Single string — chained commands run in one shell invocation
result = sandbox.run_cmd(command="echo $HOME && python --version")
print(result.stdout)
# Equivalent with explicit shell invocation
result = sandbox.run_cmd(
command="sh",
args=["-lc", "echo $HOME && python --version"],
)
print(result.stdout)
sandbox.kill()
import { GravixLayer } from 'gravixlayer';
const client = new GravixLayer(); // defaults to cloud="aws", region="us-east-1"
const sandbox = await client.runtime.create(); // defaults to template="base-small"
// Single string — chained commands run in one shell invocation
const chained = await sandbox.runCmd('echo $HOME && python --version');
console.log(chained.stdout);
const viaShell = await sandbox.runCmd('sh', { args: ['-lc', 'echo $HOME && python --version'] });
console.log(viaShell.stdout);
await sandbox.kill();
gravixlayer runtime exec "$RT" -- sh -lc 'echo $HOME && python --version'
curl -X POST "https://api.gravixlayer.ai/v1/agents/runtime/$RT/commands/run" \
-H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "sh",
"args": ["-lc", "echo $HOME && python --version"]
}'
With Environment Variables
Setenv_vars at runtime creation so variables are available to every run_cmd / run_code call, or pass them per command:
from gravixlayer import GravixLayer
client = GravixLayer() # defaults to cloud="aws", region="us-east-1"
sandbox = client.runtime.create(env_vars={"APP_MODE": "production"}) # defaults to template="base-small"
result = sandbox.run_cmd(command="sh", args=["-lc", "echo APP_MODE=$APP_MODE"])
print(result.stdout) # APP_MODE=production
# Per-command environment (client API — not on the bound handle)
result = client.runtime.run_cmd(
sandbox.runtime_id,
command="sh",
args=["-lc", "echo $FOO"],
environment={"FOO": "bar"},
)
print(result.stdout)
sandbox.kill()
import { GravixLayer } from 'gravixlayer';
const client = new GravixLayer(); // defaults to cloud="aws", region="us-east-1"
const sandbox = await client.runtime.create({ envVars: { APP_MODE: 'production' } }); // defaults to template="base-small"
const result = await sandbox.runCmd('sh', { args: ['-lc', 'echo APP_MODE=$APP_MODE'] });
console.log(result.stdout); // APP_MODE=production
const perCommand = await sandbox.runCmd('sh', {
args: ['-lc', 'echo $FOO'],
environment: { FOO: 'bar' },
});
console.log(perCommand.stdout);
await sandbox.kill();
gravixlayer runtime exec "$RT" -e FOO=bar -- echo "$FOO"
curl -X POST "https://api.gravixlayer.ai/v1/agents/runtime/$RT/commands/run" \
-H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "sh",
"args": ["-lc", "echo $FOO"],
"environment": {"FOO": "bar"}
}'
Streaming Output
For long-running commands, passon_stdout / on_stderr / on_exit callbacks to receive output incrementally as the process produces it. The transport switches to Server-Sent Events transparently; the returned CommandRunResponse still carries the aggregated stdout/stderr/exit_code so existing code keeps working.
from gravixlayer import GravixLayer
client = GravixLayer() # defaults to cloud="aws", region="us-east-1"
sandbox = client.runtime.create() # defaults to template="base-small"
result = sandbox.run_cmd(
command="sh -lc 'for i in 1 2 3 4 5; do echo line-$i; sleep 1; done'",
on_stdout=lambda chunk: print(chunk, end="", flush=True),
on_stderr=lambda chunk: print(chunk, end="", flush=True),
on_exit=lambda code: print(f"\n[exit={code}]"),
)
print("final exit code:", result.exit_code)
print("duration:", result.duration_ms, "ms")
sandbox.kill()
import { GravixLayer } from 'gravixlayer';
const client = new GravixLayer(); // defaults to cloud="aws", region="us-east-1"
const sandbox = await client.runtime.create(); // defaults to template="base-small"
const result = await sandbox.runCmd(
"sh -lc 'for i in 1 2 3 4 5; do echo line-$i; sleep 1; done'",
{
onStdout: (chunk) => process.stdout.write(chunk),
onStderr: (chunk) => process.stderr.write(chunk),
onExit: (code) => console.log(`\n[exit=${code}]`),
},
);
console.log('final exit code:', result.exitCode);
console.log('duration:', result.durationMs, 'ms');
await sandbox.kill();
gravixlayer runtime exec "$RT" --stream -- sh -lc 'for i in 1 2 3 4 5; do echo line-$i; sleep 1; done'
curl -N -X POST "https://api.gravixlayer.ai/v1/agents/runtime/$RT/commands/run?stream=true" \
-H "Authorization: Bearer $GRAVIXLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"command": "sh",
"args": ["-lc", "for i in 1 2 3 4 5; do echo line-$i; sleep 1; done"]
}'
agent user inside the runtime. sudo is configured for the agent user with NOPASSWD, so commands like sudo apt-get install -y ... work without prompting.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
command | string | Yes | Command to execute. May be a single shell string or a program name. |
args | list[string] | No | Additional arguments appended to command. |
working_dir | string | No | Working directory. |
timeout | integer | No | Timeout in seconds (Python SDK / CLI). REST API uses milliseconds. |
environment | object | No | Per-command environment variables. |
on_stdout | callable(str) | No | Per-chunk stdout callback. Enables streaming mode. |
on_stderr | callable(str) | No | Per-chunk stderr callback. Enables streaming mode. |
on_exit | callable(int) | No | Final exit-code callback. Enables streaming mode. |
Response
| Field | Type | Description |
|---|---|---|
stdout | string | Standard output (aggregated when streaming) |
stderr | string | Standard error (aggregated when streaming) |
exit_code | integer | Process exit code |
duration_ms | integer | Execution duration in milliseconds |
success | boolean | True when exit code is 0 |
error | string | API-level error (if any) |