Skip to main content
PraisonAI Code provides AI agents with powerful tools to read, write, and modify code files with surgical precision. Inspired by Kilo Code’s architecture, it uses a SEARCH/REPLACE diff strategy with fuzzy matching for reliable code modifications.

Quick Start

from praisonai.code import (
    set_workspace,
    code_read_file,
    code_write_file,
    code_apply_diff,
    code_list_files,
    code_execute_command,
    CODE_TOOLS,
)

# Set the workspace root
set_workspace("/path/to/your/project")

# Read a file with line numbers
content = code_read_file("src/main.py")
print(content)

# Apply a precise diff
diff = """<<<<<<< SEARCH
:start_line:10
-------
def old_function():
    pass
=======
def new_function():
    return True
>>>>>>> REPLACE"""

result = code_apply_diff("src/main.py", diff)
print(result)  # "Successfully applied 1 change(s) to src/main.py"

Available Tools

ToolDescription
code_read_fileRead file contents with optional line ranges
code_write_fileCreate or overwrite files
code_list_filesList directory contents with filtering
code_apply_diffApply SEARCH/REPLACE diffs with fuzzy matching
code_search_replaceSimple search and replace operations
code_execute_commandRun shell commands safely

Using with Agents

The CODE_TOOLS list contains all tools ready for use with PraisonAI agents:
from praisonaiagents import Agent
from praisonai.code import CODE_TOOLS, set_workspace

# Set workspace before creating agent
set_workspace("/path/to/project")

# Create an agent with code editing capabilities
agent = Agent(
    name="Code Editor",
    instructions="""You are a code editing assistant. 
    Use the code tools to read, modify, and write files.
    Always read a file before modifying it.""",
    tools=CODE_TOOLS
)

# The agent can now edit code
agent.start("Add error handling to the main.py file")

Tool Reference

code_read_file

Read file contents with optional line ranges and line number annotations.
from praisonai.code import code_read_file, set_workspace

set_workspace("/my/project")

# Read entire file
content = code_read_file("src/main.py")

# Read specific lines (1-indexed)
content = code_read_file("src/main.py", start_line=10, end_line=50)
Output format:
File: src/main.py (150 lines)

  1 | def hello():
  2 |     print("Hello, World!")
  3 |
  4 | def main():
  5 |     hello()

code_write_file

Create new files or completely replace existing files.
from praisonai.code import code_write_file, set_workspace

set_workspace("/my/project")

# Create a new file
result = code_write_file("src/new_module.py", """
def greet(name):
    return f"Hello, {name}!"
""")
print(result)  # "Created file: src/new_module.py (45 bytes)"

# Overwrite existing file
result = code_write_file("src/config.py", "DEBUG = True")
print(result)  # "Updated file: src/config.py (12 bytes)"
For partial modifications, use code_apply_diff instead of overwriting the entire file.

code_list_files

List files and directories with optional filtering.
from praisonai.code import code_list_files, set_workspace

set_workspace("/my/project")

# List current directory
files = code_list_files(".")

# List recursively with extension filter
files = code_list_files("src", recursive=True, extensions="py,js")
Output format:
Contents of src:
  📁 utils/
  📁 models/
  📄 main.py (2.5KB)
  📄 config.py (512B)
  📄 helpers.js (1.2KB)

code_apply_diff

Apply precise, surgical modifications using SEARCH/REPLACE diffs.
from praisonai.code import code_apply_diff, set_workspace

set_workspace("/my/project")

diff = """<<<<<<< SEARCH
:start_line:5
-------
def calculate_total(items):
    total = 0
    for item in items:
        total += item
    return total
=======
def calculate_total(items):
    \"\"\"Calculate total with 10% markup.\"\"\"
    return sum(item * 1.1 for item in items)
>>>>>>> REPLACE"""

result = code_apply_diff("src/utils.py", diff)

Diff Format

The diff format uses clear markers:
<<<<<<< SEARCH
:start_line:N
-------
[exact content to find]
=======
[new content to replace with]
>>>>>>> REPLACE
  • :start_line:N - Optional line number hint for faster matching
  • ------- - Separator after line hints
  • ======= - Divider between search and replace content
  • Multiple blocks can be included in a single diff

Multiple Changes

Apply multiple changes in one operation:
diff = """<<<<<<< SEARCH
:start_line:1
-------
import os
=======
import os
import sys
>>>>>>> REPLACE

<<<<<<< SEARCH
:start_line:20
-------
def old_function():
    pass
=======
def new_function():
    return True
>>>>>>> REPLACE"""

result = code_apply_diff("src/main.py", diff)
# "Successfully applied 2 change(s) to src/main.py"

code_search_replace

Simple search and replace for straightforward text substitutions.
from praisonai.code import code_search_replace, set_workspace

set_workspace("/my/project")

