This repository has been archived on 2026-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
anvillm/docs/code-execution-migration-gu...

9.1 KiB
Raw Blame History

Migration Guide: Direct Tools to Code Execution

Overview

This guide shows how to migrate from direct MCP tool calls to the code execution pattern. The migration reduces token consumption by 80-99% while enabling more powerful workflows.

Key Differences

Aspect Direct Tools Code Execution
Tool loading All upfront Progressive discovery
Data flow Through context In subprocess
Control flow Alternating calls Loops, conditionals
Token cost High (linear with data) Low (constant)
Privacy Data in context Data isolated

Migration Patterns

Pattern 1: Single Tool Call

Before:

Agent: TOOL CALL check_inbox(agent_id: "82b93a8a")
MCP: { "content": [{"type": "text", "text": "[Message 1]\n[Message 2]\n..."}] }

After:

execute_code with code: "bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) 82b93a8a"

Token savings: Minimal for single calls, but enables further optimization

Pattern 2: Sequential Tool Calls

Before:

Agent: TOOL CALL check_inbox(agent_id: "agent-1")
MCP: { "content": [...] }  // 5,000 tokens
Agent: TOOL CALL check_inbox(agent_id: "agent-2")
MCP: { "content": [...] }  // 5,000 tokens
Agent: TOOL CALL check_inbox(agent_id: "agent-3")
MCP: { "content": [...] }  // 5,000 tokens

Total: 15,000 tokens

After:

execute_code with code: "
for agent_id in agent-1 agent-2 agent-3; do
  bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) \$agent_id | wc -l
done | awk '{sum+=\$1} END {print \"Total messages:\", sum}'
"

Output: "Total messages: 47" (~10 tokens)

Token savings: 99.9% (10 tokens vs 15,000 tokens)

Pattern 3: Filtering Large Results

Before:

Agent: TOOL CALL get_spreadsheet(sheet_id: "abc123")
MCP: { "content": [...] }  // 200,000 tokens (10,000 rows)
Agent: [Processes in context, filters to 47 pending orders]

Total: 200,000+ tokens

After:

execute_code with code: "
rows=\$(9p read anvillm/sheets/abc123)
pending=\$(echo \"\$rows\" | jq '[.[] | select(.Status == \"pending\")]')
count=\$(echo \"\$pending\" | jq 'length')
total=\$(echo \"\$rows\" | jq 'length')
echo \"Found \$count pending orders out of \$total total\"
"

Output: "Found 47 pending orders out of 10000 total" (~15 tokens)

Token savings: 99.99% (15 tokens vs 200,000 tokens)

Pattern 4: Polling Loops

Before:

Agent: TOOL CALL check_status(job_id: "job-123")
MCP: { "status": "running" }
Agent: [Waits, then calls again]
Agent: TOOL CALL check_status(job_id: "job-123")
MCP: { "status": "running" }
[Repeats 10 times]

Total: ~5,000 tokens (10 calls × 500 tokens)

After:

execute_code with code: "
job_id=job-123
status=running
attempts=0

while [ \"\$status\" = \"running\" ] && [ \$attempts -lt 10 ]; do
  status=\$(9p read anvillm/jobs/\$job_id/status)
  if [ \"\$status\" = \"running\" ]; then
    sleep 5
  fi
  attempts=\$((attempts + 1))
done

echo \"Job \$job_id status: \$status (checked \$attempts times)\"
"

Output: "Job job-123 status: completed (checked 7 times)" (~15 tokens)

Token savings: 99.7% (15 tokens vs 5,000 tokens)

Pattern 5: Multi-Step Data Pipeline

Before:

Agent: TOOL CALL check_inbox(agent_id: "82b93a8a")
MCP: { "content": [...] }  // 10,000 tokens
Agent: [Identifies 5 urgent messages]
Agent: TOOL CALL send_message(to: "manager", body: "5 urgent messages")
MCP: { "content": "Message sent" }
Agent: TOOL CALL set_state(agent_id: "82b93a8a", state: "idle")
MCP: { "content": "State updated" }

Total: ~11,000 tokens

After:

execute_code with code: "
inbox=\$(bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) 82b93a8a)
urgent_count=\$(echo \"\$inbox\" | grep -c URGENT || echo 0)

if [ \$urgent_count -gt 0 ]; then
  bash <(9p read anvillm/tools/anvilmcp/send_message.sh) 82b93a8a manager NOTIFICATION 'Urgent messages' \"\$urgent_count urgent messages in inbox\"
fi

bash <(9p read anvillm/tools/anvilmcp/set_state.sh) 82b93a8a idle
echo \"Processed inbox: \$urgent_count urgent messages\"
"

Output: "Processed inbox: 5 urgent messages" (~10 tokens)

Token savings: 99.9% (10 tokens vs 11,000 tokens)

Tool-Specific Migrations

check_inbox

Before:

TOOL CALL check_inbox(agent_id: "82b93a8a")

After:

execute_code with code: "bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) 82b93a8a"

Or use 9P directly:

execute_code with code: "9p read anvillm/inbox/82b93a8a/json"

send_message

Before:

TOOL CALL send_message(from: "agent-1", to: "agent-2", type: "PROMPT_REQUEST", subject: "Task", body: "Do X")

After:

bash <(9p read anvillm/tools/anvilmcp/send_message.sh) agent-1 agent-2 PROMPT_REQUEST 'Task' 'Do X'

list_sessions

Before:

TOOL CALL list_sessions()

After:

execute_code with code: "bash <(9p read anvillm/tools/anvilmcp/list_sessions.sh)"

set_state

Before:

TOOL CALL set_state(agent_id: "82b93a8a", state: "running")

After:

execute_code with code: "bash <(9p read anvillm/tools/anvilmcp/set_state.sh) 82b93a8a running"

list_skills

Before:

TOOL CALL list_skills()

After:

execute_code with code: "bash <(9p read anvillm/tools/anvilmcp/list_skills.sh) | jq -r '.[].name' | paste -sd, -"

Compatibility Notes

When to Use Direct Tools

Direct tools are better for:

  1. Single operations: Simple one-off calls
  2. Small data: Results under 1,000 tokens
  3. Simple logic: No conditionals or loops needed
  4. Debugging: When you need to see intermediate results

When to Use Code Execution

Code execution is better for:

  1. Multiple tool calls: Any workflow with 2+ tool calls
  2. Large data: Any operation returning >1,000 tokens
  3. Filtering/aggregation: Processing data to extract summaries
  4. Loops: Polling, batch processing, retries
  5. Privacy: Operations involving PII or sensitive data

Migration Checklist

  • Identify workflows with multiple tool calls
  • Identify operations with large data returns
  • Convert sequential calls to loops
  • Add filtering/aggregation in subprocess
  • Return summaries instead of raw data
  • Add error handling (try/catch)
  • Test in isolated subprocess
  • Measure token savings
  • Update agent prompts with examples

Common Pitfalls

Pitfall 1: Returning Raw Data

Bad:

result=$(bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) 82b93a8a)
echo "$result"  # Could be 50,000 tokens

Good:

result=$(bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) 82b93a8a)
count=$(echo "$result" | wc -l)
echo "Inbox has $count messages"  # ~10 tokens

Pitfall 2: Not Using Loops

Bad:

result1=$(bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) agent-1)
echo "$result1"
result2=$(bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) agent-2)
echo "$result2"
result3=$(bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) agent-3)
echo "$result3"

