Throwaway projects for every language, without the existential dread of naming them.
riff is a CLI tool for creating and managing disposable project workspaces. Need to spike something out? Test a weird idea at 2am? Prototype that thing your coworker said was "impossible"? Spin up an isolated project in any language, hack away, and clean up when you're done โ or don't. We won't judge.
Each project lives in ~/.riff/ and gets an auto-generated AI description so you can figure out what past-you was thinking. ๐ฎ
- ๐ Create isolated projects in one command โ any language, any framework
- ๐ List all your projects with AI-generated descriptions
- ๐ Open projects interactively or by ID
- ๐ค Export a project to any local folder when you're ready to ship it
- ๐งน Clean up projects individually or in bulk โ archives them safely instead of deleting
- ๐๏ธ Archive management โ list archived projects and permanently purge when ready
- ๐ค Auto-describe projects via Claude Code or GitHub Copilot CLI โ because you will forget what this one does
- ๐ Framework-agnostic โ Bun, Python, Rust, Go, Node, React, Next.js, or just an empty folder
| Platform | Status |
|---|---|
| macOS | โ Fully supported |
| Linux | โ Fully supported |
| Windows (WSL) | โ Fully supported |
Shell support: bash, zsh, and fish.
Note: riff requires a Unix-like shell environment. On Windows, use WSL (Windows Subsystem for Linux).
Prerequisites:
- Claude Code or GitHub Copilot CLI for auto-generated descriptions (optional, but your future self will thank you)
Homebrew (macOS/Linux):
brew install torryt/tap/riffGo:
go install github.com/torryt/riff@latestOr grab a prebuilt binary from Releases if commitment isn't your thing.
riff <command> [options]
| Command | Description |
|---|---|
riff new [template] |
Create a fresh project (pass template name or use interactive picker) |
riff list (or ls) |
List all projects with descriptions |
riff open [id] |
Open a project (interactive picker if no ID) |
riff clean [id] (or rm) |
Archive projects (multi-select if no ID) |
riff archive |
List archived projects |
riff archive purge [id] |
Permanently delete archived projects |
riff export <folder> [id] |
Export a project to a local folder (interactive picker if no ID) |
riff config <init|path> |
Manage configuration (initialize or print path) |
riff init [shell] |
Shell setup for auto-cd (auto-detects shell) |
riff update-docs |
Regenerate descriptions for all projects |
riff help |
Show help |
# Create a new project โ pick a template or go empty
riff new
# See what you've been up to
riff list
# Jump back into one
riff open
# Marie Kondo the ones that no longer spark joy (safely archived)
riff clean
# See what's in the archive
riff archive
# Permanently delete archived projects when you're sure
riff archive purge
# Graduate a prototype to a real project
riff export ~/code/my-new-thingriff new # interactive picker (or empty folder + git)
riff new bun # bun init
riff new dotnet # dotnet new console
riff new react # create-vite react-ts
riff new python # uv init
riff new rust # cargo init
riff new go # go mod init temp
riff new node # npm init
riff new next # create-next-app
riff new --run "uv init" # arbitrary init command
riff new --no-git # skip git initriff newcreates a directory under~/.riff/with a random 7-char ID, optionally runs a template command, and sets up a git repo with a post-commit hook- Every time you commit, the hook asks your AI provider to summarize your project in ~7 words (it's surprisingly good at this)
riff listshows all your projects with their descriptions โ no more opening 14 folders to find the one with the WebSocket experimentriff cleanarchives projects to~/.riff/archive/when the guilt of digital hoarding sets in โ nothing is permanently deleted until you runriff archive purge
riff is configured via a JSON file at ~/.riff/config.json. All settings are optional โ riff works out of the box with sensible defaults.
Generate a starter config file:
riff config initThis creates ~/.riff/config.json.
To print the config file path (useful in scripts):
riff config path| Key | Type | Default | Description |
|---|---|---|---|
ai_provider |
string |
"" (auto-detect) |
Preferred AI provider for project descriptions. Valid values: "claude", "copilot", or "". When empty, riff auto-detects (Claude Code preferred). Falls back to auto-detection if the chosen provider is not in $PATH. |
templates |
object |
{} |
Custom project templates. Each key is a template name used with riff new <name>. Templates with the same name as a built-in override it. See Custom templates. |
templates.<name>.command |
string |
โ | Shell command to initialize the project. Runs via sh -c in the new project directory. |
Full example:
{
"ai_provider": "copilot",
"templates": {
"python": { "command": "python -m venv .venv && pip install pytest" },
"django": { "command": "uv init && uv pip install django && django-admin startproject app ." },
"svelte": { "command": "pnpx create-vite . --template svelte-ts" }
}
}riff uses an LLM CLI tool to auto-generate short project descriptions. It works out of the box โ no config needed โ and degrades gracefully if nothing is installed (you just won't get descriptions).
| Provider | Binary | Detection priority |
|---|---|---|
| Claude Code | claude |
1st (preferred) |
| GitHub Copilot CLI | copilot |
2nd |
riff auto-detects whichever is available in your $PATH. If both are installed, Claude Code wins.
To pin a specific provider, set ai_provider in your config.
No problem. riff works fine without one โ descriptions are simply skipped.
riff ships with built-in templates that Just Workโข:
| Name | Command |
|---|---|
bun |
bun init -y |
dotnet |
dotnet new console |
react |
pnpx create-vite . --template react-ts |
python |
uv init |
rust |
cargo init . |
node |
npm init -y |
go |
go mod init temp |
next |
pnpx create-next-app . --ts --eslint --app |
Override built-ins or add your own via the templates key in ~/.riff/config.json (see Configuration):
{
"templates": {
"python": { "command": "python -m venv .venv && pip install pytest" },
"django": { "command": "uv init && uv pip install django && django-admin startproject app ." },
"svelte": { "command": "pnpx create-vite . --template svelte-ts" }
}
}User entries with the same name as a built-in override it. Your config, your rules. ๐คท
riff new and riff open automatically cd into the project directory โ but only if you set up the shell hook. Add one line to your shell config:
Add to ~/.bashrc or ~/.zshrc:
eval "$(riff init)"Add to ~/.config/fish/config.fish:
riff init fish | sourceWant to help make riff better? Excellent taste. See CONTRIBUTING.md for setup instructions and guidelines.
MIT โ go wild. ๐
