Tools Module

Tools module for atloop agent.

class atloop.tools.ToolResult(ok: bool, stdout: str, stderr: str, meta: Dict[str, Any])[source]

Bases: object

Result of tool execution.

__init__(ok: bool, stdout: str, stderr: str, meta: Dict[str, Any]) None
__repr__() str[source]

String representation.

ok: bool
stdout: str
stderr: str
meta: Dict[str, Any]
class atloop.tools.BaseTool[source]

Bases: ABC

Base class for all tools.

Tools can declare their output semantic types to enable automatic application of appropriate output size limits.

abstract property description: str

Tool description.

abstractmethod execute(args: Dict[str, Any]) ToolResult[source]

Execute tool with given arguments.

get_detailed_description() str[source]

Generate detailed tool description for LLM prompts.

Extracts comprehensive information from the tool’s docstring including: - Main description - Usage guidelines - Important warnings - Parameters - Examples - When to use vs other tools

Returns:

Formatted detailed description string suitable for LLM prompts

abstract property name: str

Tool name.

needs_permission(args: Dict[str, Any]) bool[source]

Whether this tool needs user permission.

property output_semantic_type: OutputSemanticType

Return the semantic type of tool output.

Default: STATUS_MESSAGE (suitable for most tools that return simple success/failure messages).

Subclasses can override this property to declare their output semantic type.

Returns:

OutputSemanticType enum value

property stderr_semantic_type: OutputSemanticType

Return the semantic type of stderr output.

Default: ERROR_MESSAGE (stderr is typically error information).

Subclasses can override this if stderr has a different semantic type.

Returns:

OutputSemanticType enum value

property stdout_semantic_type: OutputSemanticType

Return the semantic type of stdout output.

Default: Uses output_semantic_type.

Subclasses can override this if stdout has a different semantic type than the general output.

Returns:

OutputSemanticType enum value

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate tool arguments. Returns (is_valid, error_message).

atloop.tools.__getattr__(name: str)[source]

Lazy import for ToolRuntime to avoid circular imports.

BaseTool

class atloop.tools.base.BaseTool[source]

Bases: ABC

Base class for all tools.

Tools can declare their output semantic types to enable automatic application of appropriate output size limits.

abstract property name: str

Tool name.

abstract property description: str

Tool description.

property output_semantic_type: OutputSemanticType

Return the semantic type of tool output.

Default: STATUS_MESSAGE (suitable for most tools that return simple success/failure messages).

Subclasses can override this property to declare their output semantic type.

Returns:

OutputSemanticType enum value

property stdout_semantic_type: OutputSemanticType

Return the semantic type of stdout output.

Default: Uses output_semantic_type.

Subclasses can override this if stdout has a different semantic type than the general output.

Returns:

OutputSemanticType enum value

property stderr_semantic_type: OutputSemanticType

Return the semantic type of stderr output.

Default: ERROR_MESSAGE (stderr is typically error information).

Subclasses can override this if stderr has a different semantic type.

Returns:

OutputSemanticType enum value

abstractmethod execute(args: Dict[str, Any]) ToolResult[source]

Execute tool with given arguments.

needs_permission(args: Dict[str, Any]) bool[source]

Whether this tool needs user permission.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate tool arguments. Returns (is_valid, error_message).

get_detailed_description() str[source]

Generate detailed tool description for LLM prompts.

Extracts comprehensive information from the tool’s docstring including: - Main description - Usage guidelines - Important warnings - Parameters - Examples - When to use vs other tools

Returns:

Formatted detailed description string suitable for LLM prompts

ToolRegistry

class atloop.tools.registry.ToolRegistry(sandbox: SandboxAdapter, skill_loader=None)[source]

Bases: object

Registry for managing tools.

__init__(sandbox: SandboxAdapter, skill_loader=None)[source]

Initialize tool registry.

Parameters:
  • sandbox – Sandbox adapter instance (required by run, read_file, write_file, etc.)

  • skill_loader – Optional skill loader for read_skill_file, load_skill, and load_skill_resource tools. Passed automatically to tools that declare skill_loader in __init__.

register(tool: BaseTool)[source]

Register a tool.

get(name: str) BaseTool | None[source]

Get a tool by name.

get_tool(name: str) BaseTool | None[source]

Get a tool by name (alias for get method).

This method provides a consistent interface name used in the output limit strategy system.

Parameters:

name – Tool name

Returns:

Tool instance or None if not found

list_tools() List[str][source]

List all registered tool names.

get_registration_stats() Dict[str, Any][source]

Get tool registration statistics.

Returns:

Dictionary with registration stats (discovered, registered, failed, tools)

execute(tool_name: str, args: Dict[str, Any]) ToolResult[source]

Execute a tool.

Parameters:
  • tool_name – Name of the tool

  • args – Tool arguments

Returns:

ToolResult instance

Raises:

ValueError – If tool not found

ToolExecutor

class atloop.orchestrator.executor.tool_executor.ToolExecutor(coordinator: WorkflowCoordinator)[source]

Bases: object

Tool executor for executing tool calls.

__init__(coordinator: WorkflowCoordinator)[source]

Initialize tool executor.

Parameters:

coordinator – Workflow coordinator instance

