docs(tools): add comprehensive documentation for all tool packages

Add detailed documentation with examples for:
- hanzo-tools-fs: read, write, edit, tree, find, search, ast
- hanzo-tools-shell: cmd, ps, zsh, bash, auto-backgrounding
- hanzo-tools-browser: 70+ Playwright actions, device emulation
- hanzo-tools-memory: memories, facts, knowledge bases, scopes
- hanzo-tools-reasoning: think and critic tools
- hanzo-tools-lsp: go-to-definition, references, rename, hover
- hanzo-tools-refactor: rename, extract, inline, batch operations
- hanzo-tools-agent: multi-agent orchestration, consensus, swarm
- hanzo-tools-llm: unified LLM interface with 100+ models

Each doc includes:
- Installation instructions
- Quick start examples
- Full API reference
- Usage examples
- Best practices
This commit is contained in:
2026-01-05 17:27:46 -08:00
parent bf551f3b44
commit b24f09e28c
10 changed files with 3145 additions and 20 deletions
+363 -2
View File
@@ -1,2 +1,363 @@
# agent
Documentation coming soon.
# hanzo-tools-agent
Multi-agent orchestration with CLI spawning, DAG execution, swarm distribution, and Metastable consensus.
## Installation
```bash
pip install hanzo-tools-agent
```
With optional features:
```bash
pip install hanzo-tools-agent[api] # httpx for direct API mode
pip install hanzo-tools-agent[perf] # uvloop for high performance
pip install hanzo-tools-agent[full] # All features
```
## Overview
`hanzo-tools-agent` provides:
- **agent** - Multi-agent orchestration (run, dag, swarm, consensus, dispatch)
- **iching** - I Ching wisdom for engineering decisions
- **review** - Code review tool
## Quick Start
```python
# Run a single agent
agent(action="run", name="claude", prompt="Explain this code")
# List available agents
agent(action="list")
# Run consensus across multiple models
agent(action="consensus", prompt="Best approach for caching?", agents=["claude", "gemini", "codex"])
# Swarm pattern - distribute work
agent(action="swarm", items=["file1.py", "file2.py"], template="Review {item}")
# DAG execution with dependencies
agent(action="dag", tasks=[
{"id": "analyze", "prompt": "Analyze the codebase"},
{"id": "plan", "prompt": "Create implementation plan", "after": ["analyze"]}
])
```
## Available Agents
| Agent | Description | API Key Env |
|-------|-------------|-------------|
| `claude` | Anthropic Claude Code CLI | `ANTHROPIC_API_KEY` |
| `codex` | OpenAI Codex CLI | `OPENAI_API_KEY` |
| `gemini` | Google Gemini CLI | `GOOGLE_API_KEY` |
| `grok` | xAI Grok CLI | `XAI_API_KEY` |
| `qwen` | Alibaba Qwen CLI | `DASHSCOPE_API_KEY` |
| `vibe` | Vibe coding agent | - |
| `dev` | Hanzo Dev agent | - |
## Actions Reference
### run
Run a single agent with a prompt.
```python
# Default agent (claude in Claude Code environment)
agent(action="run", prompt="Explain this error")
# Specific agent
agent(action="run", name="gemini", prompt="Review this code")
# With working directory
agent(action="run", name="codex", prompt="Fix the tests", cwd="/project/path")
# With timeout
agent(action="run", name="claude", prompt="Complex task", timeout=300)
```
**Parameters:**
- `name`: Agent to use (default: auto-detect)
- `prompt` (required): Task for the agent
- `cwd`: Working directory
- `timeout`: Timeout in seconds (default: 300)
### dag
Execute tasks with dependencies using a DAG (Directed Acyclic Graph).
```python
agent(
action="dag",
tasks=[
{"id": "research", "prompt": "Research best practices for caching"},
{"id": "design", "prompt": "Design cache architecture", "after": ["research"]},
{"id": "implement", "prompt": "Implement the cache", "after": ["design"]},
{"id": "test", "prompt": "Write tests", "after": ["implement"]}
]
)
```
**Task format:**
- `id` (required): Unique task identifier
- `prompt` (required): Task description
- `after`: List of task IDs that must complete first
- `agent`: Specific agent for this task (optional)
### swarm
Distribute work across multiple agents in parallel.
```python
# Process multiple files
agent(
action="swarm",
items=["auth.py", "api.py", "models.py"],
template="Review {item} for security issues",
max_concurrent=5
)
# Multiple prompts
agent(
action="swarm",
items=["Add error handling", "Add logging", "Add tests"],
template="{item} to the authentication module"
)
```
**Parameters:**
- `items` (required): List of items to process
- `template` (required): Prompt template with `{item}` placeholder
- `max_concurrent`: Maximum parallel agents (default: 100)
### consensus
Run Metastable consensus across multiple models.
```python
agent(
action="consensus",
prompt="What's the best database for this use case?",
agents=["claude", "gemini", "codex"],
rounds=3, # Consensus rounds
k=3, # Sample size per round
alpha=0.6, # Agreement threshold
beta_1=0.5, # Preference threshold
beta_2=0.8 # Decision threshold
)
```
**Parameters:**
- `prompt` (required): Question for consensus
- `agents`: Models to participate (default: all available)
- `rounds`: Number of consensus rounds (default: 3)
- `k`: Sample size per round (default: 3)
- `alpha`: Agreement threshold (default: 0.6)
- `beta_1`: Phase I preference threshold (default: 0.5)
- `beta_2`: Phase II decision threshold (default: 0.8)
**Consensus Protocol:**
Based on [Metastable Consensus](https://github.com/luxfi/consensus):
- Phase I (Sampling): k-peer sampling, confidence accumulation
- Phase II (Finality): Threshold aggregation, winner synthesis
### dispatch
Route different tasks to different agents.
```python
agent(
action="dispatch",
tasks=[
{"agent": "claude", "prompt": "Review code quality"},
{"agent": "codex", "prompt": "Suggest optimizations"},
{"agent": "gemini", "prompt": "Check documentation"}
]
)
```
### list
List all available agents.
```python
agent(action="list")
```
**Response:**
```json
{
"agents": ["claude", "codex", "gemini", "grok", "qwen", "vibe", "dev"],
"available": ["claude", "gemini"],
"configured": ["claude", "codex", "gemini"]
}
```
### status
Check if a specific agent is available.
```python
agent(action="status", name="claude")
```
### config
Show agent configuration.
```python
agent(action="config")
```
## Agent Configuration
### Config Files
Configure agents via `~/.hanzo/agents/<name>.json`:
```json
{
"cmd": "claude",
"args": ["--print", "--dangerously-skip-permissions"],
"env_key": "ANTHROPIC_API_KEY",
"max_turns": 999,
"session": true,
"model": "claude-3-opus",
"system_prompt": "You are a helpful assistant"
}
```
### Environment Overrides
Override arguments via environment:
```bash
export HANZO_AGENT_CLAUDE_ARGS="--verbose --model claude-3-5-sonnet"
```
### API Mode
Configure direct API calls (no CLI needed):
```json
{
"endpoint": "https://api.openai.com/v1/chat/completions",
"api_type": "openai",
"model": "gpt-4",
"env_key": "OPENAI_API_KEY",
"system_prompt": "You are a helpful assistant"
}
```
## YOLO Mode
All agents are configured with autonomous operation flags:
| Agent | YOLO Flags |
|-------|------------|
| claude | `--dangerously-skip-permissions`, `--print`, `--output-format text` |
| codex | `--full-auto` |
| gemini | `-y`, `-q` |
| grok | `-y` |
| qwen | `--approval-mode yolo`, `-p` |
| vibe | `--auto-approve`, `--max-turns 999`, `-p` |
## Auto-Backgrounding
Long-running agents automatically background after timeout:
```python
# Long task - will auto-background
agent(action="run", name="claude", prompt="Complex refactoring task", timeout=300)
# Check status with ps tool
ps() # List all processes
ps(logs="agent_xxx") # View output
ps(kill="agent_xxx") # Stop process
```
## IChingTool
Apply I Ching wisdom to engineering challenges.
```python
iching(challenge="How should I approach refactoring this legacy codebase?")
```
**Response:**
- Hexagram interpretation
- Relevant Hanzo principles
- Actionable recommendations
## ReviewTool
Request balanced code review.
```python
review(
focus="FUNCTIONALITY",
work_description="Implemented auto-import feature for Go files",
code_snippets=["func AddImport(file string) error { ... }"],
file_paths=["/path/to/import_handler.go"],
context="This will be used to automatically fix missing imports"
)
```
**Focus areas:**
- `GENERAL` - Overall code quality
- `FUNCTIONALITY` - Does it work correctly?
- `READABILITY` - Is it easy to understand?
- `MAINTAINABILITY` - Is it easy to modify?
- `TESTING` - Is it well tested?
- `DOCUMENTATION` - Is it well documented?
- `ARCHITECTURE` - Is the design sound?
## Examples
### Multi-Agent Code Review
```python
# Get perspectives from multiple agents
agent(
action="consensus",
prompt="Review this pull request for issues",
agents=["claude", "gemini", "codex"]
)
```
### Parallel File Processing
```python
# Review all files in parallel
agent(
action="swarm",
items=["src/auth.py", "src/api.py", "src/models.py", "src/utils.py"],
template="Review {item} and suggest improvements",
max_concurrent=4
)
```
### Sequential Workflow
```python
# Plan → Implement → Test
agent(
action="dag",
tasks=[
{"id": "plan", "prompt": "Create implementation plan for user auth"},
{"id": "implement", "prompt": "Implement the plan", "after": ["plan"]},
{"id": "test", "prompt": "Write comprehensive tests", "after": ["implement"]},
{"id": "review", "prompt": "Review implementation", "after": ["test"]}
]
)
```
## Best Practices
1. **Use consensus for decisions** - Multiple perspectives reduce bias
2. **Use swarm for bulk operations** - Parallel processing is faster
3. **Use DAG for workflows** - Dependencies ensure correct ordering
4. **Configure timeouts appropriately** - Complex tasks need more time
5. **Check agent availability** - Use `status` before assuming an agent exists
+350 -2
View File
@@ -1,2 +1,350 @@
# urowser
Documentation coming soon.
# hanzo-tools-browser
Complete browser automation with full Playwright API. Provides 70+ actions for navigation, forms, mouse control, assertions, and more.
## Installation
```bash
pip install hanzo-tools-browser
playwright install chromium
```
Or as part of the full toolkit:
```bash
pip install hanzo-mcp[tools-all]
playwright install chromium
```
## Overview
`hanzo-tools-browser` provides comprehensive browser automation:
- **Navigation**: navigate, reload, go_back, go_forward
- **Input**: click, type, fill, press, select_option
- **Mouse**: hover, drag, scroll, mouse_move
- **Touch**: tap, swipe, pinch (mobile emulation)
- **Assertions**: expect_visible, expect_text, expect_url
- **Content**: get_text, get_attribute, screenshot
- **Storage**: cookies, localStorage, sessionStorage
- **Network**: route (mock/block requests)
## Quick Start
```python
# Navigate to page
browser(action="navigate", url="https://example.com")
# Click a button
browser(action="click", selector="button.submit")
# Fill a form
browser(action="fill", selector="input[name='email']", text="[email protected]")
# Take screenshot
browser(action="screenshot", full_page=True)
```
## Device Emulation
Built-in device presets for responsive testing:
```python
# User-friendly aliases
browser(action="emulate", device="mobile") # iPhone-like (390x844)
browser(action="emulate", device="tablet") # iPad-like (1024x1366)
browser(action="emulate", device="laptop") # MacBook-like (1440x900)
browser(action="emulate", device="desktop") # Full HD (1920x1080)
# Specific devices
browser(action="emulate", device="iphone_14")
browser(action="emulate", device="pixel_7")
browser(action="emulate", device="ipad_pro")
```
## Navigation
```python
# Basic navigation
browser(action="navigate", url="https://example.com")
browser(action="reload")
browser(action="go_back")
browser(action="go_forward")
# Get page info
browser(action="url") # Current URL
browser(action="title") # Page title
browser(action="content") # HTML content
```
## Input Actions
```python
# Click variants
browser(action="click", selector="button")
browser(action="dblclick", selector=".item")
browser(action="right_click", selector=".context-menu")
# Text input
browser(action="type", selector="input", text="Hello", interval=0.1)
browser(action="fill", selector="input", text="Instant fill")
browser(action="clear", selector="input")
# Keyboard
browser(action="press", key="Enter")
browser(action="press", key="Control+c")
```
## Form Handling
```python
# Select dropdowns
browser(action="select_option", selector="select", value="option1")
# Checkboxes
browser(action="check", selector="input[type='checkbox']")
browser(action="uncheck", selector="input[type='checkbox']")
# File uploads
browser(action="upload", selector="input[type='file']", files=["./doc.pdf"])
```
## Mouse Control
```python
# Hover
browser(action="hover", selector=".menu-item")
# Drag and drop
browser(action="drag", selector=".draggable", target_selector=".dropzone")
# Scroll
browser(action="scroll", delta_y=500)
browser(action="scroll", selector=".container", delta_y=300)
# Mouse coordinates
browser(action="mouse_move", x=100, y=200)
browser(action="mouse_down")
browser(action="mouse_up")
```
## Touch & Mobile
```python
# Touch actions
browser(action="tap", selector="button")
browser(action="swipe", direction="up", distance=300)
browser(action="pinch", scale=0.5) # Zoom out
browser(action="pinch", scale=2.0) # Zoom in
```
## Locators
```python
# CSS/XPath
browser(action="locator", selector="div.class")
browser(action="locator", selector="//button[@id='submit']")
# Semantic locators
browser(action="get_by_role", role="button", name="Submit")
browser(action="get_by_text", text="Click me")
browser(action="get_by_label", text="Email")
browser(action="get_by_placeholder", text="Enter email")
browser(action="get_by_test_id", text="submit-btn")
# Composition
browser(action="first", selector=".items")
browser(action="last", selector=".items")
browser(action="nth", selector=".items", index=2)
browser(action="filter", selector=".items", has_text="Important")
```
## Assertions
```python
# Element assertions
browser(action="expect_visible", selector=".modal")
browser(action="expect_hidden", selector=".loading")
browser(action="expect_enabled", selector="button")
browser(action="expect_text", selector="h1", expected="Welcome")
browser(action="expect_count", selector=".items", index=5)
# Page assertions
browser(action="expect_url", expected="*/dashboard*")
browser(action="expect_title", expected="Dashboard")
# Negative assertions
browser(action="expect_visible", selector=".loading", not_=True)
```
## Content Extraction
```python
# Get text content
browser(action="get_text", selector="h1")
browser(action="get_inner_text", selector=".content")
# Get attributes
browser(action="get_attribute", selector="a", attribute="href")
browser(action="get_value", selector="input")
# Get HTML
browser(action="get_html", selector=".container")
# Get bounding box
browser(action="get_bounding_box", selector=".element")
```
## State Checking
```python
browser(action="is_visible", selector=".modal")
browser(action="is_hidden", selector=".loading")
browser(action="is_enabled", selector="button")
browser(action="is_editable", selector="input")
browser(action="is_checked", selector="input[type='checkbox']")
```
## Screenshots & PDFs
```python
# Screenshots
browser(action="screenshot")
browser(action="screenshot", full_page=True)
browser(action="screenshot", selector=".chart")
# PDF export
browser(action="pdf")
```
## Wait Operations
```python
# Wait for load states
browser(action="wait_for_load", state="networkidle")
browser(action="wait_for_url", url="*/success*")
# Wait for elements
browser(action="wait", selector=".loaded", state="visible")
browser(action="wait", timeout=5000)
# Wait for events
browser(action="wait_for_event", event="download")
browser(action="wait_for_response", pattern="*/api/*")
```
## Network Interception
```python
# Mock API responses
browser(
action="route",
pattern="*/api/users*",
response={"users": [{"name": "Mock User"}]},
status_code=200
)
# Block requests
browser(action="route", pattern="*.png", block=True)
# Remove route
browser(action="unroute", pattern="*/api/users*")
```
## Storage
```python
# Cookies
browser(action="cookies")
browser(action="cookies", cookies=[{"name": "token", "value": "abc"}])
browser(action="clear_cookies")
# Local/Session storage
browser(action="storage", storage_type="local")
browser(action="storage", storage_type="session", storage_data={"key": "value"})
# Save/restore auth state
browser(action="storage_state", auth_file="./auth.json")
```
## Tab Management
```python
# Multiple tabs
browser(action="new_tab", url="https://example.com")
browser(action="tabs") # List all tabs
browser(action="close_tab", tab_index=1)
```
## Parallel Agents
For parallel execution, create isolated contexts:
```python
# Create new context (isolated cookies/storage)
browser(action="new_context")
# Each agent uses separate context
# One Chrome process, many parallel sessions
```
## Configuration
### Headless Mode
```python
# Toggle headless mode
browser(action="set_headless", headless=True)
browser(action="set_headless", headless=False) # Show browser
```
### CDP Connection
Share browser instance across MCPs:
```bash
BROWSER_CDP_ENDPOINT=http://localhost:9222 hanzo-mcp
```
## Examples
### Login Flow
```python
# Navigate to login
browser(action="navigate", url="https://app.example.com/login")
# Fill credentials
browser(action="fill", selector="input[name='email']", text="[email protected]")
browser(action="fill", selector="input[name='password']", text="password123")
# Submit
browser(action="click", selector="button[type='submit']")
# Wait for redirect
browser(action="wait_for_url", url="*/dashboard*")
# Verify login
browser(action="expect_visible", selector=".user-menu")
```
### E2E Test
```python
# Test shopping cart
browser(action="navigate", url="https://shop.example.com")
browser(action="click", selector=".product-card:first-child button")
browser(action="expect_text", selector=".cart-count", expected="1")
browser(action="click", selector=".cart-icon")
browser(action="expect_visible", selector=".cart-modal")
browser(action="expect_text", selector=".total", expected="$99.00")
```
### Screenshot Comparison
```python
# Capture baseline
browser(action="navigate", url="https://example.com")
browser(action="screenshot", full_page=True)
# Returns base64 image for comparison
```
+261 -2
View File
@@ -1,2 +1,261 @@
# core
Documentation coming soon.
# hanzo-tools-core
The foundation package for all Hanzo tool implementations. Provides base classes, type definitions, and utilities for building MCP-compatible tools.
## Installation
```bash
pip install hanzo-tools-core
```
Or as part of the full toolkit:
```bash
pip install hanzo-mcp[tools-all]
```
## Overview
`hanzo-tools-core` provides:
- **BaseTool** - Abstract base class for all tool implementations
- **FileSystemTool** - Specialized base for file operations
- **ToolRegistry** - Central registry for tool management
- **MCPResourceDocument** - Structured response format
- **ToolContext** - Runtime context for tool execution
- **PermissionManager** - Path-based access control
## Quick Start
### Creating a Custom Tool
```python
from hanzo_tools.core import BaseTool, ToolContext
class MyTool(BaseTool):
"""A custom tool implementation."""
@property
def name(self) -> str:
return "my_tool"
@property
def description(self) -> str:
return "Does something useful"
async def call(self, ctx: ToolContext, message: str) -> str:
"""Execute the tool.
Args:
ctx: Tool execution context
message: Input message to process
Returns:
Processed result
"""
return f"Processed: {message}"
def register(self, mcp_server):
"""Register with MCP server."""
@mcp_server.tool(name=self.name, description=self.description)
async def handler(message: str) -> str:
ctx = ToolContext()
return await self.call(ctx, message=message)
```
### Using the Tool Registry
```python
from hanzo_tools.core import ToolRegistry, BaseTool
# Register tools
registry = ToolRegistry()
registry.register(MyTool())
# Get a tool by name
tool = registry.get("my_tool")
# List all registered tools
for name, tool in registry.items():
print(f"{name}: {tool.description}")
```
## Base Classes
### BaseTool
The abstract base class all tools must inherit from:
```python
from abc import ABC, abstractmethod
class BaseTool(ABC):
"""Abstract base class for all Hanzo tools."""
@property
@abstractmethod
def name(self) -> str:
"""Unique identifier for the tool."""
...
@property
@abstractmethod
def description(self) -> str:
"""Human-readable description shown to LLMs."""
...
@abstractmethod
async def call(self, ctx: ToolContext, **params) -> str:
"""Execute the tool with given parameters."""
...
@abstractmethod
def register(self, mcp_server: FastMCP) -> None:
"""Register the tool with an MCP server."""
...
```
### FileSystemTool
Specialized base class for tools that operate on the filesystem:
```python
from hanzo_tools.core import FileSystemTool
class ReadTool(FileSystemTool):
"""Read file contents."""
@property
def name(self) -> str:
return "read"
async def call(self, ctx, file_path: str) -> str:
# Automatic path validation and permission checking
validated_path = self.validate_path(file_path)
async with aiofiles.open(validated_path) as f:
return await f.read()
```
## Response Format
### MCPResourceDocument
Structured format for tool responses:
```python
from hanzo_tools.core import MCPResourceDocument
# Create a document response
doc = MCPResourceDocument(
uri="file:///path/to/file.py",
mime_type="text/x-python",
text="def hello(): pass"
)
# Convert to JSON string for MCP
response = doc.to_json_string()
```
## Context Management
### ToolContext
Runtime context passed to every tool invocation:
```python
from hanzo_tools.core import ToolContext, create_tool_context
# Create context with custom settings
ctx = create_tool_context(
allowed_paths=["/home/user/project"],
enable_write=True,
timeout=30.0
)
# Access context in tool
async def call(self, ctx: ToolContext, **params):
if ctx.enable_write:
# Perform write operation
...
```
## Permission Management
### PermissionManager
Controls which paths tools can access:
```python
from hanzo_tools.core import PermissionManager
pm = PermissionManager(
allowed_paths=[
"/home/user/project",
"/tmp"
],
denied_paths=[
"/home/user/project/.env",
"/home/user/project/secrets"
]
)
# Check if path is allowed
if pm.is_allowed("/home/user/project/src/main.py"):
# Safe to access
...
```
## Decorators
### auto_timeout
Automatically handle timeouts for long-running operations:
```python
from hanzo_tools.core import auto_timeout
class SlowTool(BaseTool):
@auto_timeout(seconds=30)
async def call(self, ctx, **params):
# Will automatically timeout after 30 seconds
result = await slow_operation()
return result
```
## Error Handling
Tools should return error messages as strings rather than raising exceptions:
```python
async def call(self, ctx, file_path: str) -> str:
try:
content = await read_file(file_path)
return content
except FileNotFoundError:
return f"Error: File not found: {file_path}"
except PermissionError:
return f"Error: Permission denied: {file_path}"
except Exception as e:
return f"Error: {type(e).__name__}: {str(e)}"
```
## API Reference
::: hanzo_tools.core.base.BaseTool
options:
show_source: false
members:
- name
- description
- call
- register
::: hanzo_tools.core.base.FileSystemTool
::: hanzo_tools.core.base.ToolRegistry
::: hanzo_tools.core.types.MCPResourceDocument
::: hanzo_tools.core.context.ToolContext
::: hanzo_tools.core.permissions.PermissionManager
+326 -2
View File
@@ -1,2 +1,326 @@
# fs
Documentation coming soon.
# hanzo-tools-fs
Filesystem tools for reading, writing, editing, and searching files with permission management.
## Installation
```bash
pip install hanzo-tools-fs
```
Or as part of the full toolkit:
```bash
pip install hanzo-mcp[tools-all]
```
## Overview
`hanzo-tools-fs` provides:
- **read** - Read file contents with line numbers
- **write** - Write/create files
- **edit** - Edit files with find/replace
- **tree** - Directory tree view
- **find** - Find files by pattern
- **search** - Search file contents (ripgrep-powered)
- **ast** - AST-based code structure search
## Quick Start
```python
# Read a file
read(file_path="/path/to/file.py")
# Write a file
write(file_path="/path/to/new.py", content="print('hello')")
# Edit a file
edit(file_path="/path/to/file.py", old_string="foo", new_string="bar")
# Search for patterns
search(pattern="TODO", path="./src")
# Find files
find(pattern="*.py", path="./src")
# View directory structure
tree(path="./src", depth=3)
# AST-based code search
ast(pattern="class.*Service", path="./src")
```
## Tools Reference
### read
Read file contents with line numbers.
```python
# Basic read
read(file_path="/path/to/file.py")
# Read with offset and limit (for large files)
read(file_path="/path/to/large.py", offset=100, limit=50)
```
**Parameters:**
- `file_path` (required): Absolute path to the file
- `offset`: Starting line number (0-based, default: 0)
- `limit`: Maximum lines to read (default: 2000)
**Output format:**
```
1→def hello():
2→ print("Hello, World!")
3→
[Showing lines 1-3 of 3]
```
### write
Write content to a file, creating it if it doesn't exist.
```python
# Create new file
write(file_path="/path/to/new.py", content="print('hello')")
# Overwrite existing file
write(file_path="/path/to/existing.py", content="new content")
```
**Parameters:**
- `file_path` (required): Absolute path to the file
- `content` (required): Content to write
### edit
Edit a file by replacing text.
```python
# Simple replacement
edit(
file_path="/path/to/file.py",
old_string="def old_name():",
new_string="def new_name():"
)
# Replace multiple occurrences
edit(
file_path="/path/to/file.py",
old_string="TODO",
new_string="DONE",
expected_replacements=5
)
```
**Parameters:**
- `file_path` (required): Absolute path to the file
- `old_string` (required): Text to find
- `new_string` (required): Text to replace with
- `expected_replacements`: Expected number of replacements (default: 1)
### tree
Display directory tree structure.
```python
# Basic tree view
tree(path="/project")
# Limited depth
tree(path="/project", depth=2)
# Include filtered directories
tree(path="/project", include_filtered=True)
```
**Parameters:**
- `path` (required): Directory path
- `depth`: Maximum depth (default: 3)
- `include_filtered`: Include commonly filtered dirs like node_modules (default: false)
**Output format:**
```
├── src/
│ ├── main.py
│ └── utils/
│ └── helpers.py
├── tests/
│ └── test_main.py
└── pyproject.toml
```
### find
Find files and directories by pattern.
```python
# Find Python files
find(pattern="*.py", path="/project")
# Find test files
find(pattern="test_*.py", path="/project")
# Find directories
find(pattern="*config*", path="/project", type="dir")
# Limit results
find(pattern="*.md", path="/project", max_results=20)
```
**Parameters:**
- `pattern` (required): Glob pattern to match
- `path`: Directory to search (default: current directory)
- `type`: Filter by type - "file", "dir", or None for both
- `max_results`: Maximum results (default: 100)
### search
Search for patterns in file contents using ripgrep.
```python
# Basic search
search(pattern="TODO", path="./src")
# Search with file filter
search(pattern="import", path="./src", include="*.py")
# Search with context lines
search(pattern="error", path="./logs", context_lines=5)
# Limit results
search(pattern="function", path="./src", max_results=20)
```
**Parameters:**
- `pattern` (required): Regex pattern to search for
- `path`: Directory or file to search (default: current directory)
- `include`: Glob pattern to filter files (e.g., "*.py")
- `context_lines`: Lines of context around matches (default: 2)
- `max_results`: Maximum results (default: 50)
**Features:**
- Uses ripgrep (rg) if available for high performance
- Falls back to Python regex if ripgrep not installed
- Async file I/O for non-blocking operation
### ast
AST-based code structure search using tree-sitter.
```python
# Find function definitions
ast(pattern="def test_", path="./tests")
# Find class definitions
ast(pattern="class.*Service", path="./src")
# Find with line numbers
ast(pattern="async def", path="./src", line_number=True)
# Case-insensitive search
ast(pattern="config", path="./src", ignore_case=True)
```
**Parameters:**
- `pattern` (required): Regex pattern to search for
- `path` (required): File or directory to search
- `ignore_case`: Case-insensitive matching (default: false)
- `line_number`: Display line numbers (default: false)
**Supported Languages:**
- Python (.py, .pyw)
- JavaScript/TypeScript (.js, .jsx, .ts, .tsx)
- Go (.go)
- Rust (.rs)
- C/C++ (.c, .cpp, .h, .hpp)
- Java (.java)
- Ruby (.rb)
- PHP (.php)
- And more...
## Permission Management
All filesystem tools respect permission boundaries:
```python
from hanzo_tools.fs import register_tools
from hanzo_tools.core import PermissionManager
# Set up permission manager
pm = PermissionManager(
allowed_paths=["/home/user/project"],
denied_paths=["/home/user/project/.env"]
)
# Register tools with MCP server
register_tools(mcp_server, pm)
```
### Read-Only Tools
For sandboxed environments, use read-only tools:
```python
from hanzo_tools.fs import get_read_only_filesystem_tools
# Get only read operations
tools = get_read_only_filesystem_tools(permission_manager)
# Includes: read, tree, find, search, ast
```
## Examples
### Code Review Workflow
```python
# Find all TODO comments
search(pattern="TODO|FIXME", path="./src")
# Check code structure
ast(pattern="class.*", path="./src")
# Review specific file
read(file_path="./src/main.py")
```
### Refactoring Workflow
```python
# Find all usages of old function name
search(pattern="old_function_name", path="./src")
# Find function definition
ast(pattern="def old_function_name", path="./src")
# Edit the function
edit(
file_path="./src/utils.py",
old_string="def old_function_name(",
new_string="def new_function_name("
)
```
### Project Exploration
```python
# Get project structure
tree(path="./", depth=3)
# Find configuration files
find(pattern="*.toml", path="./")
find(pattern="*.json", path="./")
# Search for entry points
ast(pattern="def main|if __name__", path="./src")
```
## Best Practices
1. **Use absolute paths** - All tools expect absolute paths for reliability
2. **Set appropriate limits** - Use `limit` and `max_results` to avoid overwhelming output
3. **Prefer search over read** - Use search/ast to find relevant code instead of reading entire files
4. **Use tree for orientation** - Start with tree to understand project structure
5. **Combine tools** - Use find + read or search + edit for efficient workflows
+321 -2
View File
@@ -1,2 +1,321 @@
# Llm
Documentation coming soon.
# hanzo-tools-llm
Unified LLM interface with multi-model consensus. Access 100+ models through a single tool.
## Installation
```bash
pip install hanzo-tools-llm[full]
```
Note: This package requires `litellm` which is a heavy dependency. It's disabled by default in hanzo-mcp.
## Overview
`hanzo-tools-llm` provides:
- **llm** - Unified LLM interface (query, consensus, model management)
- **consensus** - Multi-model consensus protocol
## Quick Start
```python
# Simple query
llm(action="query", prompt="Explain quantum computing", model="gpt-4")
# Multi-model consensus
llm(
action="consensus",
prompt="Best approach for distributed caching?",
models=["gpt-4", "claude-3-opus", "gemini-pro"]
)
# List available models
llm(action="list")
# Enable/disable providers
llm(action="enable", provider="anthropic")
llm(action="disable", provider="openai")
```
## Actions Reference
### query
Send a prompt to an LLM.
```python
# Basic query
llm(action="query", prompt="Hello, world!", model="gpt-4")
# With system prompt
llm(
action="query",
prompt="Explain this code",
model="claude-3-opus-20240229",
system_prompt="You are a senior software engineer"
)
# With temperature control
llm(
action="query",
prompt="Generate creative names",
model="gpt-4",
temperature=0.9
)
# JSON mode
llm(
action="query",
prompt="List 5 programming languages with pros/cons",
model="gpt-4",
json_mode=True
)
# Streaming
llm(
action="query",
prompt="Write a long story",
model="gpt-4",
stream=True
)
```
**Parameters:**
- `prompt` (required): The prompt to send
- `model`: Model name (default: auto-select)
- `system_prompt`: System context
- `temperature`: Response randomness (0-2, default: 0.7)
- `max_tokens`: Maximum response tokens
- `json_mode`: Request JSON output (default: false)
- `stream`: Stream response (default: false)
### consensus
Get consensus from multiple models.
```python
llm(
action="consensus",
prompt="What's the best way to handle errors in Go?",
models=["gpt-4", "claude-3-opus", "gemini-pro"],
include_raw=True, # Include individual responses
judge_model="gpt-4", # Model to synthesize consensus
devils_advocate=True # Add critical analysis
)
```
**Parameters:**
- `prompt` (required): Question for consensus
- `models`: List of models to query (default: auto-select 3)
- `consensus_size`: Number of models if not specifying (default: 3)
- `include_raw`: Include raw responses (default: false)
- `judge_model`: Model to aggregate responses
- `devils_advocate`: Add 10th model for critique (default: false)
**Response:**
```json
{
"consensus": "The agreed-upon answer synthesized from all models...",
"confidence": 0.85,
"models_queried": ["gpt-4", "claude-3-opus", "gemini-pro"],
"agreement_level": "high",
"raw_responses": [...] // if include_raw=true
}
```
### list
List available models and providers.
```python
llm(action="list")
```
**Response:**
```json
{
"providers": {
"openai": {"enabled": true, "models": ["gpt-4", "gpt-3.5-turbo"]},
"anthropic": {"enabled": true, "models": ["claude-3-opus", "claude-3-sonnet"]},
"google": {"enabled": false, "models": ["gemini-pro"]}
}
}
```
### models
List models for a specific provider.
```python
llm(action="models", provider="openai")
```
### enable / disable
Enable or disable a provider.
```python
# Enable a provider
llm(action="enable", provider="anthropic")
# Disable a provider
llm(action="disable", provider="openai")
```
### test
Test connectivity to a model.
```python
llm(action="test", model="gpt-4")
```
## Supported Providers
The LLM tool uses [LiteLLM](https://github.com/BerriAI/litellm) to support 100+ models:
| Provider | Models | API Key Env |
|----------|--------|-------------|
| OpenAI | gpt-4, gpt-3.5-turbo | `OPENAI_API_KEY` |
| Anthropic | claude-3-opus, claude-3-sonnet | `ANTHROPIC_API_KEY` |
| Google | gemini-pro, gemini-ultra | `GOOGLE_API_KEY` |
| Azure | All Azure OpenAI models | `AZURE_API_KEY` |
| AWS Bedrock | claude, titan | AWS credentials |
| Cohere | command, command-r | `COHERE_API_KEY` |
| Together | Various open models | `TOGETHER_API_KEY` |
| Ollama | Local models | - |
| And more... | | |
## ConsensusTool
Dedicated tool for multi-model consensus:
```python
consensus(
prompt="Should we use microservices or monolith?",
models=["gpt-4", "claude-3-opus", "gemini-pro"],
rounds=3
)
```
## Examples
### Code Review with Consensus
```python
# Get multiple perspectives on code
llm(
action="consensus",
prompt="""Review this function for issues:
def process(data):
result = []
for item in data:
if item > 0:
result.append(item * 2)
return result
""",
models=["gpt-4", "claude-3-opus", "gemini-pro"],
devils_advocate=True
)
```
### Choosing Best Model for Task
```python
# List available models
models = llm(action="list")
# Test specific model
llm(action="test", model="claude-3-opus-20240229")
# Query with best model
llm(
action="query",
prompt="Complex reasoning task",
model="claude-3-opus-20240229"
)
```
### JSON Output
```python
# Get structured data
response = llm(
action="query",
prompt="List 3 Python web frameworks with their pros and cons",
model="gpt-4",
json_mode=True
)
# Response will be valid JSON
```
### Creative vs Deterministic
```python
# Creative task (high temperature)
llm(
action="query",
prompt="Write a poem about coding",
model="gpt-4",
temperature=0.9
)
# Deterministic task (low temperature)
llm(
action="query",
prompt="Convert this SQL to Python",
model="gpt-4",
temperature=0.1
)
```
## Configuration
### API Keys
Set API keys via environment variables:
```bash
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
export GOOGLE_API_KEY="..."
```
### Default Model
Set default model via environment:
```bash
export HANZO_DEFAULT_LLM_MODEL="gpt-4"
```
### Model Aliases
Configure model aliases in `~/.hanzo/llm/aliases.json`:
```json
{
"smart": "gpt-4",
"fast": "gpt-3.5-turbo",
"creative": "claude-3-opus-20240229"
}
```
## Performance Tips
1. **Use streaming for long responses** - Better UX for users
2. **Cache responses when appropriate** - Same prompt = same response
3. **Choose model based on task** - GPT-3.5 for simple, GPT-4 for complex
4. **Set max_tokens** - Avoid unnecessarily long responses
5. **Use consensus for important decisions** - Multiple perspectives reduce errors
## Best Practices
1. **Set appropriate temperature** - Low for factual, high for creative
2. **Use system prompts** - Provide context for better responses
3. **Validate JSON output** - Even with json_mode, validate responses
4. **Handle rate limits** - LiteLLM handles retries automatically
5. **Monitor costs** - Different models have different pricing
+283 -2
View File
@@ -1,2 +1,283 @@
# lsp
Documentation coming soon.
# hanzo-tools-lsp
Language Server Protocol tool for code intelligence. Provides go-to-definition, find references, rename, hover, and more.
## Installation
```bash
pip install hanzo-tools-lsp
```
Or as part of the full toolkit:
```bash
pip install hanzo-mcp[tools-all]
```
## Overview
`hanzo-tools-lsp` provides on-demand LSP configuration and automatic installation:
- **definition** - Go to definition of symbol at position
- **references** - Find all references to symbol
- **rename** - Rename symbol across codebase
- **hover** - Get hover information at position
- **completion** - Get code completions at position
- **diagnostics** - Get errors and warnings for file
- **status** - Check LSP server status
## Supported Languages
| Language | LSP Server | Install Command |
|----------|------------|-----------------|
| Go | gopls | `go install golang.org/x/tools/gopls@latest` |
| Python | pyright | `npm install -g pyright` |
| TypeScript/JS | typescript-language-server | `npm install -g typescript typescript-language-server` |
| Rust | rust-analyzer | `rustup component add rust-analyzer` |
| Java | jdtls | `brew install jdtls` |
| C/C++ | clangd | `brew install llvm` |
| Ruby | solargraph | `gem install solargraph` |
| Lua | lua-language-server | `brew install lua-language-server` |
## Quick Start
```python
# Go to definition
lsp(action="definition", file="/path/to/file.go", line=10, character=15)
# Find all references
lsp(action="references", file="/path/to/file.py", line=25, character=8)
# Rename symbol
lsp(action="rename", file="/path/to/file.ts", line=5, character=10, new_name="newName")
# Get hover info
lsp(action="hover", file="/path/to/file.rs", line=42, character=20)
# Get completions
lsp(action="completion", file="/path/to/file.py", line=30, character=5)
# Check status
lsp(action="status", file="/path/to/file.go")
```
## Actions Reference
### definition
Find where a symbol is defined.
```python
lsp(action="definition", file="main.go", line=42, character=15)
```
**Response:**
```json
{
"action": "definition",
"file": "main.go",
"definition": {
"file": "/project/pkg/utils.go",
"start": {"line": 25, "character": 5},
"end": {"line": 25, "character": 15}
}
}
```
### references
Find all references to a symbol.
```python
lsp(action="references", file="utils.py", line=10, character=4)
```
**Response:**
```json
{
"action": "references",
"file": "utils.py",
"references": [
{"file": "main.py", "start": {"line": 15, "character": 8}},
{"file": "tests/test_utils.py", "start": {"line": 22, "character": 12}}
],
"count": 2
}
```
### rename
Rename a symbol across the codebase.
```python
lsp(action="rename", file="models.ts", line=5, character=10, new_name="newClassName")
```
**Response:**
```json
{
"action": "rename",
"file": "models.ts",
"new_name": "newClassName",
"changes": {
"/project/models.ts": [
{"range": {...}, "newText": "newClassName"}
],
"/project/index.ts": [
{"range": {...}, "newText": "newClassName"}
]
},
"files_affected": 2
}
```
### hover
Get documentation and type information at a position.
```python
lsp(action="hover", file="main.rs", line=30, character=8)
```
**Response:**
```json
{
"action": "hover",
"file": "main.rs",
"position": {"line": 30, "character": 8},
"contents": "fn process(data: &[u8]) -> Result<(), Error>\n\nProcesses the input data..."
}
```
### completion
Get code completions at a position.
```python
lsp(action="completion", file="app.py", line=25, character=10)
```
**Response:**
```json
{
"action": "completion",
"file": "app.py",
"position": {"line": 25, "character": 10},
"completions": [
{"label": "append", "kind": 2, "detail": "(element) -> None"},
{"label": "extend", "kind": 2, "detail": "(iterable) -> None"}
],
"count": 2
}
```
### status
Check if LSP server is installed and get capabilities.
```python
lsp(action="status", file="main.go")
```
**Response:**
```json
{
"language": "go",
"lsp_server": "gopls",
"installed": true,
"capabilities": ["definition", "references", "rename", "diagnostics", "hover", "completion"]
}
```
## Architecture
### Automatic Server Management
The LSP tool automatically:
1. Detects language from file extension
2. Finds project root based on language markers (go.mod, package.json, etc.)
3. Checks if LSP server is installed
4. Installs LSP server if needed
5. Starts and initializes the server
6. Maintains singleton server per language:project_root
### Server Lifecycle
```
Request → Detect Language → Find Project Root
↓
Check Cache (language:root_uri)
↓
If not running: Install → Start → Initialize
↓
Execute LSP Request → Return Result
```
### Global Server Registry
LSP servers are managed globally to avoid redundant instances:
```python
# Servers are keyed by language:root_uri
# e.g., "go:/home/user/project"
# Cleanup happens automatically on process exit
```
## Examples
### Code Navigation
```python
# Find where a function is defined
lsp(action="definition", file="handlers/user.go", line=45, character=12)
# Find all places that call this function
lsp(action="references", file="handlers/user.go", line=45, character=12)
```
### Safe Refactoring
```python
# First, check all references
refs = lsp(action="references", file="models.py", line=10, character=6)
# Then rename
lsp(action="rename", file="models.py", line=10, character=6, new_name="UserProfile")
```
### IDE-like Experience
```python
# Get documentation on hover
lsp(action="hover", file="main.rs", line=25, character=8)
# Get completions while typing
lsp(action="completion", file="app.ts", line=30, character=15)
```
## Configuration
### Project Root Detection
The LSP tool finds project roots using language-specific markers:
| Language | Markers |
|----------|---------|
| Go | go.mod, go.sum |
| Python | pyproject.toml, setup.py, requirements.txt |
| TypeScript | tsconfig.json, package.json |
| Rust | Cargo.toml |
| Java | pom.xml, build.gradle |
| C/C++ | compile_commands.json, CMakeLists.txt |
| Ruby | Gemfile |
### Custom LSP Servers
For custom configurations, ensure the LSP server is in your PATH before using the tool.
## Best Practices
1. **Use status first** - Check if LSP is available before heavy operations
2. **Provide accurate positions** - Line and character must match exact symbol position
3. **Let servers persist** - Servers are cached; avoid restarting unnecessarily
4. **Combine with other tools** - Use with search/ast for comprehensive code analysis
+283 -2
View File
@@ -1,2 +1,283 @@
# memory
Documentation coming soon.
# hanzo-tools-memory
Unified memory and knowledge management for AI agents. Store, recall, and manage memories and facts across sessions.
## Installation
```bash
pip install hanzo-tools-memory
```
Or as part of the full toolkit:
```bash
pip install hanzo-mcp[tools-all]
```
## Overview
`hanzo-tools-memory` provides:
- **Memory** - Episodic memory for storing and recalling information
- **Facts** - Knowledge base management for structured information
- **Scopes** - Session, project, and global memory levels
- **Summarization** - Automatic content summarization
## Quick Start
```python
# Store a memory
memory(action="create", data={"content": "User prefers dark mode"})
# Recall memories
memory(action="recall", query="user preferences")
# Store facts
memory(action="store_facts", data={
"facts": ["API rate limit is 100/hour"],
"kb_name": "api_docs"
})
# Recall facts
memory(action="facts", query="rate limit")
```
## Memory Actions
### create
Store new memories:
```python
memory(action="create", data={
"content": "User prefers TypeScript over JavaScript",
"scope": "project" # session, project, or global
})
# Store multiple memories
memory(action="create", data={
"statements": [
"User works in Python",
"Project uses FastAPI",
"Prefers minimal dependencies"
]
})
```
### recall
Search and retrieve memories:
```python
# Simple query
memory(action="recall", query="user preferences")
# With scope filter
memory(action="recall", query="coding style", scope="project")
# Limit results
memory(action="recall", query="API endpoints", limit=5)
# Multiple queries (parallel search)
memory(action="recall", data={
"queries": ["database schema", "API design", "error handling"]
})
```
### update
Modify existing memories:
```python
memory(action="update", data={
"updates": [
{"id": "mem_123", "statement": "User now prefers light mode"},
{"id": "mem_456", "statement": "Updated API endpoint"}
]
})
```
### delete
Remove memories:
```python
memory(action="delete", data={
"ids": ["mem_123", "mem_456"]
})
```
### manage
Batch operations (create, update, delete in one call):
```python
memory(action="manage", data={
"creations": ["New fact 1", "New fact 2"],
"updates": [{"id": "mem_1", "statement": "Updated"}],
"deletions": ["mem_old1", "mem_old2"]
})
```
## Facts & Knowledge Bases
### store_facts
Store structured facts in knowledge bases:
```python
memory(action="store_facts", data={
"facts": [
"Python uses indentation for blocks",
"FastAPI supports async/await"
],
"kb_name": "python_basics",
"scope": "project"
})
```
### facts
Query knowledge bases:
```python
# Query specific knowledge base
memory(action="facts", query="async patterns", kb_name="python_basics")
# Query all knowledge bases
memory(action="facts", query="error handling")
# With scope
memory(action="facts", query="API docs", scope="global")
```
### kb_manage
Manage knowledge bases:
```python
# Create knowledge base
memory(action="kb_manage", data={
"action": "create",
"kb_name": "api_docs",
"description": "API documentation and endpoints"
})
# List knowledge bases
memory(action="kb_manage", data={"action": "list", "scope": "project"})
# Delete knowledge base
memory(action="kb_manage", data={"action": "delete", "kb_name": "old_docs"})
```
## Summarization
### summarize
Summarize content and store in memory:
```python
memory(action="summarize", data={
"content": "Long discussion about API design decisions...",
"topic": "API Design Decisions",
"scope": "project",
"auto_facts": True # Auto-extract facts
})
```
## Scopes
Memories exist at three levels:
| Scope | Persistence | Use Case |
|-------|-------------|----------|
| `session` | Current session only | Temporary context |
| `project` | Per-project | Project-specific knowledge |
| `global` | All projects | User preferences, global facts |
```python
# Session memory (temporary)
memory(action="create", data={
"content": "Currently debugging auth issue",
"scope": "session"
})
# Project memory (persistent)
memory(action="create", data={
"content": "Project uses PostgreSQL",
"scope": "project"
})
# Global memory (shared)
memory(action="create", data={
"content": "User prefers Vim keybindings",
"scope": "global"
})
```
## Storage
Memories are stored in:
- `~/.hanzo/memory/session/` - Session memories
- `~/.hanzo/memory/project/<project>/` - Project memories
- `~/.hanzo/memory/global/` - Global memories
## Examples
### Context Building
```python
# At start of session, recall relevant context
memories = memory(action="recall", data={
"queries": [
"project architecture",
"recent changes",
"pending tasks"
],
"scope": "project"
})
```
### Learning User Preferences
```python
# Store preference when learned
memory(action="create", data={
"content": "User prefers functional programming style",
"scope": "global"
})
# Later, recall preferences
prefs = memory(action="recall", query="coding style preferences")
```
### Project Documentation
```python
# Store project facts
memory(action="store_facts", data={
"facts": [
"Database: PostgreSQL 15",
"ORM: SQLAlchemy 2.0",
"API Framework: FastAPI",
"Auth: JWT tokens"
],
"kb_name": "tech_stack",
"scope": "project"
})
# Query later
stack = memory(action="facts", query="what database", kb_name="tech_stack")
```
### Session Summarization
```python
# At end of session, summarize work
memory(action="summarize", data={
"content": conversation_history,
"topic": "Session Summary - Auth Implementation",
"scope": "project"
})
```
+328 -2
View File
@@ -1,2 +1,328 @@
# reasoning
Documentation coming soon.
# hanzo-tools-reasoning
Structured thinking and critical analysis tools for AI agents. Provides the `think` and `critic` tools for deliberate reasoning.
## Installation
```bash
pip install hanzo-tools-reasoning
```
Or as part of the full toolkit:
```bash
pip install hanzo-mcp[tools-all]
```
## Overview
`hanzo-tools-reasoning` provides:
- **think** - Structured reasoning and brainstorming
- **critic** - Critical analysis and devil's advocate
## think
Use the think tool for deliberate reasoning without taking action.
### When to Use
1. **Exploring solutions** - Brainstorm approaches before implementing
2. **Debugging** - Organize hypotheses about failures
3. **Planning** - Think through architecture decisions
4. **Complex problems** - Break down multi-step solutions
### Usage
```python
think(thought="""
Feature Implementation Planning
- New code search feature requirements:
* Search for code patterns across multiple files
* Identify function usages and references
* Analyze import relationships
* Generate summary of matching patterns
- Implementation considerations:
* Need to leverage existing search mechanisms
* Should use regex for pattern matching
* Results need consistent format
* Must handle large codebases efficiently
- Design approach:
1. Create new CodeSearcher class
2. Implement core pattern matching
3. Add result formatting
4. Integrate with file traversal
5. Add caching for performance
- Testing strategy:
* Unit tests for search accuracy
* Integration tests with existing components
* Performance tests with large codebases
""")
```
### Best Practices
- **Be specific**: Include concrete details and constraints
- **Structure thoughts**: Use lists, sections, and hierarchies
- **Consider alternatives**: List multiple approaches
- **Note tradeoffs**: Document pros/cons of each option
### Examples
#### Bug Investigation
```python
think(thought="""
Bug Analysis: API returning 500 errors
Symptoms:
- Intermittent 500 errors on /api/users endpoint
- Happens under high load
- Error logs show connection pool exhausted
Hypotheses:
1. Connection pool too small
- Check: current pool size vs concurrent requests
- Fix: increase pool size or add connection recycling
2. Slow queries blocking connections
- Check: query execution times
- Fix: add indexes, optimize queries
3. Connection leak in error paths
- Check: connection release in exception handlers
- Fix: ensure connections released in finally blocks
Investigation order:
1. Check connection pool metrics
2. Review slow query logs
3. Audit connection handling code
""")
```
#### Architecture Decision
```python
think(thought="""
Architecture Decision: State Management
Options:
1. Redux
+ Predictable state updates
+ Great devtools
- Boilerplate heavy
- Overkill for simple apps
2. Zustand
+ Minimal API
+ No providers needed
+ TypeScript friendly
- Less ecosystem
3. React Context + useReducer
+ Built-in, no dependencies
+ Familiar patterns
- Performance concerns at scale
- Manual optimization needed
Recommendation: Zustand
- Our app is medium complexity
- Team prefers minimal boilerplate
- TypeScript is priority
- Performance is acceptable for our scale
""")
```
## critic
Use the critic tool for critical analysis and quality assurance.
### When to Use
1. **Code review** - Analyze implementations for issues
2. **Before finalizing** - Ensure quality standards met
3. **Testing** - Question if tests are comprehensive
4. **Design review** - Challenge assumptions
### Usage
```python
critic(analysis="""
Code Review Analysis:
Implementation Issues:
- No error handling for network failures in API calls
- Missing validation for user input boundaries
- Race condition possible in concurrent updates
- Memory leak potential in event listener registration
Test Coverage Gaps:
- No tests for error scenarios
- Missing edge case: empty array input
- No performance benchmarks for large datasets
- Integration tests don't cover auth failures
Security Concerns:
- SQL injection vulnerability in query construction
- Missing rate limiting on public endpoints
- Sensitive data logged in debug mode
Performance Issues:
- O(n²) algorithm where O(n log n) is possible
- Database queries in a loop (N+1 problem)
- No caching for expensive computations
Code Quality:
- Functions too long and doing multiple things
- Inconsistent naming conventions
- Missing type annotations
- No documentation for complex algorithms
Design Flaws:
- Tight coupling between modules
- Hard-coded configuration values
- No abstraction for external dependencies
- Violates single responsibility principle
Recommendations:
1. Add comprehensive error handling
2. Implement input validation
3. Use database transactions for race conditions
4. Parameterize SQL queries
5. Implement rate limiting
6. Refactor to smaller functions
7. Add missing type annotations
8. Batch database queries
""")
```
### The Inner Critic Mindset
The critic tool forces critical thinking that:
- **Questions assumptions** - "Is this really necessary?"
- **Looks for bugs** - "What could go wrong?"
- **Checks edge cases** - "What about empty input?"
- **Verifies security** - "Can this be exploited?"
- **Reviews performance** - "Will this scale?"
- **Ensures quality** - "Is this maintainable?"
### Examples
#### Feature Review
```python
critic(analysis="""
Review: User Authentication Feature
Positive aspects:
- Clean API design
- Good separation of concerns
- Follows existing patterns
Issues found:
1. Token expiry not handled
- Tokens never expire
- No refresh token mechanism
- Risk: Stolen tokens valid forever
2. Password handling
- Using MD5 (insecure)
- No salt
- Should use bcrypt/argon2
3. Rate limiting missing
- No limit on login attempts
- Vulnerable to brute force
4. Error messages too specific
- "Invalid password" reveals user exists
- Should use generic "Invalid credentials"
5. Session management
- No logout invalidation
- Can't revoke sessions
- No concurrent session limit
Required before merge:
- Switch to bcrypt
- Add rate limiting
- Implement token refresh
- Generic error messages
""")
```
#### Test Review
```python
critic(analysis="""
Test Suite Analysis:
Coverage gaps:
- No tests for boundary conditions
- Error paths untested
- Async behavior not verified
- No integration tests with real DB
Test quality issues:
- Tests too coupled to implementation
- Magic numbers without explanation
- No test documentation
- Flaky tests due to timing
Missing test categories:
- Performance/load tests
- Security tests
- Accessibility tests
- Cross-browser tests
Recommendations:
1. Add boundary condition tests
2. Test all error scenarios
3. Use proper test fixtures
4. Add integration test suite
5. Document test intentions
""")
```
## Combining Think and Critic
Use both tools together for thorough analysis:
```python
# First, think through the problem
think(thought="""
Planning: Implement caching layer
- Need to cache API responses
- Options: Redis, in-memory, file-based
- Must handle invalidation
- Need TTL support
""")
# Then, critically analyze the plan
critic(analysis="""
Cache Implementation Review:
Potential issues:
- Cache invalidation strategy unclear
- No handling for cache stampede
- Memory limits not considered
- No monitoring/metrics planned
Missing considerations:
- What happens when cache is full?
- How to warm cache on startup?
- How to handle partial failures?
- What's the fallback if Redis down?
Recommendations:
1. Define explicit invalidation triggers
2. Add circuit breaker for cache failures
3. Implement cache warming strategy
4. Add memory limits with eviction
5. Include cache hit/miss metrics
""")
```
+353 -2
View File
@@ -1,2 +1,353 @@
# refactor
Documentation coming soon.
# hanzo-tools-refactor
Advanced refactoring with LSP/AST support. FAST parallel processing for large codebases.
## Installation
```bash
pip install hanzo-tools-refactor
```
Or as part of the full toolkit:
```bash
pip install hanzo-mcp[tools-all]
```
## Overview
`hanzo-tools-refactor` provides intelligent code refactoring:
- **rename** - Rename symbol across entire codebase
- **rename_batch** - Batch rename multiple symbols
- **extract_function** - Extract code into a new function
- **extract_variable** - Extract expression into a variable
- **inline** - Inline a function or variable
- **move** - Move symbol to another file
- **change_signature** - Modify function parameters
- **find_references** - Find all references to a symbol
- **organize_imports** - Clean up and sort imports
## Quick Start
```python
# Rename a symbol
refactor(action="rename", file="main.py", line=10, column=5, new_name="newName")
# Batch rename multiple symbols
refactor(
action="rename_batch",
renames=[
{"old": "foo", "new": "bar"},
{"old": "baz", "new": "qux"}
],
path="./src"
)
# Change function signature
refactor(
action="change_signature",
file="utils.py",
line=15,
add_parameter={"name": "timeout", "default": "30"}
)
# Find references
refactor(action="find_references", file="models.py", line=25, column=8)
```
## Actions Reference
### rename
Rename a symbol at a specific location.
```python
refactor(
action="rename",
file="/path/to/file.py",
line=42,
column=10,
new_name="betterName"
)
```
**Parameters:**
- `file` (required): File containing the symbol
- `line` (required): Line number (1-based)
- `column` (required): Column number (1-based)
- `new_name` (required): New name for the symbol
### rename_batch
Rename multiple symbols across the codebase in parallel.
```python
refactor(
action="rename_batch",
renames=[
{"old": "getUserData", "new": "fetchUserData"},
{"old": "setUserData", "new": "updateUserData"},
{"old": "deleteUserData", "new": "removeUserData"}
],
path="./src",
parallel=True # Default: true
)
```
**Parameters:**
- `renames` (required): List of {old, new} pairs
- `path`: Directory to search (default: current directory)
- `parallel`: Process in parallel (default: true)
### extract_function
Extract selected code into a new function.
```python
refactor(
action="extract_function",
file="/path/to/file.py",
start_line=20,
end_line=30,
new_name="processData"
)
```
**Parameters:**
- `file` (required): Source file
- `start_line` (required): First line of code to extract
- `end_line` (required): Last line of code to extract
- `new_name`: Name for the new function
### extract_variable
Extract an expression into a variable.
```python
refactor(
action="extract_variable",
file="/path/to/file.py",
line=15,
start_column=10,
end_column=45,
new_name="calculatedValue"
)
```
**Parameters:**
- `file` (required): Source file
- `line` (required): Line containing the expression
- `start_column`: Start of expression
- `end_column`: End of expression
- `new_name`: Variable name
### inline
Inline a function or variable at its call sites.
```python
refactor(
action="inline",
file="/path/to/file.py",
line=10,
column=5
)
```
**Parameters:**
- `file` (required): Source file
- `line` (required): Line of the symbol
- `column` (required): Column of the symbol
### move
Move a symbol to a different file.
```python
refactor(
action="move",
file="/path/to/source.py",
line=15,
column=6,
target_file="/path/to/destination.py"
)
```
**Parameters:**
- `file` (required): Source file
- `line` (required): Line of the symbol
- `column` (required): Column of the symbol
- `target_file` (required): Destination file
### change_signature
Modify a function's parameters.
```python
# Add a parameter
refactor(
action="change_signature",
file="api.py",
line=20,
add_parameter={"name": "timeout", "default": "30", "type": "int"}
)
# Remove a parameter
refactor(
action="change_signature",
file="api.py",
line=20,
remove_parameter="deprecated_param"
)
# Reorder parameters
refactor(
action="change_signature",
file="api.py",
line=20,
reorder_parameters=["user_id", "data", "options"]
)
```
### find_references
Find all references to a symbol.
```python
refactor(action="find_references", file="models.py", line=10, column=6)
```
**Response:**
```json
{
"symbol": "UserModel",
"references": [
{"file": "views.py", "line": 15, "column": 8},
{"file": "tests/test_models.py", "line": 22, "column": 12}
],
"count": 2
}
```
### organize_imports
Clean up and sort imports in a file.
```python
refactor(action="organize_imports", file="main.py")
```
## Parallel Processing
The refactor tool uses parallel processing for large-scale operations:
```python
# Parallel is enabled by default
refactor(
action="rename_batch",
renames=[...], # Many renames
path="./large_codebase",
parallel=True # Uses all CPU cores
)
# Disable for sequential processing
refactor(
action="rename_batch",
renames=[...],
parallel=False
)
```
## Preview Mode
Preview changes before applying them:
```python
# Preview only - don't apply changes
refactor(
action="rename",
file="main.py",
line=10,
column=5,
new_name="newName",
preview=True
)
```
**Response:**
```json
{
"preview": true,
"changes": [
{"file": "main.py", "line": 10, "old": "oldName", "new": "newName"},
{"file": "utils.py", "line": 25, "old": "oldName", "new": "newName"}
],
"files_affected": 2
}
```
## Examples
### Safe Symbol Rename
```python
# 1. Find all usages first
refs = refactor(action="find_references", file="models.py", line=10, column=5)
# 2. Preview the rename
preview = refactor(
action="rename",
file="models.py",
line=10,
column=5,
new_name="BetterName",
preview=True
)
# 3. Apply the rename
refactor(
action="rename",
file="models.py",
line=10,
column=5,
new_name="BetterName"
)
```
### Large-Scale Refactoring
```python
# Rename multiple patterns across codebase
refactor(
action="rename_batch",
renames=[
{"old": "v1_api", "new": "legacy_api"},
{"old": "v2_api", "new": "current_api"},
{"old": "v3_api", "new": "api"}
],
path="./src",
parallel=True
)
```
### Extract Common Code
```python
# Extract duplicated logic into a function
refactor(
action="extract_function",
file="handlers.py",
start_line=45,
end_line=60,
new_name="validate_and_process"
)
```
## Best Practices
1. **Always preview first** - Use `preview=True` for important refactors
2. **Run tests after** - Verify refactoring didn't break functionality
3. **Use batch operations** - `rename_batch` is faster than individual renames
4. **Commit before refactoring** - Have a clean git state to easily revert
5. **Combine with LSP** - Use `lsp` tool for initial symbol discovery
+277 -2
View File
@@ -1,2 +1,277 @@
# shell
Documentation coming soon.
# hanzo-tools-shell
Unified command execution with DAG support, auto-backgrounding, and process management. The shell toolkit provides the `cmd`, `zsh`, `bash`, and `ps` tools.
## Installation
```bash
pip install hanzo-tools-shell
```
Or as part of the full toolkit:
```bash
pip install hanzo-mcp[tools-all]
```
## Overview
`hanzo-tools-shell` provides:
- **cmd** - Unified command execution with DAG support
- **zsh** / **bash** / **shell** - Shell-specific execution
- **ps** - Process management (list, kill, logs)
- **npx** / **uvx** - Package runner tools
- **open** - Platform-aware file/URL opener
## Key Features
### Auto-Backgrounding
Commands automatically background after 45 seconds (configurable):
```python
# Long-running command auto-backgrounds
cmd("npm run build") # If takes >45s, continues in background
# Check status later
ps() # List all background processes
ps(logs="cmd_abc123") # View output
ps(kill="cmd_abc123") # Stop process
```
### DAG Execution
Execute commands with dependency graphs:
```python
# Sequential (default)
cmd(["mkdir dist", "cp files dist/", "zip -r out.zip dist/"])
# Parallel
cmd(["npm install", "cargo build"], parallel=True)
# Mixed DAG with dependencies
cmd([
"mkdir -p dist",
{"parallel": ["cp a.txt dist/", "cp b.txt dist/"]},
"zip -r out.zip dist/"
])
```
## Tools Reference
### cmd
The primary command execution tool:
```python
# Simple command
cmd("ls -la")
# Sequential commands
cmd(["git status", "git diff", "git log -5"])
# Parallel execution
cmd(["npm install", "pip install -r requirements.txt"], parallel=True)
# Mixed DAG
cmd([
"mkdir -p dist",
{"parallel": ["build-frontend", "build-backend"]},
"deploy"
])
# With options
cmd(
"npm test",
timeout=120, # Command timeout in seconds
cwd="/project", # Working directory
env={"NODE_ENV": "test"}, # Environment variables
quiet=True, # Suppress stdout
strict=True # Stop on first error
)
```
### zsh / bash / shell
Shell-specific wrappers around `cmd`:
```python
# Use specific shell
zsh("echo $SHELL") # Uses zsh
bash("echo $SHELL") # Uses bash
shell("echo $SHELL") # Auto-detects: zsh > bash > sh
# Same options as cmd
zsh(["cmd1", "cmd2"], parallel=True, timeout=60)
```
### ps
Process management for background commands:
```python
# List all background processes
ps()
# Get specific process info
ps(id="cmd_abc123")
# View process output (last 100 lines by default)
ps(logs="cmd_abc123")
ps(logs="cmd_abc123", n=50) # Last 50 lines
# Kill process
ps(kill="cmd_abc123") # SIGTERM (default)
ps(kill="cmd_abc123", sig=9) # SIGKILL
```
### npx / uvx
Package runners with auto-backgrounding:
```python
# Run npm packages
npx("create-react-app my-app")
npx("http-server -p 8080") # Auto-backgrounds if long-running
# Run Python packages
uvx("ruff check .")
uvx("mkdocs serve") # Auto-backgrounds if long-running
```
### open
Platform-aware opener for files and URLs:
```python
# Open URLs
open("https://example.com")
# Open files with default application
open("./document.pdf")
open("/path/to/image.png")
```
## Configuration
### Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `HANZO_AUTO_BACKGROUND_TIMEOUT` | `45` | Seconds before auto-backgrounding (0 to disable) |
| `HANZO_DEFAULT_SHELL` | `zsh` | Default shell for execution |
### Timeout Configuration
```python
# Disable auto-backgrounding for a command
cmd("long-running-command", timeout=0)
# Set global timeout via environment
import os
os.environ["HANZO_AUTO_BACKGROUND_TIMEOUT"] = "120" # 2 minutes
```
## Examples
### Build Pipeline
```python
# Parallel build with sequential deploy
cmd([
{"parallel": [
"npm run build:frontend",
"npm run build:backend",
"npm run build:docs"
]},
"npm run test",
"npm run deploy"
])
```
### Development Server
```python
# Start dev server (auto-backgrounds)
cmd("npm run dev")
# Later, check status
ps()
# Output: cmd_abc123 | running | npm run dev | started 5m ago
# View logs
ps(logs="cmd_abc123")
# Stop when done
ps(kill="cmd_abc123")
```
### Tool Invocation in DAG
```python
# Mix shell commands with tool calls
cmd([
"git pull origin main",
{"tool": "search", "input": {"pattern": "TODO"}},
"npm test"
])
```
### Parallel File Operations
```python
# Process multiple files in parallel
cmd([
["process file1.txt", "process file2.txt", "process file3.txt"]
], parallel=True)
```
## Architecture
### ShellExecutor
Single async execution engine for all shell tools:
```
CmdTool (cmd) # Unified execution graph (DAG)
├── ZshTool (zsh) # Thin shim: shell=zsh
├── BashTool (bash) # Thin shim: shell=bash
└── ShellTool # Smart shim: zsh > bash > sh
ShellExecutor (singleton)
└── ProcessManager (singleton)
└── ps tool (process listing/kill/logs)
```
### Process Lifecycle
1. Command starts with `asyncio.create_subprocess_exec`
2. Wait for completion with configured timeout
3. If timeout reached: register with ProcessManager, continue in background
4. User can monitor with `ps --logs <id>` or stop with `ps --kill <id>`
## Error Handling
```python
# Strict mode: stop on first error
cmd(["cmd1", "cmd2", "cmd3"], strict=True)
# Default: continue on errors, report all
cmd(["cmd1", "cmd2", "cmd3"]) # Returns combined output with errors
# Check exit codes in response
result = cmd("might-fail")
if "exit code" in result.lower():
# Handle error
...
```
## Best Practices
1. **Use DAG for dependencies**: Let the executor handle ordering
2. **Parallelize independent operations**: Use `parallel=True` for speed
3. **Set appropriate timeouts**: Avoid blocking on hung processes
4. **Use `ps` for long tasks**: Don't wait for builds, check later
5. **Prefer `cmd` over raw shell**: Better error handling and logging