zsh-tool
Provides tools for executing zsh commands with yield-based oversight, PTY mode, circuit breaker, and intelligent polling, enabling interactive shell command execution and management.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@zsh-toolrun 'ls -la' in current directory"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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.7.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."
Related MCP server: VibeWatch
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_pollInteractive input — send with
zsh_sendTask 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_sendProper 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
Delta Output with Line Numbers (v0.6.3)
zsh_poll returns only new output since the last poll, prefixed with global line numbers. No more dumping 800 lines every poll call.
801: Installing package foo...
802: Compiling module bar...
803: Done.Field | What it tells you |
| Line range in this delta (e.g., 801-803) |
| Byte count of new output since last poll |
| Pass |
First poll returns all output from line 1. Subsequent polls continue where the last left off. Completed tasks return the final delta, then empty on re-poll.
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 |
| How many empty polls in a row |
| Idle time since last output |
| A.L.A.N.'s duration prediction based on command history |
| 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 |
| Killed well before median completion | "Killed at 30s. Median is 120s. Needs more time." |
| Ran way past expected duration | "Killed after 180s. Median is 45s. Something is wrong." |
| 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 |
| Execute command with yield-based oversight |
| Get new output (delta) from running task with line numbers |
| Send input to task's stdin |
| Kill a running task |
| List all active tasks |
| Overall health status |
| A.L.A.N. database statistics |
| Query pattern insights for a command |
| Circuit breaker state |
| Reset circuit to CLOSED |
Installation
From Marketplace (Recommended)
Add the ArkTechNWA marketplace to Claude Code:
ArkTechNWA/claude-pluginsThen 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-toolEnable 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
│ ├── format.rs # Rich output formatting
│ ├── 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.mdConfiguration
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.7.2
User-Visible Output — Tell the model to show its work
Fix: MCP tool results are invisible to users in Claude Code (platform limitation). Tool descriptions now instruct the model to relay command output verbatim in its response text.
This is a workaround for Claude Code not rendering MCP tool result blocks to users.
0.7.1
Stale Binary Fix — Actually deliver the new format
Fix:
run-mcp.shnow runscargo clean -pbefore rebuild when source changes, preventing Cargo's incremental build from serving a stale binaryFix: Rebuild trigger now also watches
Cargo.toml(version bumps were invisible to the oldfind -newercheck)
0.7.0
Rich Output Formatting — No more JSON dumps
Structured output — command header, separator-divided sections, status footer with icons
Visual status icons —
✔/✘replace[COMPLETED/[FAILEDbracketsProgress consolidation — consecutive progress lines (e.g.,
10%,20%,30%) collapsed to show only the latest, preventing screen spam during downloads/buildsCommand echo —
$ commandheader shows what ran, truncated at 120 charsColored exit codes — green=0, red=nonzero, yellow=signal (129+)
Richer notifications — background task completions use
┌ notify:with failure coloringALAN insight icons —
⚠for warnings,ℹfor infoNew
format.rsmodule — all formatting extracted from mod.rs into isolated, testable module35 new tests (121 total) covering all formatting functions
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 + ruffPython 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 suggestionsKill-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 observationsNew
manopt_cachetable for persistent man-page option storageENV 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]stringsGrouped 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 outputMarker now stripped in
_build_task_response()before returning to callerPrevents 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 integerEach pipeline segment paired with its actual exit status from zsh
$pipestatusA.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.pymoduleCentralized configuration in
zsh_tool/config.pyFixed 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 pipelineEach segment recorded as independent observation with its own exit code
When
cat foo | grep -badopts | sortfails, you know grep was the problemQuote/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_afterTest 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 runPortable
.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 filesFixed 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 trackingget_ssh_host_stats()— per-host connection/command success ratesget_ssh_command_stats()— per-command stats across all hostsSSH-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_sendTask management:
zsh_poll,zsh_kill,zsh_tasksFixed 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.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ArkTechNWA/zsh-tool'
If you have feedback or need assistance with the MCP directory API, please join our Discord server