execute_actions(actions: List[Dict[str, Any]]) List[Dict[str, Any]][source]

Execute a list of actions.

Parameters:

actions – List of action dictionaries

Returns:

List of tool execution results

Filesystem Tools

Filesystem tools.

class atloop.tools.filesystem.ReadFileTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for reading files from the sandbox workspace with type detection and chunked reading.

Features: - Automatic file type detection (text/binary) - Support for large files via line range reading - Binary file detection and handling - File size limits (10MB max for full read)

Use cases: - Reading source code files - Reading configuration files - Reading documentation files - Reading log files (with line ranges)

Note: This tool reads from the sandbox workspace (/workspace), not from the local machine. For reading skill files (stored locally), use read_skill_file instead.

__init__(sandbox: SandboxAdapter)[source]

Initialize read file tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute read file tool.

Args:
args: Tool arguments dictionary
  • path (str, required): File path. Relative paths are relative to /workspace. Absolute paths are used as-is.

  • offset (int, optional): Start line number (1-indexed). Default: 1 (start of file). Use this for reading large files in chunks.

  • limit (int, optional): Number of lines to read. If not specified, reads from offset to end of file. Use this for reading large files in chunks.

Returns:

ToolResult with: - ok (bool): True if file was read successfully (no errors in stderr) - stdout (str): File content (or metadata for binary/large files) - stderr (str): Error messages if any (empty string means success) - meta (dict): Contains path, file_type, file_size, start_line, end_line

Examples:

# Read entire file read_file(path=”src/main.py”)

# Read first 100 lines read_file(path=”src/main.py”, offset=1, limit=100)

# Read lines 50-100 read_file(path=”src/main.py”, offset=50, limit=51)

# Read from line 200 to end read_file(path=”src/main.py”, offset=200)

Behavior: - Text files: Returns file content in stdout - Binary files: Returns metadata message (file type, size) instead of content - Large files (>10MB): Returns metadata message, suggests using line ranges - File not found: Returns ok=False with error message in stderr - Line ranges: If offset/limit specified, only reads those lines

Path Handling: - All commands run with workdir=”/workspace” - Relative paths are resolved relative to /workspace - Absolute paths are used as-is

Error Handling: - Success is determined by stderr content, not exit code - If stderr is empty, the operation succeeded - Check stderr for specific error messages if ok=False

property name: str

Tool name.

property output_semantic_type: OutputSemanticType

FILE_CONTENT.

Type:

Return semantic type

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

class atloop.tools.filesystem.ReadSkillFileTool(skill_loader=None)[source]

Bases: BaseTool

Tool for reading files from skill directories (on local machine, not from sandbox workspace).

🚨🚨🚨 CRITICAL: This tool reads from skill directories on the LOCAL machine, NOT from the sandbox!

Key Points: - Skill files are stored LOCALLY (on the host machine, in ~/.atloop/skills/ or project .atloop/skills/) - Workspace is a REMOTE SANDBOX (/workspace) - it does NOT contain skill files or templates - When a skill mentions other files (e.g., “see docx-js.md”, “reference guide.md”), those files are LOCAL - You MUST use `read_skill_file` to read skill-related files - they are NOT in the sandbox! - DO NOT try to use `read_file` or `run(“cat …”)` to find skill files in the sandbox - they don’t exist there!

Use cases: - Reading skill files (when skill mentions other files to reference) - Reading files referenced in skill documentation - Accessing skill-specific resources (templates, guides, examples)

Path resolution: - With skill_name: Path is relative to skill directory (most common use case) - Without skill_name: Absolute path or relative to ~/.atloop/ - Supports ~ expansion for home directory

Important distinction: - ✓ Skill files → Use read_skill_file (stored locally) - ✓ Workspace files → Use read_file (stored in remote sandbox /workspace) - ❌ Never use `read_file` or `run` to find skill files - they are not in the sandbox!

__init__(skill_loader=None)[source]

Initialize read skill file tool.

Parameters:

skill_loader – Optional skill loader instance for resolving skill paths

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute read skill file tool.

🚨🚨🚨 CRITICAL: This tool reads from skill directories on the LOCAL machine, NOT from the sandbox workspace!

Important understanding: - Skill files are stored LOCALLY (on the host machine) - Workspace is a REMOTE SANDBOX (/workspace) - it does NOT contain skill files - When a skill mentions other files, those files are LOCAL, not in the sandbox - You MUST use `read_skill_file` to read skill-related files - DO NOT try to use `read_file` or `run(“cat …”)` to find skill files in the sandbox - they don’t exist there!

Use read_file to read files from the sandbox workspace (/workspace).

Args:
args: Tool arguments dictionary
  • path (str, required): File path. Resolution depends on skill_name: - If skill_name provided: Path is relative to skill directory - If path starts with ~: Expanded to home directory - If absolute path: Used as-is - Otherwise: Relative to ~/.atloop/

  • skill_name (str, optional): Skill name. If provided, path is resolved relative to the skill’s directory. Use this when a skill mentions other files to reference.

  • offset (int, optional): Start line number (1-indexed). Default: 1. Use for reading large files in chunks.

  • limit (int, optional): Number of lines to read. If not specified, reads from offset to end of file.

