Metadata-Version: 2.4
Name: sshrew
Version: 0.1.0
Summary: Let Claude reach any box you'd normally SSH with zero inbound access.
Project-URL: Homepage, https://github.com/duriantaco/sshrew
Project-URL: Repository, https://github.com/duriantaco/sshrew
Project-URL: Issues, https://github.com/duriantaco/sshrew/issues
Author: sshrew contributors
License-Expression: MIT
License-File: License
Keywords: ai-agents,claude,cloudflare-tunnel,devops,mcp,remote-access,ssh
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Systems Administration
Requires-Python: >=3.10
Requires-Dist: fastmcp<3,>=2.3
Description-Content-Type: text/markdown

# sshrew

<p align="center">
  <img src="sshrew/assets/sshrew.png" alt="sshrew" width="220">
</p>

Let Claude reach any machine you'd normally SSH into. Claude can now read
files, tail logs, run allowlisted commands **without inbound SSH, port
forwarding, or config files.** Works on home servers, VPSes, Raspberry Pis,
Jetsons, whatever. If it runs Linux and can dial out, sshrew can bridge it.

## Quick start

On the machine you want Claude to see:

```bash
curl -fsSL https://raw.githubusercontent.com/duriantaco/sshrew/main/install.sh | bash
```

It prints:

```
==============================================================
  Your bridge is live. In Claude, go to:
    Settings -> Connectors -> Add custom connector
  and paste this URL:

    https://random-words.trycloudflare.com/kJx.../mcp
==============================================================
```

Paste that URL into claude.ai, enable the connector in a chat, done. By
default Claude can only read `~/.sshrew-share`; pass `--root DIR` when you
want to expose a specific project or log directory.

That one command handles everything: installs `uv` (which brings its own
Python 3.12, so old distros work), fetches sshrew, generates and saves a
secret token, downloads the right `cloudflared` binary for your CPU, opens
the tunnel, and starts the server.

## How it works

SSH is you reaching *in*. sshrew is the box reaching *out*:

```
claude.ai --(custom MCP connector)--> https://xxx.trycloudflare.com/<token>/mcp
                                                   |
                                        cloudflared (outbound only)
                                                   |
                                        sshrew on 127.0.0.1:8787
```

You need access to the machine exactly once — to run the installer. After
that (especially as a systemd service) you never reach in again.

The secret token lives in the URL path, so possession of the URL is the
credential. It's stored in `~/.config/sshrew/token`, reused across restarts,
and rotated with `--rotate-token`.

Every tool call is also recorded locally in `~/.config/sshrew/audit.jsonl`.
The log stores metadata like tool name, path, argv, exit code, bytes returned,
duration, and a token fingerprint. It does not store file contents, command
output, or the secret token itself. Ask Claude to call `recent_activity()` to
review what happened in the current session.

## Multiple machines

Run sshrew on each box. Each gets its own token and its own connector entry
("home-server", "lab-pi", "gpu-box"). Enable several in one chat and ask
Claude to compare across them.

## Options

Default is **read-only**, scoped to `~/.sshrew-share`.

```bash
sshrew --profile readonly                  # default: shared folder only
sshrew --profile dev                       # shared folder plus ~/projects and ~/src if present
sshrew --profile server                    # logs plus safe read-only diagnostics
sshrew --profile edge                      # server profile plus edge-device diagnostics
sshrew --profile full-trust                # home directory plus unrestricted shell; be careful
sshrew --root ~/projects --root /var/log     # narrow what Claude can read
sshrew --allow-shell --allow journalctl --allow systemctl
sshrew --allow-shell                         # full shell access; use only on trusted links
sshrew --no-tunnel                           # bring your own tunnel
sshrew --rotate-token                        # invalidate the old URL
```

Profiles are conservative. `dev` does not enable shell. `server`, `edge`,
`workstation`, and `ops` enable only a small read-oriented command allowlist.
`full-trust` is the only profile that grants unrestricted shell access.

Flags pass through the installer too:

```bash
curl -fsSL .../install.sh | bash -s -- --profile server
```

