<!-- PROJECT HEADER -->
<br />
<div align="center">
<h1 align="center">Tapes V2</h1>
<img src="media/icon.svg" alt="Tapes logo" width="200">
An atomic dotfile switcher for ricing.
Swap your whole setup in one command, get it back in one command.
Rewritten to be safer, simpler and truly atomic
<a href="https://github.com/futurekismo-oss/tapes-v2/issues/new">Report Bug</a>
·
<a href="https://github.com/futurekismo-oss/tapes-v2/issues/new">Request Feature</a>
</div>
[](LICENSE)
[](Cargo.toml)
[](https://github.com/futurekismo-oss/tapes-v2/releases)
---
## Why Tapes?
If you stare at your desktop for longer than zero hours, you have personal configs of every app you use in `~/.config`. Your desktop decorations and app settings all technically live in there, which means changing how your entire desktop looks is done the manual way... or with **tapes**.
A **tape** is someone's whole `~/.config` setup — or just the parts they want to share — packed into one folder you can plug in with a single command.
Most dotfile managers (like GNU Stow or manual symlink managers) operate file-by-file. If something crashes midway, your `~/.config` is left in a broken, half-swapped state.
Tapes does the opposite: it builds your new config tree off to the side, then swaps the old and new trees in one single kernel operation. That means:
- **No half-states** — `~/.config` is either your old setup or the new one, never in between.
- **Instant rollback** — `tapes-v2 eject` puts things back exactly how they were, atomically.
- **Your files are never touched** — the original config is never modified, overwritten, or deleted.
That's the whole idea. If you want to know how the swap actually works, see [INTERNALS.md](INTERNALS.md).
In day-to-day terms: keep as many tapes in your library as you like and insert and eject them at will — the workflow is like running `matugen`, except instead of regenerating colors it swaps entire config trees. And insertion is not a full reset: only the configs a tape actually provides are overridden, everything else from your old `~/.config` carries over. A tape that ships just a `quickshell/` config swaps only that — your Chromium profile stays logged in and your `nvim` config stays yours, no re-login, no expenses.
---
## Tapes in Action
https://github.com/user-attachments/assets/6791a91b-a3be-429b-9fd0-adc34fc93b08
---
## Quickstart
Install a tape, insert it into your desktop, and eject when you want your old setup back:
```bash
# 1. Install downloads or copies a tape into the library (~/.tapes/). It doesn't touch anything else yet
tapes-v2 install https://github.com/username/some_dots --name demo
tapes-v2 install https://github.com/username/some_dots --dir dots/.config # or from a specific folder in the repo
tapes-v2 install https://github.com/username/some_dots --branch dots # or branch
# Or from a local folder:
# tapes-v2 install ~/my-dots --name demo
# 2. See what the tape contains and what it overrides
tapes-v2 show demo
# 3. Insert the tape (swaps your config and runs reload hooks)
tapes-v2 insert demo
# 4. Check what's active
tapes-v2 status
# 5. Revert back like nothing ever happened
tapes-v2 eject
```
> Tip: add `alias tapes="tapes-v2"` to your `~/.bashrc` or `~/.zshrc` to use `tapes` as a shortcut.
> **Before inserting a tape you didn't write, read it.** Hooks are arbitrary shell commands that run as your user the moment a swap lands — `hyprctl reload` is the friendly example, but a `tape.toml` can just as easily contain `rm -rf`. The swap itself is reversible; a hook command is not. `tapes-v2 show <name>` prints every hook a tape runs, and `insert --no-hooks` lets you test a tape without executing any of its commands first.
---
## Installation
Tapes is Linux-only — the whole trick is a kernel syscall, so macOS and BSD are out of scope.
### Option 1: Install script (Arch and other Linux)
```bash
curl -fsSL https://raw.githubusercontent.com/futurekismo-oss/tapes-v2/main/install.sh | bash
```
### Option 2: Nix / NixOS
```bash
nix run github:futurekismo-oss/tapes-v2 -- --help
# or add it to your profile:
nix profile install github:futurekismo-oss/tapes-v2
```
### Option 3: cargo binstall
```bash
# it is required to specify the version until tapes leaves beta
cargo binstall tapes-v2@0.1.3-beta
```
### Option 4: From source
```bash
git clone https://github.com/futurekismo-oss/tapes-v2.git
cd tapes-v2
cargo install --path .
```
### Shell Completion
For shell completion, add the following to your .zshrc or .bashrc or *other* depending on your shell
```bash
source <(COMPLETE=YOUR_SHELL_NAME_HERE tapes-v2)
```
tapes shell completion supports fish, zsh, bash, nushell and elvish
---
## Commands
| Command | What it does |
|---------|--------------|
| `tapes-v2 install <source>` | Downloads or copies a tape into your library (`~/.tapes/`) |
| `tapes-v2 show [name]` | Lists all installed tapes, or inspects one |
| `tapes-v2 insert [name]` | Swaps a tape into `~/.config` and runs its insert hooks |
| `tapes-v2 eject` | Swaps your original config back and runs its eject hooks |
| `tapes-v2 status [-v]` | Shows the active tape, where it came from, and its targets |
Handy flags on top of the above:
```bash
--dry-run # show the plan without touching anything
--no-hooks # skip the hook commands from the manifest (e.g. hyprctl reload)
install -b # install a specific branch, tag, or commit
--path # insert straight from any directory, skipping the library
-q # quiet output
```
The short version:
```bash
# Clone someone's rice and try it
tapes-v2 install user/awesome-rice
tapes-v2 install user/awesome-rice --dir dots # or from a specific folder in the repo
tapes-v2 install user/awesome-rice --branch dots # or branch
tapes-v2 insert awesome-rice
# Don't like it? One command and nothing ever happened
tapes-v2 eject
```
---
## Creating Your Own Tape
A tape is just a folder with your config overrides and a `tape.toml` manifest.
The top level of a tape mirrors the top level of `~/.config` — a folder named `hypr` in the tape overrides `~/.config/hypr`, and so on.
```text
my-tape/
├── tape.toml # manifest
├── hypr/ # overrides ~/.config/hypr
│ └── hyprland.conf
├── waybar/ # overrides ~/.config/waybar
│ └── config.jsonc
└── nvim/ # overrides ~/.config/nvim
└── init.lua
```
`tape.toml`:
```toml
[tape]
name = "neon-dream"
desc = "Vibrant synthwave theme for Hyprland + Waybar"
dependencies = ["hyprland", "waybar"]
[hooks]
# Commands run right after the swap
insert = [
"hyprctl reload",
"qs kill",
"waybar &",
"notify-send 'Tapes' 'Switched to neon-dream!'",
]
# Commands run after the tape is ejected
eject = [
"hyprctl reload",
"pkll waybar",
# hooks run in the current shell session not in the background
"qs -c caelestia -d",
"notify-send 'Tapes' 'Back to caelestia'",
]
```
Any configs your tape doesn't provide (Chrome profiles, `pulse`, whatever else lives in `~/.config`) stay exactly as they are.
---
## Acknowledgements
Thanks to these wonderful individuals for
[erotic-erox](https://github.com/exotic-erox) for calling out some lifecycle bugs on version 0.1.2-beta
[LilaccFlowerr](https://github.com/LilaccFlowerr) for providing the tapes-v2 showcase video and hopefully a gui in the future
[saksham_kumar](https://github.com/saksham_kumar) for being a contributor and writing the beloved install command
[Mvk](https://github.com/Mvkweb) for providing words of encourgement and support
[Clover](https://github.com/Cloverthestars) for providing the most encourgement and support, without them tapes wouldn't have gotten a rewrite and would have been the broken mess it was in Cassette-tapes, so massive thanks to him
---
## Roadmap
- [ ] A TUI or GUI
- [ ] Colored output
- [ ] More features
---
## Contributing
Contributions are welcome. See [Contributing.md](Contributing.md) for the guidelines.
The internals of how Tapes works live in [INTERNALS.md](INTERNALS.md) — worth a read before you touch the code.
---
## License
Distributed under the [MIT License](LICENSE).