# shagent: Bun MCP + OpenRouter free loop after I deleted the Zsh shell harness

Source: https://www.michaelchurley.com/blog/shagent-bun-mcp-openrouter-after-zsh-harness-delete  
Published: 2026-06-22  
Author: Michael C. Hurley  
Tags: shagent, bun, typescript, mcp, model-context-protocol, openrouter, cli, agent, zsh, filesystem-mcp, chrome-devtools-mcp, michaelmonetized

![OG / zsh to bun](/blog/shagent-bun-mcp-openrouter-after-zsh-harness-delete/screenshots/zsh-to-bun.png)

## Who

I wanted a shell-native agent that already knew my Zsh profile. Then I tore that harness out and put a Bun MCP controller in its place.

For operators who care about the honest split between a **deleted Zsh THOUGHT/COMMAND loop** and the **HEAD Bun + OpenRouter + filesystem MCP** stack under the same public repo name.

## What

I built **shagent**, public https://github.com/michaelmonetized/shagent. HEAD `61ecd7d`. **3** commits. **0** stars. Default **main**. `package.json` **1.0.0**. README is **0 bytes**.

**At HEAD (Bun / TypeScript):**

- Entry `./shagent` (`#!/usr/bin/env bun`): requires `OPENROUTER_API_KEY`; model `SHAGENT_MODEL` or **`openrouter/free`**
- `Shagent` in `src/controller/shagent.ts` (~79 LOC): MCP `Client` + `StdioClientTransport` running `npx -y @modelcontextprotocol/server-filesystem` on `process.cwd()`
- OpenRouter `https://openrouter.ai/api/v1/chat/completions` loop, **max 15** turns
- System prompt forces JSON: `{"action":"tool_name","args":{...}}` or `{"message":"..."}`; regex scrape `/{.*?}/gs`; `client.callTool`
- Sibling probe `src/controller/index.ts` lists tools from `npx -y chrome-devtools-mcp`; that probe is **not** what the CLI entry wires

![Agent loop](/blog/shagent-bun-mcp-openrouter-after-zsh-harness-delete/screenshots/agent-loop.png)

**Deleted on the Jun 22 rewrite (`2ecb32f`):** `src/shagent.sh`, **258** lines of Zsh.

What that harness did (still recoverable from `0729083`):

- Source `~/.zshenv` / `.zprofile` / `.zshrc` + optional `.env`
- Session `-s/--session` (default `default`)
- Deps: `rg fd eza bat git jq curl … qmd mcp-cli`
- Response contract: `THOUGHT:` / `COMMAND:` then `eval`
- Optional async `qmd update` / `qmd embed`
- Same OpenRouter free default

![Deleted Zsh harness](/blog/shagent-bun-mcp-openrouter-after-zsh-harness-delete/screenshots/zsh-harness.png)

**Fiction still in-tree:** `index.html` sells Launch, scale, and monitor autonomous AI agents with CTA to `github.com/shagent/getting-started` and footer **Rusty P. Shackelford**. Fiction only; no deploy; unwired to `./shagent`.

![Fiction lander](/blog/shagent-bun-mcp-openrouter-after-zsh-harness-delete/screenshots/fiction-lander.png)

**Residue:** `stdout-test.txt` (~116KB) is a shell-era OpenRouter request dump that still narrates Zsh + mcp-cli + qmd. Second nightly `61ecd7d` is an **empty** commit (message only).

Sibling surfaces to keep straight: `orclawstrator` (OpenClaw Swift/Go command center), `mission-control` / `hurley-mission-control`. This public repo is local Bun + npx MCP or it does not run.

## Where

Code: [github.com/michaelmonetized/shagent](https://github.com/michaelmonetized/shagent), public.

Run (facts from entry): set `OPENROUTER_API_KEY`, optional `SHAGENT_MODEL`, then `./shagent 'task description'` with Bun available. `bun.lock` present; no scripts block in `package.json`.

No live product URL. No claimed domain.

## When

- **2026-05-26.** `0729083` init: empty README + Zsh harness
- **2026-06-22 16:50 ET.** `2ecb32f` nightly: delete `src/shagent.sh`; add Bun controller, fiction HTML, stdout dump, uncap
- **2026-06-22 17:56 ET.** `61ecd7d` nightly: empty tree diff; HEAD
- Pack prepared **2026-09-08 ~4:55 PM ET** (draft + assets only)

## Why

I needed a minimal OpenRouter agent that could call tools. The Zsh version lived inside my shell profile. The Bun version talks MCP over stdio to a filesystem server and keeps the model choice on OpenRouter free by default. The marketing HTML and the empty README are the honesty tax sitting next to that loop.

**Engagement:** how many public agent repos still ship a fiction lander and a 0-byte README after deleting the shell harness that `stdout-test.txt` still describes?