## Installing permanently

```bash
uv tool install --python 3.12 git+https://github.com/duriantaco/sshrew
sshrew
```

Run at boot with systemd. This installs the service for the current Linux user:

```bash
sed "s/^User=me/User=$USER/" sshrew.service | sudo tee /etc/systemd/system/sshrew.service >/dev/null
sudo systemctl daemon-reload && sudo systemctl enable --now sshrew
```

That user controls what sshrew can read and run. Keep it non-root.

Heads-up: **quick-tunnel URLs change every restart**, so a reboot means
re-pasting the connector URL. For a stable URL, point a named Cloudflare
tunnel or Tailscale Funnel at `127.0.0.1:8787` and run `sshrew --no-tunnel`.
The sample service includes systemd sandboxing and only allows writes to
`~/.config/sshrew` and `~/.sshrew-share`.

## Do I need nginx?

Not for the default setup. sshrew listens on `127.0.0.1`, and `cloudflared`
is the only public-facing network layer. nginx does not fix token leakage,
path scoping, or command execution risk.

Use nginx, Caddy, or a named Cloudflare Tunnel with Cloudflare Access if you
are directly exposing a stable domain and need TLS termination, request
limits, access logs, mTLS, SSO, or extra rate limiting.

## Roadmap

sshrew should be more than a tunnel. The goal is an agent-aware host capsule
for anything you can run: laptops, workstations, home servers, VPSes, lab
machines, Raspberry Pis, Jetsons, NAS boxes, CI runners, and edge devices.
Every machine gets explicit, inspectable rules for what an AI agent can see
or do.

- Capability tokens: mint separate URLs for separate roots, tools, and TTLs.
- Local approval queue: require terminal approval for risky operations like
  service restarts, package installs, or writes.
- Audit controls: retention, export, tamper-evident hashes, and per-token
  activity views.
- Profiles: per-profile command arguments, root templates, and generated
  systemd services.
- Host facts: richer GPU, network, process, and service inventory.
- Device packs: optional tools for specific environments like NVIDIA Jetson,
  Raspberry Pi, Docker hosts, systemd servers, macOS laptops, Linux laptops,
  NAS boxes, and CI runners.
- Safer ops tools: expose `tail_logs`, `restart_service`, `docker_status`, and
  `journal_errors` as structured tools instead of relying on raw shell.
- Stable URL wizard: generate named Cloudflare Tunnel, Tailscale Funnel, or
  local-only configs from one command.
- Cloudflare Access mode: support service-token headers and JWT validation for
  stable public deployments.
- Live dashboard: show current URL, roots, enabled tools, recent calls, and a
  one-click token revoke.
- Event channels: push alerts when logs spike, thermals go high, disk fills, or
  a watched service fails.

## Security notes

- The URL is the password. Long random token, never post it, rotate if in doubt.
- `--root` is a hard jail. Paths are fully resolved, including symlinks, and refused if they escape.
- Shell is off unless you pass `--allow-shell`. With `--allow CMD`, sshrew executes the parsed command directly instead of through a shell, so shell operators like `&&` and `|` are not executed. Without `--allow`, `--allow-shell` grants full shell access.
- sshrew runs with the permissions of its user. DO NOT run it as root.
- Reads are size-capped, negative offsets and sizes are refused, and binary files are refused.
- Search skips hidden directories and symlinks that point outside the allowed roots.

## Tools exposed

| tool | what it does |
|---|---|
| `list_dir(path)` | directory listing inside allowed roots |
| `read_file(path, offset, max_bytes)` | chunked text reads |
| `file_info(path)` | size / mtime / permissions |
| `search_files(root, name_glob, contains)` | recursive find + grep-lite |
| `run_command(command)` | shell, gated by `--allow-shell` / `--allow` |
| `host_facts()` | structured OS / CPU / memory / disk / service / device facts |
| `system_status()` | uptime, memory, disk (+ tegrastats if it's a Jetson) |
| `recent_activity(limit)` | recent audit log entries for accountability |

## License

MIT
