Major improvements to mode and tool management:
1. Essential System Tools - Critical tools (llm, consensus, config, mode,
tool, version, stats) are now ALWAYS enabled regardless of active mode.
Previously, mode system disabled all tools then only enabled mode-specific
ones, causing critical tools to be unavailable.
2. Unified 'tool' Command - Consolidates tool_install, tool_enable,
tool_disable, tool_list into single 'tool' command with actions:
- list: List all tools by category
- enable/disable: Toggle tool state
- install/uninstall: Package management
- upgrade/reload: Update tools
- self_update: Update hanzo-mcp
3. Fixed Permission Manager - Made permission_manager optional in:
- FileSystemTool base class
- ComputerTool
- ConfigTool
- ReadTool, WriteTool, EditTool
Now creates default PermissionManager if not provided.
4. Fixed Mode System - Builtin modes (hanzo, minimal, fullstack, devops,
security) are now always registered alongside hanzo-persona profiles.
Previously they were skipped when hanzo-persona was available.
5. Updated ESSENTIAL_TOOLS constant with modern tool names and added
llm, consensus, config, mode to ensure they're in all default modes.
Version bump: 0.10.19 -> 0.10.20
- git_search.py: All 6 subprocess.run calls converted to asyncio.create_subprocess_exec
- search_tool.py: All 6 subprocess.run + 3 blocking file reads converted to async
- npx.py: Converted to asyncio.create_subprocess_exec with proper timeout
- uvx.py: Both subprocess calls converted to async with timeout handling
- open.py: Platform openers converted to async fire-and-forget pattern
All tools now use non-blocking async I/O for better concurrency.
Tests: 31/31 passing.
- Delete deprecated agent_tool_v1_deprecated.py and swarm_tool_v1_deprecated.py
- Keep CriticTool as name='critic' (not code_review) per user request
- Add missing stub classes for CLI agents when hanzo-agents unavailable
- Fix NameError: ClaudeCodeAgent not defined in tests
- Document hanzo-mcp vs hanzo-tools-* architecture in CLAUDE.md
Updated tool descriptions with DISPLAY INSTRUCTIONS to guide LLM output rendering:
- read.py: Show output in fenced code block with language hint
- write.py: Show brief status message
- edit.py: Show diff in fenced code block
- find_tool.py: Show formatted file list directly
This helps agent and other LLMs render tool output more readably
instead of showing raw JSON.
- Add MCPResourceDocument.to_readable_string() for human-readable output
- Update search, find, lsp, refactor tools to use readable format
- Cleaner to_json_string() that doesn't double-wrap data
- Better formatted results with:
- Search stats and timing info
- Numbered results with file:line locations
- Truncated long matches for readability
- Pagination info
- Sync improvements to hanzo-tools-core package
Add runtime check to provide better error message if ProcessManager()
returns None. This should never happen with proper singleton pattern,
but helps diagnose issues in edge cases.
- Add 30s timeout to each search engine (grep, ast, lsp, git)
- Fix NoneType error when process_manager unavailable in auto_timeout
- Prevents LSP engine from hanging indefinitely on large codebases
- DAG commands that exceed timeout now auto-background instead of failing
- Backgrounded processes return SUCCESS status so DAG continues
- Register backgrounded processes with ProcessManager for ps tool tracking
- Async log capture for backgrounded process output
- Enable standalone zsh tool for simple single-command execution
- All I/O uses aiofiles for non-blocking async operations
- Kill any backgrounded process without affecting DAG completion
- Check Homebrew paths first (/opt/homebrew/bin, /usr/local/bin)
- Prefer zsh, fallback to bash if not available
- Support both Apple Silicon and Intel Macs
- Add version() tool to get hanzo-mcp version via MCP
- Sync __version__ with pyproject.toml (0.9.23)
- Returns hanzo_mcp version, python version, platform, arch
- Replace has_permission() with is_path_allowed() across all tools
- Update tests to use AutoPaginatedResponse instead of PaginatedResponse
- Fix batch tool invocations to use tool_name/input instead of tool/parameters
- Update ReadTool/WriteTool imports from new module locations
- Add skip markers for deprecated tests (UvxBackgroundTool, swarm dispatch_to_model)
- Update all dependencies to latest versions (aiofiles 25.1.0, fastmcp 2.14.1, etc.)
- Add e2e LiteLLM integration test structure
All tests pass (35 passed, 6 skipped)
- Add --force-shell CLI argument with choices [bash, zsh, sh]
- Set HANZO_MCP_FORCE_SHELL environment variable when option is used
- Modified BashTool, ZshTool, and ShellTool to respect the env var
- Allows users to force all shell operations to use a specific shell
even when AI requests a different one
Example usage in ~/.claude.json:
"args": ["hanzo-mcp", "--force-shell", "zsh"]
Bumps version to 0.9.19
The TodoTool was calling self.read_todos() and self.write_todos() but
these methods were not defined in either TodoTool or TodoBaseTool.
Added the methods using TodoStorage with a default session ID.
Comprehensive async fix for all shell/process handling modules:
- command_executor.py: Made _get_shell_by_type, _get_system_shell,
_get_interpreter_path async with asyncio.to_thread for shutil.which.
Temp file creation/cleanup now uses aiofiles.os.
- logs.py: Added aiofiles for async file reads. Path.exists(), stat(),
glob() wrapped in asyncio.to_thread(). Batch async stat operations
with asyncio.gather().
- processes.py: Changed cpu_percent(interval=0.1) to interval=None
to avoid 100ms blocking per process. Wrapped sync psutil operations
in asyncio.to_thread().
- streaming_command.py: Replaced subprocess.run with async subprocess
in tail(). stream_to_file now uses aiofiles. All file I/O operations
made async throughout.
- Legacy modules (run_background.py, npx_background.py, uvx_background.py):
Added deprecation warnings pointing to new async implementations in
base_process.py and tool-specific modules.
Version bump to 0.9.17.
- Add aiofiles as runtime dependency
- Convert all file I/O in base_process.py to async with aiofiles
- Convert log writing in auto_background.py to async
- Convert log reading in process_tool.py to async
- Make create_log_file() async
- Add _ensure_log_dir() async method for deferred initialization
This ensures the event loop is never blocked by file operations,
which was causing hangs in MCP tools.
Fixes blocking file I/O identified by agent swarm review.
- Remove all sync subprocess.Popen usage in favor of asyncio.create_subprocess_exec
- ProcessManager now exclusively uses asyncio.subprocess.Process
- Use returncode attribute instead of poll() for process status
- Add _write_output_to_log for async background log writing
- Fix test_shell_features.py to use returncode instead of poll()
- Fix decorator ordering in test_long_command_backgrounds
Breaking: ProcessManager.add_process now expects asyncio.subprocess.Process
ProcessManager.list_processes() was calling .poll() which only
exists on subprocess.Popen, not asyncio.subprocess.Process.
Since auto_background.py uses asyncio.create_subprocess_exec(),
the stored process objects don't have poll(). Now checks for
.returncode directly for asyncio processes.
- Rename directory_tree tool to tree for brevity
- Remove symbols alias (use ast tool directly)
- Fix search tool registration to handle new factory functions
- Update all references in configs, prompts, examples, and tests
- Bump version to 0.9.10
Note: zsh_tool and shell_tool already existed
MCP naming (mcp__hanzo__*) is standard MCP protocol format, cannot be changed
On platforms without InfinityDB support (like Darwin arm64), the mock
implementation is expected behavior. Logging at debug level instead of
warning reduces noise in logs.
Implements comprehensive change_signature functionality:
- add_parameter: Add new parameters with optional defaults and type hints
- remove_parameter: Remove parameters by name or index
- rename_parameter: Rename parameters across definition and call sites
- reorder_parameters: Reorder parameters and update all call sites
- change_default: Modify default values
Features:
- Full Python, JavaScript/TypeScript, and Go signature parsing
- Automatic call site detection and transformation
- Handles complex nested arguments and string literals
- Preview mode to review changes before applying
- Parallel processing for large codebases
Also adds 11 new tests for change_signature functionality.
Version bump to 0.9.9