{
  "markdown": "<img align=\"right\" src=\"logo.png\" width=\"150\">\n\n<!-- mcp-name: io.github.ArkTechNWA/zsh-tool -->\n\n<br><br><br>\n\n# zsh-tool\n\n[![CI/CD](https://img.shields.io/gitlab/pipeline-status/arktechnwa%2Fmcp%2Fzsh-tool?branch=master&gitlab_url=https%3A%2F%2Fgitlab.arktechnwa.com&label=CI%2FCD)](https://gitlab.arktechnwa.com/arktechnwa/mcp/zsh-tool/-/pipelines)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Rust](https://img.shields.io/badge/rust-stable-orange.svg)](https://www.rust-lang.org/)\n\nZsh 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.\n\n**Status:** Beta (v0.7.2)\n\n**Author:** Claude + Meldrey\n\n**License:** [MIT](LICENSE)\n\n**Organization:** [ArkTechNWA](https://github.com/ArkTechNWA)\n\n---\n\n*Built with obsessive attention to reliability.*\n\n---\n\n## Why?\n\n**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.\n\n**The token math:** One avoided debug spiral = 30+ seconds saved, hundreds of tokens preserved.\n\nzsh-tool is **intelligent shell execution**:\n\n| Problem | zsh-tool Solution |\n|---------|-------------------|\n| Bash/zsh quotation confusion | **Native zsh** — no shell mismatch, no debug loops |\n| Commands hang forever | **Yield-based execution** — always get control back |\n| No visibility into running commands | **zsh_poll** — incremental output collection |\n| Can't interact with prompts | **PTY mode** + **zsh_send** — full interactive support |\n| Can't type passwords | **PTY mode** — let Claude Code type its own passwords |\n| Timeouts cascade | **NEVERHANG circuit breaker** — fail fast, auto-recover |\n| No memory between calls | **A.L.A.N. 2.0** — retry detection, streak tracking, proactive insights |\n| Polling wastes tokens | **Intelligent polling** — 2s listen window, adaptive suggestions, duration estimates |\n| Blind kills, no learning | **Kill-aware A.L.A.N.** — classifies impatience vs genuine hangs |\n| Retrying with wrong flags | **manopt** — auto-surfaces command options on repeated failures |\n| No task management | **zsh_tasks**, **zsh_kill** — full control |\n\nThis is the difference between \"run commands\" and \"intelligent shell integration.\"\n\n---\n\n## Features\n\n### Yield-Based Execution\nCommands return after `yield_after` seconds with partial output if still running:\n- **No more hanging** — you always get control back\n- **Incremental output** — collect with `zsh_poll`\n- **Interactive input** — send with `zsh_send`\n- **Task management** — `zsh_kill` and `zsh_tasks`\n\n### PTY Mode\nFull pseudo-terminal emulation for interactive programs:\n```bash\n# Enable with pty: true\nzsh(command=\"pass insert mypass\", pty=true)\n# See prompts, send input with zsh_send\n```\n- Proper handling of interactive prompts\n- Programs that require a TTY\n- Color output and terminal escape sequences\n- Full stdin/stdout/stderr merging\n\n### NEVERHANG Circuit Breaker\nPrevents hanging commands from blocking sessions:\n- Tracks timeout patterns per command hash\n- Opens circuit after 3 timeouts in rolling 1-hour window\n- Auto-recovers after 5 minutes\n- States: `CLOSED` (normal) → `OPEN` (blocking) → `HALF_OPEN` (testing)\n\n### A.L.A.N. 2.0 (As Long As Necessary)\nIntelligent short-term learning — *\"Maybe you're fuckin' up, maybe you're doing it right.\"*\n\n- **Retry Detection** — warns when you're repeating failed commands\n- **Streak Tracking** — celebrates success streaks, warns on failure streaks\n- **Fuzzy Matching** — `git push origin feature-1` → `git push origin *`\n- **Proactive Insights** — contextual feedback before you run commands\n- **Session Memory** — 15-minute rolling window tracks recent activity\n- **Temporal Decay** — exponential decay (24h half-life), auto-prunes\n- **SSH Intelligence** — separates host connectivity from remote command success\n- **Pipeline Segment Tracking** — when `cat foo | grep -badopts | sort` fails, A.L.A.N. knows *which* segment failed\n\n#### Delta Output with Line Numbers (v0.6.3)\n`zsh_poll` returns only **new output since the last poll**, prefixed with global line numbers. No more dumping 800 lines every poll call.\n\n```\n801: Installing package foo...\n802: Compiling module bar...\n803: Done.\n```\n\n| Field | What it tells you |\n|-------|-------------------|\n| `from_line` / `to_line` | Line range in this delta (e.g., 801-803) |\n| `new_bytes` | Byte count of new output since last poll |\n| `full_output` (param) | Pass `true` to get entire buffer with line numbers |\n\nFirst 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.\n\n#### Intelligent Polling\n`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:\n\n| Field | What it tells you |\n|-------|-------------------|\n| `polls_since_output` | How many empty polls in a row |\n| `elapsed_since_last_output_s` | Idle time since last output |\n| `alan_estimate` | A.L.A.N.'s duration prediction based on command history |\n| `suggestion` | Adaptive advice: space out polls, check soon, or consider killing |\n\nSuggestions are advisory only — the agent always decides. A 2-minute `pip install` no longer generates 40 empty round-trips.\n\n#### Kill-Aware A.L.A.N.\nWhen the agent kills a command, A.L.A.N. records it as a `KILLED` outcome and classifies *why*:\n\n| Category | Meaning | Example |\n|----------|---------|---------|\n| `EARLY_KILL` | Killed well before median completion | *\"Killed at 30s. Median is 120s. Needs more time.\"* |\n| `LATE_KILL` | Ran way past expected duration | *\"Killed after 180s. Median is 45s. Something is wrong.\"* |\n| `PATTERN_PROBLEM` | Template gets killed >50% of the time | *\"This pattern may need a different approach entirely.\"* |\n\nKill classification compares `kill_elapsed / median_duration` to distinguish impatience from genuine hangs.\n\n#### manopt — Man Page Options on Failure\nWhen a command fails repeatedly, A.L.A.N. surfaces its available options:\n\n- **1st failure** — normal feedback, no manopt\n- **2nd failure** — triggers async `manopt` lookup in background (2s timeout)\n- **3rd+ failure** — presents cached option table in A.L.A.N. insight\n\nParsed from local man pages. Cached in SQLite. On by default (`ALAN_MANOPT_ENABLED=1`).\n\n#### SSH Tracking\nA.L.A.N. treats SSH commands specially, recording two separate observations:\n\n| Observation | What it tracks | Example insight |\n|-------------|----------------|-----------------|\n| **Host connectivity** | Can we connect to this host? | *\"Host 'vps' has 67% connection failure rate\"* |\n| **Remote command** | Does this command work across hosts? | *\"Remote command 'git pull' reliable across 3 hosts\"* |\n\nExit code classification:\n- `0` — Success (connected AND command succeeded)\n- `255` — Connection failed (SSH couldn't connect)\n- `1-254` — Command failed (connected but remote command failed)\n\nThis 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.\n\n---\n\n## Tools\n\n| Tool | Purpose |\n|------|---------|\n| `zsh` | Execute command with yield-based oversight |\n| `zsh_poll` | Get new output (delta) from running task with line numbers |\n| `zsh_send` | Send input to task's stdin |\n| `zsh_kill` | Kill a running task |\n| `zsh_tasks` | List all active tasks |\n| `zsh_health` | Overall health status |\n| `zsh_alan_stats` | A.L.A.N. database statistics |\n| `zsh_alan_query` | Query pattern insights for a command |\n| `zsh_neverhang_status` | Circuit breaker state |\n| `zsh_neverhang_reset` | Reset circuit to CLOSED |\n\n---\n\n## Installation\n\n### From Marketplace (Recommended)\n\nAdd the ArkTechNWA marketplace to Claude Code:\n```\nArkTechNWA/claude-plugins\n```\n\nThen install: `/plugin install arktechnwa/zsh-tool`\n\n**That's it.** The plugin auto-installs dependencies on first run.\n\n### Manual Installation\n\n```bash\ngit clone https://github.com/ArkTechNWA/zsh-tool.git ~/.claude/plugins/zsh-tool\n```\n\nEnable in `~/.claude/settings.json`:\n```json\n{\n  \"enabledPlugins\": {\n    \"zsh-tool\": true\n  }\n}\n```\n\nThe bundled `scripts/run-mcp.sh` builds the Rust binary on first run and launches the MCP server.\n\n### Local Development\n\nFor 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.\n\nAlternatively, create a `.mcp.local.json` with absolute paths:\n```json\n{\n  \"mcpServers\": {\n    \"zsh-tool\": {\n      \"type\": \"stdio\",\n      \"command\": \"/path/to/zsh-tool/scripts/run-mcp.sh\",\n      \"env\": {\n        \"NEVERHANG_TIMEOUT_DEFAULT\": \"120\",\n        \"NEVERHANG_TIMEOUT_MAX\": \"600\"\n      }\n    }\n  }\n}\n```\n\nThe `ALAN_DB_PATH` will be automatically set to `{plugin_root}/data/alan.db` if not explicitly provided.\n\n**Requirements:** Rust toolchain (`cargo`) and `zsh` must be installed.\n\n---\n\n## Architecture\n\n```\nzsh-tool/\n├── .claude-plugin/\n│   ├── plugin.json\n│   └── CLAUDE.md\n├── .mcp.json\n├── zsh-tool-rs/\n│   ├── Cargo.toml\n│   └── src/\n│       ├── main.rs          # CLI entry point\n│       ├── lib.rs           # Module exports\n│       ├── executor.rs      # Pipe/PTY command execution\n│       ├── config.rs        # User config (~/.config/zsh-tool/)\n│       ├── circuit.rs       # NEVERHANG circuit breaker\n│       ├── meta.rs          # Task metadata (exit code, pipestatus)\n│       ├── alan/            # A.L.A.N. 2.0 learning engine\n│       │   ├── mod.rs       #   Recording + insights\n│       │   ├── hash.rs      #   Fuzzy command hashing\n│       │   ├── insights.rs  #   Proactive feedback\n│       │   ├── manopt.rs    #   Man-page option parsing\n│       │   ├── ssh.rs       #   SSH host/command tracking\n│       │   ├── streak.rs    #   Success/failure streaks\n│       │   ├── pipeline.rs  #   Pipeline segment tracking\n│       │   ├── prune.rs     #   Temporal decay + pruning\n│       │   └── stats.rs     #   Database statistics\n│       └── serve/           # MCP JSON-RPC server\n│           ├── mod.rs       #   Request dispatch + tool handlers\n│           ├── format.rs    #   Rich output formatting\n│           ├── protocol.rs  #   JSON-RPC framing\n│           └── tools.rs     #   Tool schema definitions\n├── scripts/\n│   └── run-mcp.sh           # Build + launch wrapper\n├── data/\n│   └── alan.db              # A.L.A.N. SQLite database\n└── README.md\n```\n\n---\n\n## Configuration\n\nEnvironment variables (set in .mcp.json):\n- `ALAN_DB_PATH` — A.L.A.N. database location\n- `NEVERHANG_TIMEOUT_DEFAULT` — Default timeout (120s)\n- `NEVERHANG_TIMEOUT_MAX` — Maximum timeout (600s)\n- `ALAN_MANOPT_ENABLED` — Enable man-page option hints on failure (default: `1`)\n- `ALAN_MANOPT_TIMEOUT` — Max seconds to wait for manopt parsing (default: `2.0`)\n- `ALAN_MANOPT_FAIL_TRIGGER` — Fail count to trigger async lookup (default: `2`)\n- `ALAN_MANOPT_FAIL_PRESENT` — Fail count to present cached options (default: `3`)\n\n### Disabling Bash (Optional)\n\nTo use zsh as the only shell, add to `~/.claude/settings.json`:\n```json\n{\n  \"permissions\": {\n    \"deny\": [\"Bash\"]\n  }\n}\n```\n\n---\n\n## Changelog\n\n### 0.7.2\n**User-Visible Output** — *Tell the model to show its work*\n- **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.\n- This is a workaround for Claude Code not rendering MCP tool result blocks to users.\n\n### 0.7.1\n**Stale Binary Fix** — *Actually deliver the new format*\n- **Fix:** `run-mcp.sh` now runs `cargo clean -p` before rebuild when source changes, preventing Cargo's incremental build from serving a stale binary\n- **Fix:** Rebuild trigger now also watches `Cargo.toml` (version bumps were invisible to the old `find -newer` check)\n\n### 0.7.0\n**Rich Output Formatting** — *No more JSON dumps*\n- **Structured output** — command header, separator-divided sections, status footer with icons\n- **Visual status icons** — `✔` / `✘` replace `[COMPLETED` / `[FAILED` brackets\n- **Progress consolidation** — consecutive progress lines (e.g., `10%`, `20%`, `30%`) collapsed to show only the latest, preventing screen spam during downloads/builds\n- **Command echo** — `$ command` header shows what ran, truncated at 120 chars\n- **Colored exit codes** — green=0, red=nonzero, yellow=signal (129+)\n- **Richer notifications** — background task completions use `┌ notify:` with failure coloring\n- **ALAN insight icons** — `⚠` for warnings, `ℹ` for info\n- **New `format.rs` module** — all formatting extracted from mod.rs into isolated, testable module\n- **35 new tests** (121 total) covering all formatting functions\n\n### 0.6.1\n**Protocol Fix** — *Bare JSON-RPC support for Claude Code v2.1+*\n- **Fix:** MCP server now auto-detects bare newline-delimited JSON (Claude Code v2.1.42+) vs Content-Length framing\n- **Debug logging:** stderr diagnostics for protocol negotiation, request/response lifecycle, shutdown\n- **Log file:** `run-mcp.sh` redirects stderr to `/tmp/zsh-tool-mcp.log` for MCP debugging\n\n### 0.6.0\n**Full Rust Rewrite** — *Goodbye Python, hello speed*\n- **Complete rewrite in Rust** — MCP server, executor, A.L.A.N., NEVERHANG, all native\n- **79 Rust tests** — unit tests + full MCP integration tests (JSON-RPC round-trip)\n- **CI pipeline rewritten** — `cargo test` + `cargo clippy` replace pytest + ruff\n- **Python removed** — 7,600+ lines of Python deleted, zero Python dependencies\n- **~2x faster CI** — cold build 97s → cached 48s (vs Python's 60-120s)\n- All features preserved: yield/poll/send/kill, PTY mode, A.L.A.N. 2.0, NEVERHANG, manopt, SSH tracking, pipeline segments\n\n### 0.5.0\n**A.L.A.N. v2 Upgrade** — *Intelligent polling, kill awareness, manopt*\n- **Intelligent polling**: 2s listen window in `zsh_poll` reduces empty round-trips; poll metadata with duration estimates and adaptive suggestions\n- **Kill-aware A.L.A.N.**: `KILLED` outcome type with elapsed tracking; classifies early kills (impatience), late kills (genuine hangs), and pattern problems (wrong approach)\n- **manopt integration**: Async man-page option parsing on repeated command failures; cached in SQLite; presented on 3rd+ failure for the same command template\n- New `outcome_type` and `kill_elapsed_ms` columns on observations\n- New `manopt_cache` table for persistent man-page option storage\n- ENV vars: `ALAN_MANOPT_ENABLED`, `ALAN_MANOPT_TIMEOUT`, `ALAN_MANOPT_FAIL_TRIGGER`, `ALAN_MANOPT_FAIL_PRESENT`\n\n### 0.4.90\n**Feedback Improvements** — *Better signal, less noise*\n- ALAN insights now classified as info/warning tuples\n- Command awareness: grep exit 1 = \"no match\" (info), exit 127 = \"command not found\" (warning)\n- Post-execution insights: silent detection, pipe masking warnings, SIGPIPE exclusion\n- ANSI coloring on metadata lines (green=success, red=failure, cyan=running, yellow=timeout)\n- COMPLETED/FAILED status word based on exit code\n- Raw pipestatus lists replace formatted `[cmd:code]` strings\n- Grouped insight display: `[info: A.L.A.N.: ...]` and `[warning: A.L.A.N.: ...]`\n\n### 0.4.83\n**Python 3.14 Support** — *Future-proofing*\n- Added Python 3.14 classifier and badge\n- Removed deprecated `asyncio.DefaultEventLoopPolicy` fixture (slated for removal in 3.16)\n- All 331 tests pass on Python 3.14.2\n\n### 0.4.81\n**Pipestatus Marker Leak Fix** — *Data integrity*\n- Fixed race condition where `___ZSH_PIPESTATUS_MARKER___` could leak into output\n- Marker now stripped in `_build_task_response()` before returning to caller\n- Prevents corrupted file content when output is captured mid-execution\n- CI: Runner switched to docker executor, added PEP 668 compliance\n\n### 0.4.80\n**Per-Segment Exit Codes** — *Know exactly which command failed*\n- Exit codes now show `[cmd1:0,cmd2:1,cmd3:0]` format instead of single integer\n- Each pipeline segment paired with its actual exit status from zsh `$pipestatus`\n- A.L.A.N. learning receives accurate per-command outcomes\n- Self-documenting output for human and AI analysis\n- Fixes bug where all commands reported `exit=0` regardless of actual status\n\n### 0.4.79\n**Server Modular Refactoring** — *Cleaner architecture*\n- Extracted MCP server into `zsh_tool/server.py` module\n- Centralized configuration in `zsh_tool/config.py`\n- Fixed plugin.json version sync with package version\n\n### 0.4.75\n**Pipeline Intelligence** — *Know which segment of your pipeline is failing*\n- A.L.A.N. now captures zsh's `$pipestatus` array for every pipeline\n- Each segment recorded as independent observation with its own exit code\n- When `cat foo | grep -badopts | sort` fails, you know *grep* was the problem\n- Quote/escape-aware pipeline parsing handles complex commands correctly\n- Backwards compatible: full pipeline still recorded alongside segments\n- 248 new test lines covering segment tracking and edge cases\n\n### 0.4.6\n**Configuration & Polish** — *User-configurable defaults, 91% coverage*\n- User config file (`~/.config/zsh-tool/config.yaml`) for custom yield_after\n- Test coverage improved: 303 tests, 91% coverage\n- Fixed null-check bug in task cleanup\n- Logo files consolidated and fixed\n\n### 0.4.5\n**Bundled Plugin** — *Zero-friction marketplace install*\n- Auto-install wrapper (`scripts/run-mcp.sh`) creates venv on first run\n- Portable `.mcp.json` using `${CLAUDE_PLUGIN_ROOT}`\n- ArkTechNWA marketplace support\n- No manual pip install required\n\n### 0.4.0\n**Test Suite & CI** — *290 tests, 89% coverage*\n- Comprehensive test suite covering all modules\n- CI pipeline with test and lint stages\n- Dynamic pipeline and coverage badges\n- Gentle test runner (`run_tests.sh`) with nice and sleep between files\n- Fixed deprecation warnings and lint errors\n- Added pytest-asyncio for async test support\n\n### 0.3.1\n**SSH Intelligence** — *Separate host connectivity from remote command success*\n- SSH commands now record dual observations (host + remote command)\n- Exit code classification: 0=success, 255=connection_failed, 1-254=command_failed\n- New `ssh_observations` table for SSH-specific tracking\n- `get_ssh_host_stats()` — per-host connection/command success rates\n- `get_ssh_command_stats()` — per-command stats across all hosts\n- SSH-specific insights: flaky hosts, reliable hosts, failing commands\n- 31 new tests for SSH tracking\n\n### 0.3.0\n**A.L.A.N. 2.0** — *\"Maybe you're fuckin' up, maybe you're doing it right.\"*\n- Retry detection: warns when repeating failed commands\n- Streak tracking: celebrates success, warns on failure\n- Fuzzy template matching: similar commands grouped\n- Proactive insights: contextual feedback before execution\n- Session memory: 15-minute rolling window\n- New database tables: `recent_commands`, `streaks`\n\n### 0.2.0\n- Yield-based execution with live oversight\n- PTY mode for full terminal emulation\n- Interactive input support via `zsh_send`\n- Task management: `zsh_poll`, `zsh_kill`, `zsh_tasks`\n- Fixed stdin blocking with subprocess.PIPE\n\n### 0.1.0\n- Initial release\n- NEVERHANG circuit breaker\n- A.L.A.N. learning database\n\n---\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n\n---\n\n<p align=\"center\">\n  <b>For Johnny5. For us.</b><br>\n  <i>ArkTechNWA</i>\n</p>\n",
  "bytes": 19304,
  "sha": "d5b9558285af49b9d0d14d42048b3a1a63725c1bf6c21f01f588a4d4389677e3",
  "repo_slug": "arktechnwa/zsh-tool",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_arktechnwa_zsh_tool_7e552d37/readme"
}