execute_code vs terminal: Choosing the Lower-Risk Tool

+15 Mana ✨

Introduction

It is tempting to think terminal is the only way to run code. Hermes also ships execute_code, which runs Python in a sandboxed environment with access to Hermes tools. For many tasks, execute_code is a strictly better choice: same flexibility, smaller blast radius, fewer approval prompts. Knowing when to pick which is part of being a fluent operator.

Key Concepts

  • execute_code: Runs a Python script in a sandbox. The script can call other Hermes tools (read files, search the web) and combine results.
  • terminal: Runs an arbitrary shell command.
  • Sandboxing: The boundary that limits what code can reach. execute_code is sandboxed by default; terminal is not (unless you use a container backend).
  • Tool composition: Calling multiple tools from within one tool call. execute_code is the cleanest way to compose tools when you need imperative logic between calls.

Real World Context

If the agent needs to fetch three URLs, parse JSON from each, and emit a CSV, it has two choices: run three web_extract calls and reason about them in chat, or write a Python snippet via execute_code that does all three in one tool call. The Python option is cheaper (one round trip), more reliable (the logic is explicit), and lower-risk (no shell, no filesystem mutation by default).

Deep Dive

execute_code exists because some workflows are awkward in the conversational loop. Three or more sequential tool calls with logic between them (transform this, then filter by that, then summarize the rest) cost a turn each. Bundling them into one Python snippet is faster and clearer.

The key trade-offs:

Propertyexecute_codeterminal
LanguagePython onlyAnything the shell can run
SandboxYes (Python execution environment)Depends on backend
Access to Hermes toolsYes, programmaticallyNo, only what the shell can call
Approval promptsRarelyFrequently for dangerous patterns
Filesystem persistenceLimited to its scopeFull filesystem of the backend
Best forComposing tool calls, data transformation, parsingRunning real commands: build, test, git, install

A common rule of thumb: if your task is take some data, transform it, return a summary, reach for execute_code. If your task is interact with the system the way a developer would, reach for terminal.

Note that execute_code is not a hiding place. It still runs code, and that code can do real work. But it is a smaller, more predictable surface than a shell.

Common Pitfalls

  1. Using terminal for what execute_code does better: A long pipeline of curl | jq | awk is usually clearer as five lines of Python via execute_code.
  2. Using execute_code for what terminal does better: Running pnpm install or git commit through Python's subprocess defeats the point. Use terminal for shell-native tasks.

Best Practices

  1. Prefer execute_code when the work is data-shaped: Parsing, transforming, summarizing data benefits from Python and from being a single call.
  2. Use terminal for shell-native work: Builds, tests, package management, git. These are not data transformations; they are commands to a system.

Summary

  • execute_code runs Python in a sandbox; it can call other Hermes tools.
  • terminal runs arbitrary shell commands and is the largest surface in the registry.
  • For data transformation and tool composition, prefer execute_code.
  • For shell-native developer workflows, prefer terminal.
  • The choice changes blast radius, cost, and how often you see approval prompts.

Code Examples

python
# execute_code task: fetch three URLs, count unique authors
import json

urls = [
    'https://api.example.com/posts/1',
    'https://api.example.com/posts/2',
    'https://api.example.com/posts/3',
]

authors = set()
for url in urls:
    page = web_extract(url=url)  # Hermes tool, callable from Python
    data = json.loads(page['content'])
    authors.add(data['author'])

print(f'Unique authors: {len(authors)}')
✓ Completed