Returns:

ToolResult with: - ok (bool): True if file was read successfully (no errors in stderr) - stdout (str): File content (or metadata for binary/large files) - stderr (str): Error messages if any (empty string means success) - meta (dict): Contains path, file_size, start_line, end_line

Examples:

# Read skill file (when skill mentions other files) read_skill_file(path=”references/guide.md”, skill_name=”long_document_writer”)

# Read skill documentation read_skill_file(path=”docx-js.md”, skill_name=”docx”)

# Read with line range read_skill_file(path=”skill-doc.md”, skill_name=”docx”, offset=1, limit=50)

When to use this vs read_file: - ✓ Reading skill files → use read_skill_file (stored locally, NOT in sandbox) - ✓ Reading files referenced in skills → use read_skill_file (skill mentions are LOCAL files) - ✓ Reading skill templates/examples → use read_skill_file (stored locally) - ❌ Reading workspace files → use read_file (sandbox files in /workspace) - ❌ DO NOT use `read_file` or `run` to find skill files - they are NOT in the sandbox!

File Size Limits: - Files larger than 10MB return metadata only - Use offset/limit to read specific sections of large files

Error Handling: - Success is determined by stderr content, not exit code - If stderr is empty, the operation succeeded - Check stderr for specific error messages if ok=False

property name: str

Tool name.

property output_semantic_type: OutputSemanticType

FILE_CONTENT.

Type:

Return semantic type

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

class atloop.tools.filesystem.WriteFileTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for writing files (creates new files or completely overwrites existing files).

⚠️ Important Usage Guidelines: - Use for: Creating new files or completely rewriting existing files - Do NOT use for: Modifying parts of existing files (use edit_file instead) - Character limit: Maximum 6,000 characters per turn - Directory creation: Automatically creates parent directories if they don’t exist - ⚠️ CRITICAL: Do NOT generate code with {variable} patterns: Patterns like {error_output},

{variable}, etc. will be written literally to the file and will NOT be populated by shell variable expansion. Use proper templating in the target language instead (e.g., Python f-strings, format(), etc.)

When to use write_file vs edit_file: - ✓ Creating a new file → use write_file - ✓ Completely rewriting a file → use write_file - ❌ Modifying a function/class → use edit_file (more precise and safer) - ❌ Adding/removing a few lines → use edit_file (more precise and safer)

File content handling: - Uses placeholder mechanism: content should be FILE_CONTENT_#1, FILE_CONTENT_#2, etc. - Actual content follows the JSON output, delimited by —(FILE_CONTENT_#1)— - This prevents JSON parsing issues with large content

Trailing newline behavior: - Files always end with exactly one newline character - Input content’s trailing newline is normalized automatically

__init__(sandbox: SandboxAdapter)[source]

Initialize write file tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute write file tool.

⚠️ WARNING: This tool completely overwrites the entire file. If the file exists, all existing content will be replaced with the new content.

When to use this tool: - ✓ Creating a new file - ✓ Completely rewriting an existing file - ❌ Modifying part of a file → use edit_file instead - ❌ Appending content → use append_file instead

Args:
args: Tool arguments dictionary
  • path (str, required): File path. Relative paths are relative to /workspace. Parent directories are automatically created if they don’t exist.

  • content (str, required): File content to write. This will completely replace any existing file content. Maximum 6,000 characters per turn. Use placeholder FILE_CONTENT_#1 in JSON, actual content follows after.

Returns:

ToolResult with: - ok (bool): True if file was written successfully (no errors in stderr) - stdout (str): Command output (usually empty) - stderr (str): Error messages if any (empty string means success) - meta (dict): Contains path, cmd, duration_ms

Examples:

# Create a new Python file write_file(path=”src/main.py”, content=”FILE_CONTENT_#1”) # Then provide actual content after JSON: # —(FILE_CONTENT_#1)— # def main(): # print(“Hello, World!”) # —(FILE_CONTENT_#1)—

Note on Trailing Newlines: Files always end with exactly one newline character: - If content ends with ‘n’, it’s preserved - If content doesn’t end with ‘n’, one is added - Result: File always ends with exactly one newline character - Exception: Empty string content results in a file with one newline

⚠️ Important: Content with {variable} patterns: Do NOT generate code or text with patterns like {error_output}, {variable}, etc. expecting them to be populated by shell variable expansion. These are written literally to the file and will NOT be expanded. If you need variable substitution, use proper templating mechanisms in the target language (e.g., Python f-strings, format(), etc.).

Error Handling: - Success is determined by stderr content, not exit code - If stderr is empty, the operation succeeded - Check stderr for specific error messages if ok=False

property name: str

Tool name.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

class atloop.tools.filesystem.AppendFileTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for appending content to the end of existing files.

⚠️ This tool is fully available and can be used normally!

Use cases: - Continuing to write files that exceed 6,000 characters (after initial write_file) - Adding log entries - Appending comments or notes - Building files incrementally

Key differences from write_file and edit_file: - write_file: Completely overwrites file (creates or replaces entire file) - edit_file: Replaces specific text within file (precise modifications) - append_file: Adds content to end of file (doesn’t modify existing content)

