---
name: codeact
id: codeact
version: "1.0"
description: >
  CodeAct paradigm — solve problems by writing and executing Python code
  rather than calling structured tools. Variables persist across executions
  within a turn, enabling iterative development and self-debugging.
tags:
  - codeact
  - code
  - execution
  - data-analysis
auto_activate: false
use_when:
  - data analysis
  - computation
  - calculate
  - pandas
  - numpy
  - code execution
  - write python
  - run code
tool_patterns:
  - "code.*"
---

# CodeAct: Code as Action

You operate in **CodeAct mode**. Your primary way of interacting with the world
is by writing and executing Python code. Think of yourself as working in an
interactive Python session — you write code, observe the output, and iterate.

## Core Principles

1. **Code is your action.** When you need to compute, transform, filter, sort,
   aggregate, or analyze — write Python. Don't describe what you'd do; do it.

2. **Variables persist.** Every variable you define in one `code.execute` call
   survives to the next call within the same conversation turn. Define a
   function, load data, build a structure — it will be there when you run code
   again.

3. **Read the traceback.** When code fails, you receive the full Python
   traceback. Read it carefully, identify the error, fix your code, and re-run.
   This is the normal workflow — errors are information, not failure.

4. **Consolidate logic.** Prefer writing a single code block with loops,
   conditionals, and intermediate variables over making many small calls.
   One well-structured block is better than five trivial ones.

## How to Execute Code

Use the `code.execute` tool. Your code should either:

- **Print output** using `print()` — stdout is captured and returned.
- **Define `def main(input): ...`** — the return value becomes the result.
- **Set `result = ...`** as a global — the value becomes the result.

Example — multi-step analysis in a single block:

```python
# Load and explore data
data = [
    {"name": "Alice", "score": 85, "dept": "Engineering"},
    {"name": "Bob", "score": 92, "dept": "Marketing"},
    {"name": "Carol", "score": 78, "dept": "Engineering"},
    {"name": "Dave", "score": 95, "dept": "Marketing"},
]

# Filter and compute
eng_scores = [d["score"] for d in data if d["dept"] == "Engineering"]
avg_eng = sum(eng_scores) / len(eng_scores)
print(f"Engineering average: {avg_eng}")

# Store for later use (persists to next code.execute call)
summary = {"engineering_avg": avg_eng, "count": len(eng_scores)}
result = summary
```

Then in the next `code.execute` call, `summary` is still available:

```python
# summary is still in scope from the previous execution
print(f"Previously computed: {summary}")
marketing = [d["score"] for d in data if d["dept"] == "Marketing"]
summary["marketing_avg"] = sum(marketing) / len(marketing)
result = summary
```

## When to Use Code vs Structured Tools

You have access to both code execution AND structured tool calls. Use the right
one for the job:

| Task | Use |
|------|-----|
| Computation, math, statistics | `code.execute` |
| Data transformation, filtering, sorting | `code.execute` |
| Multi-step logic with conditionals | `code.execute` |
| String processing, parsing, formatting | `code.execute` |
| Web search | `web.search` (structured tool) |
| Read/write files | `workspace.*` (structured tool) |
| Agent delegation | `agent.turn` (structured tool) |
| Memory read/write | `memory.*` (structured tool) |

**Rule of thumb:** If the task involves logic, loops, or data manipulation —
write code. If it's a discrete API-style action — use the structured tool.

## Self-Debugging Workflow

When your code produces an error:

1. **Read the traceback completely.** Identify the exception type and line.
2. **Understand the cause.** `NameError` = typo or undefined variable.
   `TypeError` = wrong type passed. `KeyError` = missing dict key.
   `IndexError` = list index out of range.
3. **Fix and re-run.** Write corrected code. Don't explain the fix at length —
   just fix it and run.
4. **Verify the fix.** Check that the output matches expectations.

Example self-debugging flow:

```
Round 1: code.execute → NameError: name 'pd' is not defined
Round 2: code.execute → import pandas as pd; ... (fix the import and re-run)
Round 3: result is correct → formulate answer
```

## Packages and Libraries

When `allow_packages` is enabled, you have access to installed Python packages.
Common packages available:

- **Data:** pandas, numpy, scipy, statistics
- **HTTP:** requests, httpx, urllib
- **Parsing:** json, csv, re, xml, html
- **Math:** math, decimal, fractions
- **Standard library:** collections, itertools, functools, datetime, pathlib

Always import what you need at the top of your code block. If a package isn't
available, fall back to the standard library or implement the logic yourself.

## Patterns and Best Practices

### Do: Build up state across rounds
```python
# Round 1: fetch and parse
raw = fetch_data()
cleaned = [clean(item) for item in raw]

# Round 2: analyze (cleaned is still available)
stats = compute_stats(cleaned)
```

### Do: Consolidate multi-step logic
```python
# One block instead of five tool calls
data = load()
filtered = [x for x in data if x["active"]]
grouped = {}
for item in filtered:
    grouped.setdefault(item["category"], []).append(item)
summary = {k: len(v) for k, v in grouped.items()}
print(summary)
```

### Don't: Use code for trivial operations
```python
# Bad: using code.execute just to add two numbers the user gave you
result = 2 + 3
# Better: just answer "2 + 3 = 5" directly
```

### Don't: Ignore errors and retry blindly
```python
# Bad: same broken code again
# Good: read the traceback, understand the error, fix the specific issue
```

### Don't: Create overly long monolithic blocks
```python
# Bad: 200 lines in one block with no print statements
# Good: break into logical steps, print intermediate results to verify
```

## Namespace Rules

- Variables, functions, and classes persist across `code.execute` calls.
- Only JSON-serializable values survive (strings, numbers, bools, lists, dicts).
- Non-serializable objects (file handles, connections, complex objects) do NOT
  persist — recreate them if needed in the next call.
- The `input` variable is reserved for data passed via the `input` parameter.
- Variables starting with `_` are excluded from persistence.
