npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@abhi-arya1/wt

v0.0.9

Published

Git worktree sandboxes, locally or on remote hosts over SSH.

Readme

wt

Run git worktree sandboxes, locally or on remote hosts over SSH, with minimal setup.

wt clones your repo into a bare mirror, then spins up isolated worktrees you can enter, run commands in, and throw away when you're done. Works on your machine or any box you can SSH into, with SSH keys, agents, environments, and more included.

wt
├── host
│   ├── add [name]
│   ├── ls
│   ├── check <name>
│   ├── rm <name>
│   ├── map <name> <localPort> <hostPort>
│   └── unmap <name> <localPort>
├── up [name]
├── local [name]
├── rename <old> <new>
├── enter <name>
├── run <name> <cmd>
├── sessions
├── gc
├── doctor
├── bootstrap
├── ls
├── rm <name>
└── status <name>

Install

# with any package manager, but bun is recommended
bun install -g @abhi-arya1/wt

Requires Bun (v1.3.3+). You can also build a standalone binary with bun build --compile if you prefer — no runtime needed, but the binary will be larger.

From source

git clone https://github.com/abhi-arya1/wt.git && cd wt
bun install
bun run build
bun link

Or just run it directly during development:

bun run dev -- <command>

Quick start

Local sandbox

You're in a git repo. You want an isolated copy to mess around in without touching your working tree.

wt local my-experiment --enter
# you're now in a worktree at .wt/sandboxes/my-experiment
# type `exit` to leave the sandbox shell

# or just let it pick the name from your current branch
wt local --enter
# sandbox named after your current branch

Remote sandbox

You have a server you can SSH into. Register it as a host, then spin up sandboxes there.

wt host add prod-box --ssh [email protected] --root /srv/wt
wt up my-feature --host prod-box --enter

Clean up

wt rm my-experiment       # remove a specific sandbox
wt gc                     # remove all sandboxes older than 7 days
wt gc --older-than 1d     # more aggressive
wt gc --dry-run           # see what would get deleted

Agent Usage

If you are using an agent to make sandboxes for multiple agents to work within them, you can install wt then give agents the SKILL.md file. This will allow them to understand usage of wt and create sandboxes on your behalf.

Guides

Setting up a remote host from scratch

  1. Make sure the remote box has git installed and your SSH key is authorized.

  2. Add the host:

wt host add myserver --ssh [email protected] --root /home/me/wt-sandboxes

This registers the host and runs a connectivity check. If it passes, you're good.

  1. Check what's installed on the remote:
wt bootstrap --host myserver --tmux --agents claude,opencode

This tells you what's present and what's missing. It doesn't install anything -- just reports.

  1. Verify everything works:
wt doctor --host myserver
  1. Create a sandbox from any local git repo:
cd ~/projects/my-app
wt up test-sandbox --host myserver --enter

You're now in a shell on myserver inside a worktree of your repo. .env files from your local directory get copied over automatically.

  1. Run commands without entering:
wt run test-sandbox -- make build
wt run test-sandbox -- bun test
  1. Use tmux for persistent sessions:
wt enter test-sandbox --tmux
# detach with ctrl-b d, reattach later with the same command

Running multiple sandboxes for parallel work

Say you need to test three branches at once.

wt up --branch feature/auth
wt up --branch feature/payments
wt up --branch fix/header-bug

wt ls
# NAME         HOST   REF       CREATED
# auth         local  a1b2c3d4  2/8/2026
# payments     local  e5f6g7h8  2/8/2026
# header-bug   local  i9j0k1l2  2/8/2026

wt run auth -- bun test
wt run payments -- bun test
wt run header-bug -- bun test

# rename one if you want
wt rename auth login-revamp

# done, clean up
wt rm login-revamp
wt rm payments
wt rm header-bug

SSH keys and identity files

Use -i to point at a specific key when adding a host, and -p for a non-standard port:

wt host add mybox --ssh [email protected] --root /srv/wt -i ~/.ssh/id_mybox -p 2222

These are stored in config and used for every SSH and SCP operation to that host. If you don't pass -i, wt uses whatever OpenSSH picks from your agent or default key.

Private repos on remote hosts