Content handling: - Content is appended exactly as provided - Preserves trailing newlines in input content - Unlike write_file/edit_file, doesn’t normalize trailing newlines

⚠️ CRITICAL: Do NOT generate code with {variable} patterns: Patterns like {error_output}, {variable}, etc. will be written literally to the file and will NOT be populated by shell variable expansion. Use proper templating in the target language instead (e.g., Python f-strings, format(), etc.)

__init__(sandbox: SandboxAdapter)[source]

Initialize append file tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute append file tool.

⚠️ IMPORTANT: This tool is fully available and can be used normally! Don’t assume it’s unavailable - it works perfectly fine.

Args:
args: Tool arguments dictionary
  • path (str, required): File path. Relative paths are relative to /workspace. File must exist (this tool appends to existing files, doesn’t create new ones).

  • content (str, required): Content to append to the end of the file.

Returns:

ToolResult with: - ok (bool): True if content was appended successfully (no errors in stderr) - stdout (str): Command output (usually empty) - stderr (str): Error messages if any (empty string means success) - meta (dict): Contains path, cmd, duration_ms

Examples:

# Continue writing a long document (after initial write_file with 6k chars) append_file(

path=”long_document.md”, content=”nn## Chapter 2nThis is the continuation…”

)

# Add a log entry append_file(

path=”app.log”, content=”[2024-01-01] User logged inn”

)

Content Appending Behavior: - Content is appended exactly as provided, without modification - If content ends with ‘n’, it’s appended with the newline - If content doesn’t end with ‘n’, it’s appended without a newline - This differs from write_file and edit_file, which normalize trailing newlines - Use this when you need precise control over trailing newlines

⚠️ Important: Content with {variable} patterns: Do NOT generate code or text with patterns like {error_output}, {variable}, etc. expecting them to be populated by shell variable expansion. These are written literally to the file and will NOT be expanded. If you need variable substitution, use proper templating mechanisms in the target language (e.g., Python f-strings, format(), etc.).

Common Workflow: 1. First turn: Use write_file to create file with first 6k characters 2. Subsequent turns: Use append_file to continue adding content 3. Check file: Use read_file to verify complete content

Error Handling: - Success is determined by stderr content, not exit code - If stderr is empty, the operation succeeded - Check stderr for specific error messages if ok=False

property name: str

Tool name.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

class atloop.tools.filesystem.EditFileTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for editing files using Git-style diff (old_string -> new_string).

⚠️ This is the preferred tool for modifying existing files!

Why use edit_file instead of write_file: - ✓ More precise: Only modifies the specified part - ✓ Safer: Doesn’t risk overwriting unrelated code - ✓ More efficient: No need to read and rewrite entire file - ✓ Better for local modifications: Functions, classes, paragraphs, etc.

⚠️ CRITICAL: Do NOT generate code with {variable} patterns: Patterns like {error_output}, {variable}, etc. will be written literally to the file and will NOT be populated by shell variable expansion. Use proper templating in the target language instead (e.g., Python f-strings, format(), etc.)

Safety features: - Match count validation: Only replaces if old_string appears exactly once - Prevents accidental multiple replacements - Clear error messages when matches are not found or ambiguous

Use cases: - Modifying a function or method - Updating a class definition - Changing a specific section of code - Fixing a bug in a specific location - Updating configuration values

__init__(sandbox: SandboxAdapter)[source]

Initialize edit file tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute edit file tool.

⚠️ IMPORTANT: This is the preferred tool for modifying existing files! Use this instead of write_file for any file modifications.

Args:
args: Tool arguments dictionary
  • path (str, required): File path. Relative paths are relative to /workspace.

  • content (str, required): Content in format <old>old_string</old><new>new_string</new>. The old_string is the exact text to replace. Must match exactly including whitespace, indentation, and newlines. Should include at least 3 lines of context before and after to ensure uniqueness.

  • replace_all (bool, optional): If True, replace all occurrences of old_string. Default: False. When False, only replaces if old_string appears exactly once.

Returns:

ToolResult with: - ok (bool): True if edit was successful (no errors in stderr) - stdout (str): Diff summary (e.g., “Updated file: +2 lines, -1 lines”) - stderr (str): Error messages if any (empty string means success) - meta (dict): Contains path, operation, replace_all

Examples:

# Modify a function edit_file(

path=”src/utils.py”, content=”<old>def calculate(x, y):

return x + y</old><new>def calculate(x, y): return x * y</new>”

)

# Add context for uniqueness edit_file(

path=”src/main.py”, content=”<old># Configuration

DEBUG = True # End config</old><new># Configuration DEBUG = False # End config</new>”

)

Safety Checks: - Match count validation: When replace_all=False (default):

  • If old_string appears 0 times → Error: “old_string not found”

  • If old_string appears 1 time → Success: Replaces it

  • If old_string appears 2+ times → Error: “found X times, make old_string more specific”

  • When replace_all=True: Replaces all occurrences without validation

Best Practices: 1. Include context: Add at least 3 lines before and after the code you’re changing 2. Be precise: Match exact whitespace, indentation, and newlines 3. Make it unique: Ensure old_string appears only once in the file 4. Use read_file first: Read the file to see exact formatting before editing

