cron-execute-code-blocked.md 6.26 KB

Cron Mode: execute_code Blocked

Why It's Blocked

execute_code runs arbitrary local Python, including subprocess calls that can bypass shell-string approval checks. In cron jobs, no user is present to approve these calls, so the tool is denied for safety.

Error Signature

When blocked, you see:

BLOCKED: execute_code runs arbitrary local Python (including subprocess calls that bypass shell-string approval checks). Cron jobs run without a user present to approve it. Use normal tools instead, or set approvals.cron_mode: approve only if this cron profile is intentionally trusted.

Note on approvals.cron_mode: The error message mentions this as a configuration option that could potentially enable execute_code in cron mode. However, this requires explicit user configuration of the cron profile as "intentionally trusted." Do NOT attempt to work around the block by trying different Python code — the restriction is at the tool-policy level, not the code level. If the user wants execute_code enabled in cron, they must configure it explicitly; the agent cannot and should not bypass this.

Workaround Patterns

Common Trigger: Batching su Commands via subprocess

A frequent anti-pattern that triggers this block is attempting to use execute_code to run multiple su -c shell commands through Python's subprocess module:

# This WILL be blocked in cron mode:
def su_run(cmd):
    full_cmd = f"su -c '{cmd}'"
    subprocess.run(full_cmd, shell=True, capture_output=True, text=True)

# Then calling it repeatedly in a Python script:
su_run("ls /sdcard/VisualAgent/commands/")
su_run("cat /sdcard/VisualAgent/commands/cmd.json")
su_run("screencap -p /sdcard/result.png")

Why this is blocked: The subprocess call with shell=True bypasses the shell-string approval mechanism. Even though each individual command is benign, the execute_code tool cannot verify this without running the code, which is exactly what the cron safety guard prevents.

The fix: Replace the Python subprocess wrapper with direct terminal tool calls, one per operation. The terminal tool's shell-string approval mechanism can inspect each command individually and approve safe ones.

Workaround Patterns

Use terminal with su -c for each operation:

# Check for commands
su -c 'ls -la /sdcard/VisualAgent/commands/'

# Read a command file
su -c 'cat /sdcard/VisualAgent/commands/cmd_001.json'

# Execute screenshot
su -c 'screencap -p /sdcard/VisualAgent/results/screenshot.png'

# Execute tap
su -c 'input tap 500 1000'

# Write result
su -c 'echo "{\"status\":\"success\"}" > /sdcard/VisualAgent/results/result.json'

Use Hermes Android phone tools directly instead of shell commands:

  • mcp_android_phone_screenshot — captures screen via MCP
  • mcp_android_phone_tap — taps coordinates
  • mcp_android_phone_swipe — swipes screen
  • mcp_android_phone_input_text — types text
  • mcp_android_phone_open_app — launches app

These are safer and don't require execute_code.

Pattern 3: Shell + Python One-Liners (For JSON Parsing)

When you need JSON parsing in shell, use python3 -c:

# Extract command type from JSON
su -c 'python3 -c "import json; print(json.load(open(\"/sdcard/VisualAgent/commands/cmd.json\")).get(\"type\"))"'

# Parse and execute based on type
su -c 'python3 -c "
import json, subprocess, sys
cmd = json.load(open(\"/sdcard/VisualAgent/commands/cmd.json\"))
t = cmd.get(\"type\", \"\")
if t == \"screenshot\":
    subprocess.run([\"screencap\", \"-p\", \"/sdcard/VisualAgent/results/screenshot.png\"])
"'

Note: This is still a shell command, not execute_code. The Python runs in a single -c string.

However, even python3 -c via terminal may fail in cron if the command string is complex (contains quotes, newlines, or multiple statements). The terminal tool may also be blocked for long or complex shell strings in cron mode. Test with a simple one-liner first; if it fails, fall back to Pattern 4.

Pattern 4: Hybrid — MCP Tools for Execution, Terminal for File I/O (Most Reliable in Cron)

For the VisualAgent pattern, use MCP tools for UI operations and terminal for file management:

  1. terminal to list command files: su -c 'ls /sdcard/VisualAgent/commands/'
  2. terminal to read command: su -c 'cat /sdcard/VisualAgent/commands/cmd.json'
  3. MCP tool to execute (e.g., mcp_android_phone_screenshot)
  4. terminal to write result: su -c 'echo "..." > /sdcard/VisualAgent/results/result.json'

What NOT to Do

  • ❌ Don't try to use execute_code with subprocess in cron — it will be blocked
  • ❌ Don't write a Python script to a file and try to run it via execute_code
  • ❌ Don't attempt to bypass the block with creative workarounds — use the approved patterns above
  • ❌ Don't try to use execute_code for complex multi-step logic with loops/conditionals — break it into separate terminal calls instead

When execute_code IS Available

execute_code works normally in interactive sessions (when a user is present). The block only applies to cron jobs and other non-interactive contexts where no user can approve potentially dangerous operations.

Real-World Recovery Example

If you accidentally try execute_code and get blocked:

  1. Recognize the error — "BLOCKED: execute_code runs arbitrary local Python..."
  2. Stop — don't try again or look for workarounds
  3. Switch to Pattern 4 (Hybrid) — use terminal for file I/O and MCP tools for UI execution
  4. For JSON parsing — use python3 -c via terminal or jq if available

Example recovery from a blocked VisualAgent service attempt:

# Was going to do this (BLOCKED):
# execute_code with Python script that loops, parses JSON, calls subprocess

# Instead do this:
terminal: "su -c 'ls -la /sdcard/VisualAgent/commands/'"
# → see files, identify commands

terminal: "su -c 'cat /sdcard/VisualAgent/commands/cmd.json'"
# → read command content

mcp_android_phone_screenshot: {path: "/sdcard/VisualAgent/results/screenshot.png"}
# → execute screenshot via MCP

terminal: "su -c 'echo \"{\\"status\\":\\"success\\"}\" > /sdcard/VisualAgent/results/result.json'"
# → write result