# Simple text replacement
result = code_search_replace(
    "src/main.py",
    search="old_variable_name",
    replace="new_variable_name"
)
print(result)  # "Replaced 5 occurrence(s) in src/main.py"

# Regex replacement
result = code_search_replace(
    "src/main.py",
    search=r"def (\w+)\(",
    replace=r"def renamed_\1(",
    is_regex=True
)

code_execute_command

Execute shell commands safely within the workspace.
from praisonai.code import code_execute_command, set_workspace

set_workspace("/my/project")

# Run tests
result = code_execute_command("python -m pytest tests/")
print(result)

# Run linter
result = code_execute_command("ruff check src/")

# Run in subdirectory
result = code_execute_command("npm test", cwd="frontend")

Fuzzy Matching

The diff strategy includes fuzzy matching using Levenshtein distance, which helps when:
  • Code has been slightly modified since you read it
  • There are minor whitespace differences
  • Line numbers have shifted due to other changes
from praisonai.code import apply_diff

# The tool uses a 95% similarity threshold by default
# This allows for minor variations while preventing incorrect matches

Indentation Preservation

When applying diffs, indentation is automatically preserved:
# Original file:
class MyClass:
    def method(self):
        pass

# Diff with different base indentation:
diff = """<<<<<<< SEARCH
:start_line:2
-------
    def method(self):
        pass
=======
    def method(self):
        return self.value
>>>>>>> REPLACE"""

# Result maintains correct indentation:
class MyClass:
    def method(self):
        return self.value

Security Features

Workspace Isolation

All file operations are restricted to the configured workspace:
set_workspace("/my/project")

# This works - within workspace
code_read_file("src/main.py")

# This fails - path traversal blocked
code_read_file("../../../etc/passwd")
# Error: Path '../../../etc/passwd' is outside the workspace

Gitignore Support

The code_list_files tool respects .gitignore patterns by default:
# Files in .gitignore are automatically excluded
files = code_list_files(".", recursive=True)
# node_modules/, __pycache__/, .git/ are excluded

Safe Command Execution

Commands are executed with safety checks:
from praisonai.code.tools.execute_command import is_safe_command

# Safe commands
is_safe_command("python test.py")  # True
is_safe_command("npm run build")   # True

# Potentially dangerous commands
is_safe_command("rm -rf /")        # False
is_safe_command("sudo apt install") # False

Low-Level API

For advanced use cases, you can use the low-level functions directly:
from praisonai.code import (
    read_file,
    write_file,
    apply_diff,
    DiffResult,
    apply_search_replace_diff,
)

# Low-level read (returns dict)
result = read_file("src/main.py", workspace="/my/project")
if result['success']:
    print(result['content'])
    print(f"Total lines: {result['total_lines']}")

# Low-level diff application
from praisonai.code.diff import apply_search_replace_diff

result = apply_search_replace_diff(
    original_content="def old(): pass",
    diff_content=diff,
    fuzzy_threshold=0.95,  # 95% similarity required
    buffer_lines=40,       # Search range around line hints
)

if result.success:
    print(result.content)
else:
    print(f"Error: {result.error}")

Helper Functions

Creating Diff Blocks Programmatically

from praisonai.code import create_diff_block, create_multi_diff

# Create a single diff block
diff = create_diff_block(
    search_content="def old():\n    pass",
    replace_content="def new():\n    return True",
    start_line=10
)

# Create multiple diff blocks
diff = create_multi_diff([
    {'search': 'old1', 'replace': 'new1', 'start_line': 5},
    {'search': 'old2', 'replace': 'new2', 'start_line': 20},
])

Best Practices

Read the file first to get the exact content for your SEARCH block:
content = code_read_file("src/main.py")
# Use the exact content from the file in your diff
Include :start_line:N for faster and more accurate matching:
<<<<<<< SEARCH
:start_line:42
-------
Group related changes in a single diff, but keep unrelated changes separate for easier debugging.
After applying a diff, read the file again or run tests to verify:
result = code_apply_diff("src/main.py", diff)
if "Successfully" in result:
    test_result = code_execute_command("python -m pytest tests/")

Complete Example

Here’s a complete workflow showing an agent that adds error handling to a function:
from praisonaiagents import Agent
from praisonai.code import CODE_TOOLS, set_workspace

# Configure workspace
set_workspace("/path/to/my/project")

# Create coding agent
agent = Agent(
    name="Error Handler",
    instructions="""You are a Python expert. Your task is to:
    1. Read the specified file
    2. Identify functions without error handling
    3. Add appropriate try/except blocks
    4. Verify the changes compile correctly
    
    Always use code_read_file before making changes.
    Use code_apply_diff for precise modifications.
    Run tests after making changes.""",
    tools=CODE_TOOLS
)

# Run the agent
result = agent.start(
    "Add error handling to all database functions in src/database.py"
)
print(result)