Error Messages: - “old_string not found” → Check that old_string exactly matches file content - “found X times” → Add more context to make old_string unique, or use replace_all=True - “File not found” → File doesn’t exist

Note on Trailing Newlines: Files always end with exactly one newline character after editing, regardless of whether new_string ends with a newline or not.

⚠️ Important: Content with {variable} patterns: Do NOT generate code or text with patterns like {error_output}, {variable}, etc. expecting them to be populated by shell variable expansion. These are written literally to the file and will NOT be expanded. If you need variable substitution, use proper templating mechanisms in the target language (e.g., Python f-strings, format(), etc.).

property name: str

Tool name.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

class atloop.tools.filesystem.MultiEditFileTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for editing multiple files in a single atomic transaction.

Key Features: - Transactional: All edits succeed or all fail (atomicity) - Batch operations: Edit multiple files in one operation - Rollback on error: If any edit fails, all changes are rolled back

Use cases: - Updating imports across multiple files - Refactoring code that spans multiple files - Applying the same change to multiple files - Coordinated updates that must happen together

When to use: - ✓ Need to edit multiple files atomically - ✓ Changes must all succeed or all fail - ❌ Single file edit → use edit_file (simpler) - ❌ Independent edits → use multiple edit_file calls

__init__(sandbox: SandboxAdapter)[source]

Initialize multi-edit file tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute multi-edit file tool.

⚠️ Transactional Behavior: All edits are atomic - either all succeed or all fail. If any edit fails, all changes are rolled back and no files are modified.

Args:
args: Tool arguments dictionary
  • edits (list, required): List of edit operations. Each edit is a dictionary with:
    • path (str, required): File path. Relative paths are relative to /workspace.

    • old_string (str, required): Exact text to replace. Must match exactly. If empty, creates a new file.

    • new_string (str, required): Replacement text.

    • replace_all (bool, optional): Replace all occurrences. Default: False.

Returns:

ToolResult with: - ok (bool): True if all edits succeeded (no errors in stderr) - stdout (str): Summary of edited files (e.g., “Successfully edited 3 file(s)”) - stderr (str): Error messages if any (empty string means success) - meta (dict): Contains successful_edits, failed_edits, total_edits, edited_files

Examples:

# Update imports in multiple files atomically multi_edit_file(edits=[

{

“path”: “src/file1.py”, “old_string”: “from utils import helper”, “new_string”: “from utils.helpers import helper”

}, {

“path”: “src/file2.py”, “old_string”: “from utils import helper”, “new_string”: “from utils.helpers import helper”

}

])

Transaction Phases: 1. Validation phase: Read all files, check they exist 2. Transaction phase: Apply all edits in memory 3. Commit phase: Write all files (only if all edits succeeded)

Error Handling: - If any file read fails → All edits rolled back, error in stderr - If any edit fails (old_string not found) → All edits rolled back, error in stderr - If any file write fails → Partial success reported, failed files in stderr - Success is determined by stderr content, not exit code

Best Practices: 1. Use when edits must be atomic (all or nothing) 2. Ensure all old_string values are unique in their respective files 3. Include sufficient context in old_string for uniqueness 4. Test with single-file edits first, then combine into multi-edit

Note on Trailing Newlines: All files will always end with exactly one newline character after editing.

property name: str

Tool name.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

class atloop.tools.filesystem.GlobFilesTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for finding files using gitignore-style glob patterns.

Features: - Supports common glob patterns (, *) - Recursive directory searching - File filtering by extension or pattern

Use cases: - Finding all Python files: *.py - Finding all test files: test_*.py - Finding files recursively: **/*.js - Listing files in a directory: dir/*.txt

__init__(sandbox: SandboxAdapter)[source]

Initialize glob files tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute glob tool to find files matching a pattern.

Args:
args: Tool arguments dictionary
  • pattern (str, required): Glob pattern to match files. Supports: - *.py: Matches all .py files in current directory - **/*.py: Matches all .py files recursively - test_*.py: Matches files starting with “test_” - dir/*.txt: Matches .txt files in “dir” directory

  • max_results (int, optional): Maximum number of results to return. Default: 100. Use this to limit output for very large matches.

Returns:

ToolResult with: - ok (bool): True if pattern was executed successfully (no errors in stderr) - stdout (str): Formatted list of matched files, one per line - stderr (str): Error messages if any (empty string means success) - meta (dict): Contains pattern, max_results, matched_count, matched_files

Examples:

# Find all Python files glob(pattern=”*.py”)

# Find all Python files recursively glob(pattern=”**/*.py”)

# Find test files glob(pattern=”test_*.py”)

# Find files in specific directory glob(pattern=”src/*.py”)

# Limit results glob(pattern=”*.py”, max_results=10)