Good:

for agent_id in agent-1 agent-2 agent-3; do
  result=$(bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) "$agent_id")
  count=$(echo "$result" | wc -l)
  echo "$agent_id: $count messages"
done

Pitfall 3: Ignoring Errors

Bad:

result=$(bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) invalid-id)
echo "$result"  # May fail silently

Good:

if result=$(bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) invalid-id 2>&1); then
  echo "$result"
else
  echo "Failed to read inbox: $result" >&2
fi

Pitfall 4: Re-reading Tool Definitions

Bad:

for i in {1..10}; do
  tool=$(9p read anvillm/tools/anvilmcp/check_inbox.sh)
  # Parse and use...
done

Good:

# Call tool directly each time
for i in {1..10}; do
  bash <(9p read anvillm/tools/anvilmcp/check_inbox.sh) 82b93a8a
done

Performance Comparison

Workflow Direct Tools Code Execution Savings
Single small call 500 tokens 400 tokens 20%
3 sequential calls 15,000 tokens 150 tokens 99%
Filter 10k rows 200,000 tokens 100 tokens 99.95%
Poll 10 times 5,000 tokens 200 tokens 96%
Multi-step pipeline 50,000 tokens 500 tokens 99%

Rollout Strategy

Phase 1: Pilot (Week 1)

  • Migrate 1-2 simple workflows
  • Measure token savings
  • Identify issues

Phase 2: Expand (Week 2-3)

  • Migrate high-volume workflows
  • Update agent prompts
  • Train team on patterns

Phase 3: Optimize (Week 4+)

  • Refine implementations
  • Add more examples
  • Monitor metrics

Support

For questions or issues:

Token Savings Calculator

Estimate your savings:

Current tokens = (tool_count × 90) + (data_size_kb × 250)
Code execution tokens = 30 + (summary_size_kb × 250)
Savings = (Current - Code execution) / Current × 100%

Example:

  • 100 tools, 10 KB data
  • Current: (100 × 90) + (10 × 250) = 11,500 tokens
  • Code execution: 30 + (0.01 × 250) = 33 tokens
  • Savings: 99.7%