# Inline Tool Executor Safe execution of inline (anonymous) tool code within skills. ## Overview The `InlineToolExecutor` runs Python code strings defined directly in skill YAML. Execution is bounded by configurable timeout and output-size limits, with write-guard enforcement delegated to the `SkillContext`. ## InlineToolResult Frozen Pydantic model returned from every execution. | Field | Type | Description | |-------|------|-------------| | `success` | `bool` | Whether the execution succeeded | | `output` | `Any` | Captured stdout/stderr output | | `error_message` | `str \| None` | Error description on failure | | `duration_ms` | `float` | Wall-clock execution time in milliseconds | | `truncated` | `bool` | Whether output was truncated due to size limits | ## InlineToolExecutor ### Constructor ```python InlineToolExecutor( max_runtime_seconds: float = 30.0, max_output_bytes: int = 1_048_576, ) ``` | Parameter | Default | Description | |-----------|---------|-------------| | `max_runtime_seconds` | `30.0` | Maximum wall-clock seconds for execution | | `max_output_bytes` | `1_048_576` | Maximum captured output before truncation (1 MiB) | ### `execute(tool, context, input_data) -> InlineToolResult` Run an inline tool's code with safety guards. 1. **Validation** -- Checks the tool has code and uses a supported source. 2. **Write guard** -- If `tool.capability.writes` is `True`, calls `context.enforce_write_guard()`. In a read-only context this returns an error result without executing. 3. **Path restriction** -- File-path keys in `input_data` (keys ending with `_path`, `_file`, or equal to `path`) are validated against `context.get_sandbox_path()`. 4. **Threaded execution** -- Code runs in a daemon thread with `max_runtime_seconds` timeout. 5. **Output capture** -- stdout and stderr are captured. If the combined output exceeds `max_output_bytes`, it is truncated and `truncated=True` is set on the result. 6. **Change tracking** -- The invocation is recorded in the context's change tracker regardless of success/failure. ### `validate_tool(tool) -> list[str]` Return a list of validation errors (empty means valid). Checks: - Tool has non-empty `code`. - Tool's `source` is `custom` (Python). Other source types are not supported for MVP. ## Safety Constraints ### Timeout Execution uses `threading.Thread` with a join timeout. If the thread does not complete within `max_runtime_seconds`, the result reports: ``` Execution timed out after {max_runtime_seconds}s ``` The daemon thread is abandoned (not forcibly killed). For MVP this is acceptable; future versions may use process isolation. ### Output Size Combined stdout + stderr is capped at `max_output_bytes`. When exceeded the output is byte-truncated and `InlineToolResult.truncated` is set to `True`. ### Write Guard Tools declaring `capability.writes = True` trigger a write-guard check via `SkillContext.enforce_write_guard()`. In a read-only context the executor returns an error result **without executing any code**. ### Path Restriction Input data keys matching `*_path`, `*_file`, or `path` are resolved and checked against the sandbox root. Paths that escape the sandbox are rejected before execution. ### Language / Source Support Only `source = custom` (Python) is supported for MVP. Other source types (`mcp`, `agent_skill`, `builtin`, `wrapped`) are rejected by `validate_tool`. ### Network Access For MVP, inline tools run in the host process and **no network sandboxing** is enforced. Tools should be treated as local-only. Future milestones will introduce process-level or container-level isolation for network restrictions.