Pattern Support: - *: Matches any characters (except path separator) - **: Matches any characters including path separators (recursive) - Directory patterns: dir/*.ext matches files in “dir” directory - Leading ./ is optional and ignored

Error Handling: - Success is determined by stderr content, not exit code - If stderr is empty, the operation succeeded - Empty results (no matches) is considered success (ok=True) - Check stderr for specific error messages if ok=False

property name: str

Tool name.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

System Tools

System tools.

class atloop.tools.system.RunCommandTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for executing shell commands in the sandbox workspace.

⚠️ This is the primary tool for executing system commands!

Use cases: - Running build commands (make, npm, pip, etc.) - Running tests (pytest, unittest, etc.) - Executing scripts (python3, node, etc.) - File operations (ls, cat, grep, find, etc.) - System checks (which, type, etc.)

Important notes: - Commands run in /workspace directory - Success is determined by stderr content, NOT exit code - Many commands return exit_code=0 even with errors - Always check stdout and stderr content to judge success

__init__(sandbox: SandboxAdapter)[source]

Initialize run command tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute shell command in the sandbox workspace.

⚠️ IMPORTANT: This is the primary tool for executing system commands! Use this instead of trying to execute commands through other means.

Args:
args: Tool arguments dictionary
  • cmd (str, required): Shell command to execute. Can be any valid shell command. Examples: “ls -la”, “python3 script.py”, “grep -rn ‘pattern’ .”, etc.

  • timeout_sec (int, optional): Timeout in seconds. Default: 600 (10 minutes). Use shorter timeouts for quick commands, longer for builds/tests.

Returns:

ToolResult with: - ok (bool): True if command succeeded (no errors in stderr) - stdout (str): Standard output from the command - stderr (str): Standard error from the command (empty string means success) - meta (dict): Contains cmd, duration_ms

Examples:

# List files run(cmd=”ls -la”)

# Run Python script run(cmd=”python3 script.py”)

# Run tests run(cmd=”pytest tests/”)

# Search for pattern run(cmd=”grep -rn ‘def function’ .”)

# View file content run(cmd=”cat file.py”) run(cmd=”head -n 50 file.py”) run(cmd=”tail -n 20 file.py”)

⚠️ Critical: Success Determination - DO NOT rely on exit_code - it’s unreliable! - Success = empty stderr (no error messages) - Failure = non-empty stderr (contains error messages) - Many commands return exit_code=0 even with errors (e.g., pytest collection errors) - Always read stdout and stderr content to judge success

⚠️ Hard requirement: avoid “triple-layer quoting hell” If use python3 -c “….”, you must use single quotes inside the string following “-c”. Example: {

“tool”: “run”, “args”: {

“cmd”: “python3 -c "import sys; sys.path.insert(0, ‘.’); from jira_client import JiraClient; client = JiraClient(); projects = client.get_projects(); print(‘Projects:’); for p in projects: print(f" {p[‘key’]}: {p[‘name’]}")"”

}

}

Common Commands: - File viewing: cat, head, tail, less, more - File search: grep, find, locate - Text processing: sed, awk, cut, sort, uniq - File operations: ls, pwd, cd, mkdir, rm, cp, mv - Python: python3 (not python), pip3 (not pip) - Other: echo, wc, diff, which, type

Error Handling: - Success is determined by stderr content, not exit code - If stderr is empty, the command succeeded - If stderr contains “error”, “failed”, “exception”, etc., command likely failed - Always check stderr content, not just ok field

⚠️ IMPORTANT: For Complex Python/Shell Scripts, Use Specialized Tools

DO NOT use run with python3 -c “…” or bash -c “…” for complex scripts! This causes shell escaping issues (quotes, f-strings, etc.).

Instead, use: - run_python_script_string for Python code execution (use PYTHON_SCRIPT_#N placeholder) - run_shell_script_string for complex shell scripts (use SHELL_SCRIPT_#N placeholder)

Use run only for simple commands: ls, cat, grep, find, pwd, python3 script.py, etc.

property name: str

Tool name.

property output_semantic_type: OutputSemanticType

EXECUTION_RESULT.

Note: File view commands are handled specially in OutputLimitStrategy based on command content, not semantic type.

Type:

Return semantic type

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

class atloop.tools.system.RunPythonScriptStringTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for executing Python code strings without shell escaping issues.

Use this tool instead of `run` with `python3 -c “…”` for complex Python code.

Benefits: - No shell escaping issues (quotes, f-strings, etc.) - Better error messages (can show script content) - Cleaner code (no need to escape quotes)

Usage: Use PYTHON_SCRIPT_#N placeholder in JSON, then provide script content: {

“tool”: “run_python_script_string”, “args”: {

“script”: “PYTHON_SCRIPT_#1”

}

} —(PYTHON_SCRIPT_#1)— import sys from jira_client import JiraClient

client = JiraClient() projects = client.get_projects() for p in projects:

print(f”{p[‘key’]}: {p[‘name’]}”)

Important notes: - Script runs in /workspace directory - Success is determined by stderr content, NOT exit code - Script is written to a temporary file, executed, then cleaned up - Python path includes /workspace automatically

__init__(sandbox: SandboxAdapter)[source]

Initialize run Python script string tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute Python script string.

Args:
args: Tool arguments dictionary
  • script (str, required): Python code to execute. Can be multi-line. Should use PYTHON_SCRIPT_#N placeholder in JSON, actual content provided separately.

  • timeout_sec (int, optional): Timeout in seconds. Default: 600 (10 minutes).

Returns:

ToolResult with: - ok (bool): True if script succeeded (no errors in stderr) - stdout (str): Standard output from the script - stderr (str): Standard error from the script (empty string means success) - meta (dict): Contains script_preview, duration_ms

Examples:

# Simple script run_python_script_string(script=”PYTHON_SCRIPT_#1”) —(PYTHON_SCRIPT_#1)— print(“Hello, World!”) —

# Complex script with imports run_python_script_string(script=”PYTHON_SCRIPT_#1”) —(PYTHON_SCRIPT_#1)— import sys sys.path.insert(0, ‘.’) from my_module import MyClass obj = MyClass() result = obj.process() print(f”Result: {result}”) —

⚠️ Critical: Success Determination - DO NOT rely on exit_code - it’s unreliable! - Success = empty stderr (no error messages) - Failure = non-empty stderr (contains error messages) - Always read stdout and stderr content to judge success

property name: str

Tool name.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

class atloop.tools.system.RunShellScriptStringTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for executing shell script strings without shell escaping issues.

Use this tool instead of `run` with `bash -c “…”` for complex shell scripts.

Benefits: - No shell escaping issues (quotes, variables, etc.) - Better error messages (can show script content) - Cleaner code (no need to escape quotes) - Supports multi-line scripts easily

Usage: Use SHELL_SCRIPT_#N placeholder in JSON, then provide script content: {

“tool”: “run_shell_script_string”, “args”: {

“script”: “SHELL_SCRIPT_#1”

}

} —(SHELL_SCRIPT_#1)— #!/bin/bash set -e

echo “Processing files…” for file in *.txt; do

if [ -f “$file” ]; then

echo “Found: $file” wc -l “$file”

fi

done —

Important notes: - Script runs in /workspace directory - Success is determined by stderr content, NOT exit code - Script is written to a temporary file, executed, then cleaned up - Uses bash to execute the script

__init__(sandbox: SandboxAdapter)[source]

Initialize run shell script string tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute shell script string.

Args:
args: Tool arguments dictionary
  • script (str, required): Shell script to execute. Can be multi-line. Should use SHELL_SCRIPT_#N placeholder in JSON, actual content provided separately.

  • timeout_sec (int, optional): Timeout in seconds. Default: 600 (10 minutes).

Returns:

ToolResult with: - ok (bool): True if script succeeded (no errors in stderr) - stdout (str): Standard output from the script - stderr (str): Standard error from the script (empty string means success) - meta (dict): Contains script_preview, duration_ms

Examples:

# Simple script run_shell_script_string(script=”SHELL_SCRIPT_#1”) —(SHELL_SCRIPT_#1)— echo “Hello, World!” ls -la —

# Complex script with loops and conditionals run_shell_script_string(script=”SHELL_SCRIPT_#1”) —(SHELL_SCRIPT_#1)— #!/bin/bash set -e

for file in *.py; do
if [ -f “$file” ]; then

echo “Processing $file” python3 -m py_compile “$file”

fi

done —

⚠️ Critical: Success Determination - DO NOT rely on exit_code - it’s unreliable! - Success = empty stderr (no error messages) - Failure = non-empty stderr (contains error messages) - Always read stdout and stderr content to judge success

property name: str

Tool name.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

Search Tools

Search tools.

class atloop.tools.search.SearchTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Enhanced tool for searching file contents using grep with regex, context lines, and file filtering.

Features: - Full regex pattern support - Context lines (before/after matches) - File filtering by glob pattern - Multiple output modes (content, files, count) - Case-insensitive search option

Use cases: - Finding function definitions: search(‘def function_name’) - Finding imports: search(‘^import |^from ‘) - Finding specific patterns: search(‘TODO|FIXME’) - Searching in specific file types: search(‘pattern’, glob=’*.py’)

__init__(sandbox: SandboxAdapter)[source]

Initialize search tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute enhanced search tool to find patterns in files.

Args:
args: Tool arguments dictionary
  • query (str, required): Search query as regex pattern. Supports full regex syntax. Examples: “def function”, “^import “, “TODO|FIXME”, “class w+”

  • glob (str, optional): Glob pattern to filter files. Examples: “.py”, “*/*.js”

  • output_mode (str, optional): Output mode. Default: “content” - “content”: Show matching lines with context (default) - “files_with_matches”: Show only file paths that contain matches - “count”: Show match count per file

  • -A (int, optional): Number of lines to show after each match

  • -B (int, optional): Number of lines to show before each match

  • -C (int, optional): Number of lines to show before and after each match

  • -i (bool, optional): Case-insensitive search. Default: False

  • -n (bool, optional): Show line numbers. Default: True

  • max_results (int, optional): Maximum number of results to return. Default: 50. Limits output for very large result sets.