When you run wt up --host myserver, wt tells the remote to git clone --bare --mirror <origin>. That means the remote host needs access to your git remote (e.g. GitHub). For private repos, you have two options:

Option 1: SSH agent forwarding (recommended)

Add ForwardAgent yes for the host in your ~/.ssh/config:

Host myserver
    HostName 10.0.0.5
    User deploy
    ForwardAgent yes

Now your local SSH keys are available on the remote when wt runs git commands. No keys need to be deployed on the server.

Option 2: Deploy a key on the remote

Add an SSH key on the remote host and register it as a deploy key with your git provider (e.g. GitHub deploy keys). This works without agent forwarding but means the remote has standing access to the repo.

Hosts behind firewalls and jump hosts

wt doesn't have explicit jump host flags, but it passes the SSH target directly to OpenSSH, so anything in your ~/.ssh/config is honored. To reach a host behind a bastion:

Host bastion
    HostName bastion.example.com
    User ops

Host internal-box
    HostName 10.0.1.50
    User deploy
    ProxyJump bastion
    ForwardAgent yes

Then register it using the alias:

wt host add internal-box --ssh internal-box --root /srv/wt

wt will connect through the bastion transparently. The same applies to ProxyCommand, custom ControlMaster settings, or any other OpenSSH config directives.

Pushing and creating PRs from a sandbox

Sandboxes are regular git worktrees — standard git commands work as expected. Push branches and create PRs the same way you normally would:

wt enter my-sandbox

git checkout -b my-feature
# make changes
git add .
git commit -m "my changes"
git push -u origin my-feature

# create a PR with the GitHub CLI
gh pr create --title "My feature" --body "Description of changes"

You can also do this without entering the sandbox:

wt run my-sandbox -- git push -u origin my-feature
wt run my-sandbox -- gh pr create --title "My feature" --body "Description"

Note: Because wt uses git clone --bare --mirror, the mirror fetches all remote refs including GitHub's internal PR refs (refs/pull/*/head). A plain git push with no arguments may try to push these back and produce harmless remote rejected errors. To avoid this, push specific branches explicitly (git push origin my-branch) or set git config --global push.default current.

Using with tmux sessions

Every sandbox can have a tmux session tied to it. Sessions are named wt-<sandboxId>.

wt enter my-sandbox --tmux      # creates or reattaches to tmux session
wt sessions                     # list all wt-managed tmux sessions
wt sessions --host prod-box     # list sessions on a remote host

Command reference

wt up [name]

Create a sandbox worktree on a host. If name is omitted, it defaults to the branch name from -b / --ref, or the current branch. When -b is not provided, the sandbox stays on the same branch you're currently on.

| Flag | Description | |---|---| | -H, --host <name> | Target host (defaults to configured default, falls back to local) | | -b, --branch <name> | Create or use a branch with this name | | -r, --ref <ref> | Git ref to check out (branch, tag, or sha that must exist) | | -e, --enter | Enter the sandbox after creating it | | --tmux | Use tmux when entering (implies --enter) | | --json | JSON output |

wt local [name]

Shorthand for wt up [name] on the local host. Same options minus --host.

| Flag | Description | |---|---| | -b, --branch <name> | Create or use a branch with this name | | -r, --ref <ref> | Git ref to check out (branch, tag, or sha that must exist) | | -e, --enter | Enter the sandbox after creating it | | --tmux | Use tmux when entering (implies --enter) | | --json | JSON output |

wt rename <old> <new>

Rename a sandbox.

| Flag | Description | |---|---| | --json | JSON output |

wt enter <name>

Open a shell inside a sandbox.

| Flag | Description | |---|---| | --tmux | Use a tmux session instead of a plain shell | | --json | Print sandbox record as JSON without entering |

wt run <name> <cmd...>

Run a command inside a sandbox. Streams output by default.

| Flag | Description | |---|---| | --json | Capture stdout/stderr and return as JSON (must come before --) | | --quiet | Suppress non-error output (must come before --) |

Note: flags for wt run itself go before --. Everything after -- is passed to the command.

wt run my-sandbox --json -- git log --oneline -5

wt ls

List all sandboxes.

