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.

abstract property description: str

Tool description.

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

Execute tool with given arguments.

abstract property name: str

Tool name.

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).

BaseTool

class atloop.tools.base.BaseTool[source]

Bases: ABC

Base class for all tools.

abstract property name: str

Tool name.

abstract property description: str

Tool description.

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).

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 and skill 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.

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.

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.

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

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: This tool uses heredoc (cat > file <<’FILE_EOF’) which automatically adds a trailing newline. The tool normalizes input to ensure files always end with exactly one newline: - If content ends with ‘n’, it’s removed before writing (heredoc adds one) - If content doesn’t end with ‘n’, heredoc adds one - Result: File always ends with exactly one newline character - Exception: Empty string content results in a file with one newline

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

__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

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.

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.

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

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

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.SkillTool(skill_loader=None)[source]

Bases: BaseTool

Tool for loading skill content on-demand.

When the LLM needs guidance from a skill (e.g., tool-usage, error-handling), it uses this tool to load the full skill content. The skill content is returned as stdout for the LLM to read and apply.

Use cases: - Loading tool usage best practices (tool-usage skill) - Loading error handling guidance (error-handling skill) - Loading domain-specific knowledge (any custom skill)

Note: This tool requires skill_loader to be configured in the ToolRegistry.

__init__(skill_loader=None)[source]

Initialize skill tool.

Parameters:

skill_loader – SkillLoader or EnhancedSkillLoader instance for loading skill content

property description: str

Tool description.

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

Load and return skill content.

Parameters:

args – Must contain ‘name’ (str) - the skill name to load

Returns:

ToolResult with skill content in stdout, or error in stderr

property name: str

Tool name.

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

Validate arguments.

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.