Returns:

ToolResult with: - ok (bool): True if search executed successfully (no errors in stderr) - stdout (str): Search results (matching lines, file paths, or counts) - stderr (str): Error messages if any (empty string means success) - meta (dict): Contains query, glob, output_mode, max_results, cmd

Examples:

# Find function definitions search(query=”def w+”, glob=”*.py”)

# Find imports with context search(query=”^import |^from “, glob=”*.py”, -C=2)

# Find TODO comments (case-insensitive) search(query=”TODO|FIXME”, -i=True)

# Find files containing pattern (without showing content) search(query=”def main”, output_mode=”files_with_matches”)

# Count matches per file search(query=”class w+”, output_mode=”count”)

Regex Pattern Tips: - Use ^ for start of line: ^def matches “def” at line start - Use $ for end of line: import$ matches “import” at line end - Use | for alternation: TODO|FIXME matches either - Use w+ for word characters: def w+ matches “def function_name” - Escape special chars: . matches literal dot

Context Lines: - Use -C=3 to show 3 lines before and after each match - Use -B=5 to show 5 lines before each match - Use -A=2 to show 2 lines after each match - Context helps understand code structure around matches

Error Handling: - Success is determined by stderr content, not exit code - If stderr is empty, the search succeeded - No matches found is considered success (ok=True, empty stdout) - Check stderr for specific error messages if ok=False