| Flag | Description | |---|---| | -H, --host <name> | Filter by host | | --json | JSON output |

wt rm <name>

Remove a sandbox. Deletes the worktree directory, metadata, and config entry. Prunes the mirror's worktree references.

| Flag | Description | |---|---| | --json | JSON output |

wt status <name>

Show sandbox details: host, ref, path, age, whether the directory exists, and whether a tmux session is active.

| Flag | Description | |---|---| | --json | JSON output |

wt sessions

List active wt-* tmux sessions.

| Flag | Description | |---|---| | -H, --host <name> | Target host | | --json | JSON output |

wt gc

Garbage-collect stale sandboxes. A sandbox is stale if it's older than the threshold or its directory no longer exists.

| Flag | Description | |---|---| | -H, --host <name> | Target host (omit for all hosts) | | --older-than <dur> | Age threshold, e.g. 7d, 24h, 1w (default: 7d) | | --dry-run | Preview what would be deleted | | --json | JSON output |

wt doctor

Check that git, bun/node, and tmux are available on a host.

| Flag | Description | |---|---| | -H, --host <name> | Target host | | --json | JSON output |

wt bootstrap

Check host readiness. Reports what's installed and what's missing. Does not install anything.

| Flag | Description | |---|---| | -H, --host <name> | Target host | | --tmux | Include tmux in checks | | --agents <list> | Comma-separated agent CLIs to check (e.g. claude,opencode) | | --json | JSON output |

wt host add [name]

Register or update a remote host.

| Flag | Description | |---|---| | -s, --ssh <target> | SSH target (alias, user@host, or ssh://user@host:port) | | -r, --root <path> | Remote base directory (absolute path) | | -d, --default | Set as default host | | -p, --port <n> | SSH port | | -i, --identity <path> | Path to SSH identity file | | -t, --connect-timeout <s> | Connection timeout in seconds (default: 10) | | -l, --labels <k=v,...> | Comma-separated key=value labels | | --no-check | Skip connectivity check | | --json | JSON output |

wt host ls

List all configured hosts.

| Flag | Description | |---|---| | --json | JSON output |

wt host check <name>

Test SSH connectivity and capabilities of a host.

| Flag | Description | |---|---| | --json | JSON output |

wt host rm <name>

Remove a host.

| Flag | Description | |---|---| | -y, --yes | Skip confirmation prompt | | --json | JSON output |

wt host map <name> <localPort> <hostPort>

Add a port mapping to a host. When you SSH into the host (via wt enter, wt up --enter, etc.), the mapping is applied as -L localPort:localhost:hostPort, forwarding traffic from your local port to the remote port.

| Flag | Description | |---|---| | --json | JSON output |

# Forward local port 3000 to remote port 8080
wt host map myserver 3000 8080

# Now when you enter a sandbox, localhost:3000 reaches the remote's port 8080
wt enter my-sandbox
curl localhost:3000  # hits remote:8080

Mappings are stored in config and persist across restarts. If a mapping for the same local port already exists, it is updated.

wt host unmap <name> <localPort>

Remove a port mapping from a host.

| Flag | Description | |---|---| | --json | JSON output |

wt host unmap myserver 3000

How it works

wt creates a bare mirror of your repo, then uses git worktree add to spin up isolated checkouts. Each sandbox gets its own directory and metadata file.

.wt/                          # local root (inside your repo)
  mirrors/
    <repoId>.git/             # bare mirror
  sandboxes/
    <name>/                   # worktree checkout
  meta/
    <sandboxId>.json          # sandbox metadata

Remote hosts use the same layout under the configured root path (e.g. /srv/wt). All remote operations go over SSH.

Config lives at ~/.config/wt/config.json and stores hosts and sandbox records. Every structured command supports --json for scripting.

JSON output

Every command that produces structured output supports --json. Errors in JSON mode return:

{
  "ok": false,
  "error": "what went wrong"
}

This makes it straightforward to compose wt with other tools, scripts, or agents.

Future Plans

Unsure if this will be added, but I'd like to add:

  • Cloud provider abstractions (AWS, Fly.io, etc.)
  • Automatic download for sandbox dependencies
  • Better observability, error handling, cleanup, and devex