# LlamaIndex code interpreter tool in a secure sandbox Turn Runtime's sandbox functions into LlamaIndex `FunctionTool`s, and the agent's code runs in a microVM instead of on your server. **On Runtime the agent's code leaves your machine.** LlamaIndex's `CodeInterpreterToolSpec` calls `subprocess.run` on the host that runs the agent, and its own source warns that "arbitrary code execution is possible on the machine running this tool". Runtime's four tools send each command to a Firecracker microVM with its own kernel, Ubuntu 24.04 and Python 3.12, which starts in 351 ms at the median (24 September 2026) and costs $0.03125 an hour for 2 vCPU and 4 GiB while the agent waits on the LLM. llama-index-core 0.14.25 was the current PyPI release on 25 September 2026. ## The code tools LlamaIndex offers | Tool | Package | Where code runs | | -------------------------------- | ------------------------------------------ | ---------------------------------------- | | `CodeInterpreterToolSpec` | `llama-index-tools-code-interpreter` 0.6.0 | A `python -c` subprocess on your host | | Azure code interpreter tool spec | `llama-index-tools-azure-code-interpreter` | Azure Container Apps dynamic sessions | | Runtime `sandbox_tools` | `withruntime` | A Runtime microVM with a shell and files | The first is a single function, `code_interpreter(code)`, that runs Python with "access to any libraries the user has installed", in its docstring's words. Its class docstring says it "is not recommended to be used in a production setting, and would require heavy sandboxing or virtual machines". The Runtime tools are that virtual machine. ## Swap the tool ```bash no-run pip install llama-index-core withruntime ``` The agent from the [framework guide](/docs/frameworks#llamaindex): ```python check from llama_index.core.agent.workflow import FunctionAgent from llama_index.core.tools import FunctionTool from withruntime import Sandbox from withruntime.tools import sandbox_tools def coder(llm, sbx: Sandbox) -> FunctionAgent: return FunctionAgent(tools=[FunctionTool.from_defaults(fn=f) for f in sandbox_tools(sbx)], llm=llm) ``` `FunctionTool.from_defaults` reads each function's name, type hints and docstring, so the LLM sees `runtime_exec(command, cwd, timeout_seconds)` with its description. Any function-calling LLM class works, such as `llama_index.llms.openai.OpenAI`. ## Run the agent and watch its tool calls LlamaIndex agents are workflows: `agent.run(...)` returns a handler that streams events and can then be awaited for the answer. ```python check from llama_index.core.agent.workflow import ToolCallResult from withruntime import Sandbox async def answer(llm, question: str) -> str: with Sandbox.create( network={"internet": True, "allow": ["pypi.org", "*.pythonhosted.org"]}, timeout_seconds=900, on_lease_end="stop", ) as sbx: handler = coder(llm, sbx).run(user_msg=question) async for event in handler.stream_events(): if isinstance(event, ToolCallResult): print(event.tool_name, event.tool_kwargs) return str(await handler) ``` `coder` is the function above. Printing each `ToolCallResult` gives you an audit trail of every command the model ran in the sandbox. This loop was run on 25 September 2026 with llama-index-core 0.14.25 against a scripted OpenAI-style endpoint, with `streaming=False`: the call to `runtime_exec` reached the sandbox and its output reached the answer. ## Retrieval plus computation A common LlamaIndex agent answers from documents and then needs arithmetic the LLM should not do in its head. Give it a query engine tool and the sandbox tools together, and write the source data into the sandbox so the numbers come from a file, not from the prompt: ```python check from llama_index.core.agent.workflow import FunctionAgent from llama_index.core.tools import FunctionTool, QueryEngineTool from withruntime import Sandbox from withruntime.tools import sandbox_tools def analyst(llm, query_engine, sbx: Sandbox, csv_text: str) -> FunctionAgent: sbx.files.write("/workspace/sales.csv", csv_text) docs = QueryEngineTool.from_defaults( query_engine, name="handbook", description="The company's sales handbook." ) code = [FunctionTool.from_defaults(fn=f) for f in sandbox_tools(sbx)] return FunctionAgent( tools=[docs, *code], llm=llm, system_prompt="Definitions come from the handbook. Compute figures with Python on sales.csv.", ) ``` Files the agent writes stay in `/workspace` for the life of the sandbox, so a result saved in one step can be read back in the next, and your code can copy any file out with `sbx.files.read`. ## Guard rails The sandbox limits what code can do; the key limits what the application can spend. | Concern | Setting | | ------------------------------------------ | -------------------------------------------------------------------- | | Code reaching your network or the internet | `network={"internet": False}`, or an allow-list of hosts | | A sandbox left running | `timeout_seconds` with `on_lease_end="stop"` | | One expensive create | `max_cost_micros` refuses a first lease above your figure | | A runaway loop of creates | A daily spending limit on the key; past it, `spending_limit_reached` | | A token the code must use | A Runtime secret: the sandbox sees a placeholder, never the value | | A monitoring dashboard | A read-only key that cannot create, run or spend | Details are in [security](/docs/security) and [egress control](/glossary/egress-control). ## Which one to pick `CodeInterpreterToolSpec` is fine for a notebook on your own laptop with code you would run anyway. The Azure tool spec suits teams already on Azure that want Python cells. Runtime suits a hosted agent that takes questions from users, since a prompt injection then reaches a throwaway machine rather than your server, and the agent gets a shell, `pip` and files instead of one Python call. More: [a data analysis agent](/use-cases/data-analysis-agent), [a code interpreter for chatbots](/use-cases/code-interpreter-for-chatbots) and [run untrusted LLM code](/use-cases/run-untrusted-llm-code). New accounts get 50 free sandbox hours, no card: ```bash no-run npx withruntime sandbox run --trial -- python3 -c 'print(6 * 7)' ``` ## Sources - [LlamaIndex: Tools](https://developers.llamaindex.ai/python/framework/module_guides/deploying/agents/tools/), `FunctionTool.from_defaults` and `agent.run(user_msg=...)`, read 25 September 2026 - [llama-index-core on PyPI](https://pypi.org/project/llama-index-core/), version 0.14.25, read 25 September 2026 - [llama-index-tools-code-interpreter on PyPI](https://pypi.org/project/llama-index-tools-code-interpreter/), version 0.6.0; the warnings quoted are from its source, read 25 September 2026 - [llama-index-tools-azure-code-interpreter on PyPI](https://pypi.org/project/llama-index-tools-azure-code-interpreter/), read 25 September 2026 Facts on this page were checked on 25 September 2026.