property name: str

Tool name.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

Interaction Tools

Interaction tools module.

class atloop.tools.interaction.TodoReadTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for reading and displaying the current task list from TODO.md.

Use cases: - Checking current task status - Reviewing progress on multi-step tasks - Understanding what work is in progress - Planning next steps based on current status

__init__(sandbox: SandboxAdapter)[source]

Initialize todo read tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute todo read tool to read and display TODO.md.

Args:

args: Tool arguments dictionary (no arguments required)

Returns:

ToolResult with: - ok (bool): True if TODO.md was read successfully (no errors in stderr) - stdout (str): Formatted TODO list with tasks grouped by status - stderr (str): Error messages if any (empty string means success) - meta (dict): Contains todo_file, todo_count, pending, in_progress, completed

Examples:

# Read current TODO list todo_read()

Output Format: Tasks are grouped by status and displayed as: ``` # TODO List (3 task(s))

## In Progress 1. Task 1 (Running task 1)

## Pending 1. Task 2 (Will run task 2)

## Completed (1) 1. Task 3

Summary: 1 pending, 1 in progress, 1 completed ```

Behavior: - If TODO.md doesn’t exist: Returns ok=True with message to use todo_write - If TODO.md exists but is empty: Returns ok=True with message - If TODO.md has tasks: Returns formatted list grouped by status - Only shows first 5 completed tasks (to avoid clutter)

Error Handling: - Success is determined by stderr content, not exit code - If stderr is empty, the operation succeeded - Check stderr for specific error messages if ok=False

property name: str

Tool name.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.

class atloop.tools.interaction.TodoWriteTool(sandbox: SandboxAdapter)[source]

Bases: BaseTool

Tool for creating and managing task lists in TODO.md format.

Use cases: - Tracking progress on complex, multi-step tasks - Managing task status (pending, in_progress, completed) - Organizing work into manageable chunks - Providing visibility into current work status

Task statuses: - pending: Task not yet started - in_progress: Task currently being worked on - completed: Task finished

Best practices: - At least one task should be in_progress at any time - Use activeForm to describe what’s happening (e.g., “Running tests”) - Update status as work progresses

__init__(sandbox: SandboxAdapter)[source]

Initialize todo write tool.

Parameters:

sandbox – Sandbox adapter instance

property description: str

Tool description.

execute(args: Dict[str, Any]) ToolResult[source]

Execute todo write tool to create or update TODO.md.

Args:
args: Tool arguments dictionary
  • todos (list, required): List of todo items. Each item is a dictionary with:
    • content (str, required): Task content in imperative form. Example: “Run tests”, “Fix bug”, “Write documentation”

    • activeForm (str, required): Present continuous form describing the action. Example: “Running tests”, “Fixing bug”, “Writing documentation”

    • status (str, required): Task status. Must be one of: - “pending”: Task not yet started - “in_progress”: Task currently being worked on - “completed”: Task finished

Returns:

ToolResult with: - ok (bool): True if TODO.md was written successfully (no errors in stderr) - stdout (str): Summary of updated TODO list with counts by status - stderr (str): Error messages if any (empty string means success) - meta (dict): Contains todo_file, todo_count, pending, in_progress, completed

Examples:

# Create initial TODO list todo_write(todos=[

{

“content”: “Set up project structure”, “activeForm”: “Setting up project structure”, “status”: “in_progress”

}, {

“content”: “Write unit tests”, “activeForm”: “Writing unit tests”, “status”: “pending”

}

])

# Update TODO list (replaces entire list) todo_write(todos=[

{

“content”: “Set up project structure”, “activeForm”: “Setting up project structure”, “status”: “completed”

}, {

“content”: “Write unit tests”, “activeForm”: “Writing unit tests”, “status”: “in_progress”

}

])

Important Notes: - This tool replaces the entire TODO.md file with the new todos list - To update a single task, read current todos, modify, then write back - At least one task should be in_progress (warning shown if none) - TODO.md is created in the workspace root directory

File Format: The tool generates markdown format: ```markdown # TODO

## In Progress - [ ] Task 1 (Running task 1)

## Pending - [ ] Task 2 (Will run task 2)

## Completed - [x] Task 3 ```

Error Handling: - Success is determined by stderr content, not exit code - If stderr is empty, the operation succeeded - Check stderr for specific error messages if ok=False

property name: str

Tool name.

validate_args(args: Dict[str, Any]) tuple[bool, str | None][source]

Validate arguments.