zsh-tool
Zsh for Claude Code. PTY mode lets Claude type passwords. NEVERHANG + A.L.A.N.
MCP 服务配置
复制以下 JSON 到 OPClaw 或其他 MCP 客户端的配置文件中即可使用
{
"mcpServers": {
"zsh-tool-mcp": {
"args": [
"zsh-tool-mcp@0.2.1"
],
"command": "uvx"
}
}
}
可用工具 (5 个)
该服务在 MCP 协议中暴露的工具,AI 可按需调用
tavily_search 14 个参数 需填 1 项
Search the web for current information on any topic. Use for news, facts, or data beyond your knowledge cutoff. Returns snippets and source URLs.
必填参数:query
tavily_extract 6 个参数 需填 1 项
Extract content from URLs. Returns raw page content in markdown or text format.
必填参数:urls
tavily_crawl 11 个参数 需填 1 项
Crawl a website starting from a URL. Extracts content from pages with configurable depth and breadth.
必填参数:url
tavily_map 8 个参数 需填 1 项
Map a website's structure. Returns a list of URLs found starting from the base URL.
必填参数:url
tavily_research 2 个参数 需填 1 项
Perform comprehensive research on a given topic or question. Use this tool when you need to gather information from multiple sources to answer a question or complete a task. Returns a detailed response based on the research findings.
必填参数:input
服务介绍
<!- - mcp-name: io.github.ArkTechNWA/zsh-tool - ->
zsh-tool
Zsh execution tool for Claude Code with full Bash parity, yield-based oversight, PTY mode, NEVERHANG circuit breaker, and A.L.A.N. short-term learning.
Status: Beta (v0.6.2)
Author: Claude + Meldrey
License: MIT
Organization: ArkTechNWA
Built with obsessive attention to reliability.
# Why?
The # 1 reason: If you use zsh, Claude Code's Bash tool causes quotation mismatches and shell confusion. Every debug loop costs tokens. zsh-tool eliminates this instantly and permanently.
The token math: One avoided debug spiral = 30+ seconds saved, hundreds of tokens preserved.
zsh-tool is intelligent shell execution:
| Problem | zsh-tool Solution |
|- -- -- -- --|- -- -- -- -- -- -- -- -- --|
| Bash/zsh quotation confusion | Native zsh — no shell mismatch, no debug loops |
| Commands hang forever | Yield-based execution — always get control back |
| No visibility into running commands | zsh_poll — incremental output collection |
| Can't interact with prompts | PTY mode + zsh_send — full interactive support |
| Can't type passwords | PTY mode — let Claude Code type its own passwords |
| Timeouts cascade | NEVERHANG circuit breaker — fail fast, auto-recover |
| No memory between calls | A.L.A.N. 2.0 — retry detection, streak tracking, proactive insights |
| Polling wastes tokens | Intelligent polling — 2s listen window, adaptive suggestions, duration estimates |
| Blind kills, no learning | Kill-aware A.L.A.N. — classifies impatience vs genuine hangs |
| Retrying with wrong flags | manopt — auto-surfaces command options on repeated failures |
| No task management | zsh_tasks, zsh_kill — full control |
This is the difference between "run commands" and "intelligent shell integration."
# Features
# # Yield-Based Execution
Commands return after yield_after seconds with partial output if still running:
- No more hanging — you always get control back
- Incremental output — collect with
zsh_poll - Interactive input — send with
zsh_send - Task management —
zsh_killandzsh_tasks
# # PTY Mode
Full pseudo-terminal emulation for interactive programs:
# Enable with pty: true
zsh(command="pass insert mypass", pty=true)
# See prompts, send input with zsh_send
- Proper handling of interactive prompts
- Programs that require a TTY
- Color output and terminal escape sequences
- Full stdin/stdout/stderr merging
# # NEVERHANG Circuit Breaker
Prevents hanging commands from blocking sessions:
- Tracks timeout patterns per command hash
- Opens circuit after 3 timeouts in rolling 1-hour window
- Auto-recovers after 5 minutes
- States:
CLOSED(normal) →OPEN(blocking) →HALF_OPEN(testing)
# # A.L.A.N. 2.0 (As Long As Necessary)
Intelligent short-term learning — "Maybe you're fuckin' up, maybe you're doing it right."
- Retry Detection — warns when you're repeating failed commands
- Streak Tracking — celebrates success streaks, warns on failure streaks
- Fuzzy Matching —
git push origin feature-1→git push origin * - Proactive Insights — contextual feedback before you run commands
- Session Memory — 15-minute rolling window tracks recent activity
- Temporal Decay — exponential decay (24h half-life), auto-prunes
- SSH Intelligence — separates host connectivity from remote command success
- Pipeline Segment Tracking — when
cat foo | grep -badopts | sortfails, A.L.A.N. knows which segment failed
# # # Intelligent Polling
zsh_poll performs a 2-second listen window before returning. If output arrives within 2s, it comes back immediately. If not, poll metadata tells the agent what's happening:
| Field | What it tells you |
|- -- -- --|- -- -- -- -- -- -- -- -- --|
| polls_since_output | How many empty polls in a row |
| elapsed_since_last_output_s | Idle time since last output |
| alan_estimate | A.L.A.N.'s duration prediction based on command history |
| suggestion | Adaptive advice: space out polls, check soon, or consider killing |
Suggestions are advisory only — the agent always decides. A 2-minute pip install no longer generates 40 empty round-trips.
# # # Kill-Aware A.L.A.N.
When the agent kills a command, A.L.A.N. records it as a KILLED outcome and classifies why:
| Category | Meaning | Example |
|- -- -- -- -- -|- -- -- -- --|- -- -- -- --|
| EARLY_KILL | Killed well before median completion | "Killed at 30s. Median is 120s. Needs more time." |
| LATE_KILL | Ran way past expected duration | "Killed after 180s. Median is 45s. Something is wrong." |
| PATTERN_PROBLEM | Template gets killed >50% of the time | "This pattern may need a different approach entirely." |
Kill classification compares kill_elapsed / median_duration to distinguish impatience from genuine hangs.
# # # manopt — Man Page Options on Failure
When a command fails repeatedly, A.L.A.N. surfaces its available options:
- 1st failure — normal feedback, no manopt
- 2nd failure — triggers async
manoptlookup in background (2s timeout) - 3rd+ failure — presents cached option table in A.L.A.N. insight
Parsed from local man pages. Cached in SQLite. On by default (ALAN_MANOPT_ENABLED=1).
# # # SSH Tracking
A.L.A.N. treats SSH commands specially, recording two separate observations:
| Observation | What it tracks | Example insight |
|- -- -- -- -- -- --|- -- -- -- -- -- -- -- -|- -- -- -- -- -- -- -- --|
| Host connectivity | Can we connect to this host? | "Host 'vps' has 67% connection failure rate" |
| Remote command | Does this command work across hosts? | "Remote command 'git pull' reliable across 3 hosts" |
Exit code classification:
0— Success (connected AND command succeeded)255— Connection failed (SSH couldn't connect)1-254— Command failed (connected but remote command failed)
This means when ssh host3 'git pull' fails with exit 255, A.L.A.N. knows the host was unreachable—not that git pull is broken.
# Tools
| Tool | Purpose |
|- -- -- -|- -- -- -- --|
| zsh | Execute command with yield-based oversight |
| zsh_poll | Get more output from running task |
| zsh_send | Send input to task's stdin |
| zsh_kill | Kill a running task |
| zsh_tasks | List all active tasks |
| zsh_health | Overall health status |
| zsh_alan_stats | A.L.A.N. database statistics |
| zsh_alan_query | Query pattern insights for a command |
| zsh_neverhang_status | Circuit breaker state |
| zsh_neverhang_reset | Reset circuit to CLOSED |
# Installation
# # From Marketplace (Recommended)
Add the ArkTechNWA marketplace to Claude Code:
ArkTechNWA/claude-plugins
Then install: /plugin install arktechnwa/zsh-tool
That's it. The plugin auto-installs dependencies on first run.
# # Manual Installation
git clone https://github.com/ArkTechNWA/zsh-tool.git ~/.claude/plugins/zsh-tool
Enable in ~/.claude/settings.json:
{
"enabledPlugins": {
"zsh-tool": true
}
}
The bundled scripts/run-mcp.sh builds the Rust binary on first run and launches the MCP server.
# # Local Development
For local development/testing, the wrapper script automatically detects when CLAUDE_PLUGIN_ROOT isn't expanded and uses the calculated plugin root directory instead. No configuration changes needed.
Alternatively, create a .mcp.local.json with absolute paths:
{
"mcpServers": {
"zsh-tool": {
"type": "stdio",
"command": "/path/to/zsh-tool/scripts/run-mcp.sh",
"env": {
"NEVERHANG_TIMEOUT_DEFAULT": "120",
"NEVERHANG_TIMEOUT_MAX": "600"
}
}
}
}
The ALAN_DB_PATH will be automatically set to {plugin_root}/data/alan.db if not explicitly provided.
Requirements: Rust toolchain (cargo) and zsh must be installed.
# Architecture
zsh-tool/
├── .claude-plugin/
│ ├── plugin.json
│ └── CLAUDE.md
├── .mcp.json
├── zsh-tool-rs/
│ ├── Cargo.toml
│ └── src/
│ ├── main.rs # CLI entry point
│ ├── lib.rs # Module exports
│ ├── executor.rs # Pipe/PTY command execution
│ ├── config.rs # User config (~/.config/zsh-tool/)
│ ├── circuit.rs # NEVERHANG circuit breaker
│ ├── meta.rs # Task metadata (exit code, pipestatus)
│ ├── alan/ # A.L.A.N. 2.0 learning engine
│ │ ├── mod.rs # Recording + insights
│ │ ├── hash.rs # Fuzzy command hashing
│ │ ├── insights.rs # Proactive feedback
│ │ ├── manopt.rs # Man-page option parsing
│ │ ├── ssh.rs # SSH host/command tracking
│ │ ├── streak.rs # Success/failure streaks
│ │ ├── pipeline.rs # Pipeline segment tracking
│ │ ├── prune.rs # Temporal decay + pruning
│ │ └── stats.rs # Database statistics
│ └── serve/ # MCP JSON-RPC server
│ ├── mod.rs # Request dispatch + tool handlers
│ ├── protocol.rs # JSON-RPC framing
│ └── tools.rs # Tool schema definitions
├── scripts/
│ └── run-mcp.sh # Build + launch wrapper
├── data/
│ └── alan.db # A.L.A.N. SQLite database
└── README.md
# Configuration
Environment variables (set in .mcp.json):
ALAN_DB_PATH— A.L.A.N. database locationNEVERHANG_TIMEOUT_DEFAULT— Default timeout (120s)NEVERHANG_TIMEOUT_MAX— Maximum timeout (600s)ALAN_MANOPT_ENABLED— Enable man-page option hints on failure (default:1)ALAN_MANOPT_TIMEOUT— Max seconds to wait for manopt parsing (default:2.0)ALAN_MANOPT_FAIL_TRIGGER— Fail count to trigger async lookup (default:2)ALAN_MANOPT_FAIL_PRESENT— Fail count to present cached options (default:3)
# # Disabling Bash (Optional)
To use zsh as the only shell, add to ~/.claude/settings.json:
{
"permissions": {
"deny": ["Bash"]
}
}
# Changelog
# # 0.6.1
Protocol Fix — Bare JSON-RPC support for Claude Code v2.1+
- Fix: MCP server now auto-detects bare newline-delimited JSON (Claude Code v2.1.42+) vs Content-Length framing
- Debug logging: stderr diagnostics for protocol negotiation, request/response lifecycle, shutdown
- Log file:
run-mcp.shredirects stderr to/tmp/zsh-tool-mcp.logfor MCP debugging
# # 0.6.0
Full Rust Rewrite — Goodbye Python, hello speed
- Complete rewrite in Rust — MCP server, executor, A.L.A.N., NEVERHANG, all native
- 79 Rust tests — unit tests + full MCP integration tests (JSON-RPC round-trip)
- CI pipeline rewritten —
cargo test+cargo clippyreplace pytest + ruff - Python removed — 7,600+ lines of Python deleted, zero Python dependencies
- ~2x faster CI — cold build 97s → cached 48s (vs Python's 60-120s)
- All features preserved: yield/poll/send/kill, PTY mode, A.L.A.N. 2.0, NEVERHANG, manopt, SSH tracking, pipeline segments
# # 0.5.0
A.L.A.N. v2 Upgrade — Intelligent polling, kill awareness, manopt
- Intelligent polling: 2s listen window in
zsh_pollreduces empty round-trips; poll metadata with duration estimates and adaptive suggestions - Kill-aware A.L.A.N.:
KILLEDoutcome type with elapsed tracking; classifies early kills (impatience), late kills (genuine hangs), and pattern problems (wrong approach) - manopt integration: Async man-page option parsing on repeated command failures; cached in SQLite; presented on 3rd+ failure for the same command template
- New
outcome_typeandkill_elapsed_mscolumns on observations - New
manopt_cachetable for persistent man-page option storage - ENV vars:
ALAN_MANOPT_ENABLED,ALAN_MANOPT_TIMEOUT,ALAN_MANOPT_FAIL_TRIGGER,ALAN_MANOPT_FAIL_PRESENT
# # 0.4.90
Feedback Improvements — Better signal, less noise
- ALAN insights now classified as info/warning tuples
- Command awareness: grep exit 1 = "no match" (info), exit 127 = "command not found" (warning)
- Post-execution insights: silent detection, pipe masking warnings, SIGPIPE exclusion
- ANSI coloring on metadata lines (green=success, red=failure, cyan=running, yellow=timeout)
- COMPLETED/FAILED status word based on exit code
- Raw pipestatus lists replace formatted
[cmd:code]strings - Grouped insight display:
[info: A.L.A.N.: ...]and[warning: A.L.A.N.: ...]
# # 0.4.83
Python 3.14 Support — Future-proofing
- Added Python 3.14 classifier and badge
- Removed deprecated
asyncio.DefaultEventLoopPolicyfixture (slated for removal in 3.16) - All 331 tests pass on Python 3.14.2
# # 0.4.81
Pipestatus Marker Leak Fix — Data integrity
- Fixed race condition where
___ZSH_PIPESTATUS_MARKER___could leak into output - Marker now stripped in
_build_task_response()before returning to caller - Prevents corrupted file content when output is captured mid-execution
- CI: Runner switched to docker executor, added PEP 668 compliance
# # 0.4.80
Per-Segment Exit Codes — Know exactly which command failed
- Exit codes now show
[cmd1:0,cmd2:1,cmd3:0]format instead of single integer - Each pipeline segment paired with its actual exit status from zsh
$pipestatus - A.L.A.N. learning receives accurate per-command outcomes
- Self-documenting output for human and AI analysis
- Fixes bug where all commands reported
exit=0regardless of actual status
# # 0.4.79
Server Modular Refactoring — Cleaner architecture
- Extracted MCP server into
zsh_tool/server.pymodule - Centralized configuration in
zsh_tool/config.py - Fixed plugin.json version sync with package version
# # 0.4.75
Pipeline Intelligence — Know which segment of your pipeline is failing
- A.L.A.N. now captures zsh's
$pipestatusarray for every pipeline - Each segment recorded as independent observation with its own exit code
- When
cat foo | grep -badopts | sortfails, you know grep was the problem - Quote/escape-aware pipeline parsing handles complex commands correctly
- Backwards compatible: full pipeline still recorded alongside segments
- 248 new test lines covering segment tracking and edge cases
# # 0.4.6
Configuration & Polish — User-configurable defaults, 91% coverage
- User config file (
~/.config/zsh-tool/config.yaml) for custom yield_after - Test coverage improved: 303 tests, 91% coverage
- Fixed null-check bug in task cleanup
- Logo files consolidated and fixed
# # 0.4.5
Bundled Plugin — Zero-friction marketplace install
- Auto-install wrapper (
scripts/run-mcp.sh) creates venv on first run - Portable
.mcp.jsonusing${CLAUDE_PLUGIN_ROOT} - ArkTechNWA marketplace support
- No manual pip install required
# # 0.4.0
Test Suite & CI — 290 tests, 89% coverage
- Comprehensive test suite covering all modules
- CI pipeline with test and lint stages
- Dynamic pipeline and coverage badges
- Gentle test runner (
run_tests.sh) with nice and sleep between files - Fixed deprecation warnings and lint errors
- Added pytest-asyncio for async test support
# # 0.3.1
SSH Intelligence — Separate host connectivity from remote command success
- SSH commands now record dual observations (host + remote command)
- Exit code classification: 0=success, 255=connection_failed, 1-254=command_failed
- New
ssh_observationstable for SSH-specific tracking get_ssh_host_stats()— per-host connection/command success ratesget_ssh_command_stats()— per-command stats across all hosts- SSH-specific insights: flaky hosts, reliable hosts, failing commands
- 31 new tests for SSH tracking
# # 0.3.0
A.L.A.N. 2.0 — "Maybe you're fuckin' up, maybe you're doing it right."
- Retry detection: warns when repeating failed commands
- Streak tracking: celebrates success, warns on failure
- Fuzzy template matching: similar commands grouped
- Proactive insights: contextual feedback before execution
- Session memory: 15-minute rolling window
- New database tables:
recent_commands,streaks
# # 0.2.0
- Yield-based execution with live oversight
- PTY mode for full terminal emulation
- Interactive input support via
zsh_send - Task management:
zsh_poll,zsh_kill,zsh_tasks - Fixed stdin blocking with subprocess.PIPE
# # 0.1.0
- Initial release
- NEVERHANG circuit breaker
- A.L.A.N. learning database
# License
MIT License - see LICENSE for details.