CLI tool for managing ephemeral experiment directories with fuzzy search
npx @tessl/cli install tessl/github-tobi--try@1.2.1try is a Ruby CLI tool for managing ephemeral experiment directories with fuzzy search, git integration, and automatic date-prefixing. It provides instant navigation to experiment directories and smart organizational features for developers who create many short-lived projects.
# Install via Homebrew tap
brew tap tobi/try
brew install try
# Add shell integration to bash/zsh
echo 'eval "$(try init ~/src/tries)"' >> ~/.zshrc
# Add shell integration to fish
echo 'eval (try init ~/src/tries | string collect)' >> ~/.config/fish/config.fishcurl -sL https://raw.githubusercontent.com/tobi/try/refs/heads/main/try.rb > ~/.local/try.rb
chmod +x ~/.local/try.rb
# Add to bash/zsh
echo 'eval "$(ruby ~/.local/try.rb init ~/src/tries)"' >> ~/.zshrc
# Add to fish
echo 'eval (~/.local/try.rb init ~/src/tries | string collect)' >> ~/.config/fish/config.fish# Quick run
nix run github:tobi/try
nix run github:tobi/try -- --help
nix run github:tobi/try init ~/my-tries# Home Manager integration
{
inputs.try.url = "github:tobi/try";
imports = [ inputs.try.homeManagerModules.default ];
programs.try = {
enable = true;
path = "~/experiments"; # optional, defaults to ~/src/tries
};
}Note: Shell integration is required for the tool to change your current shell directory. The init command generates a shell function that wraps the try command. This wrapper uses try exec internally, which outputs shell commands to stdout that can modify your current shell session.
After installation with shell integration, the try command is available as a shell function:
# Available after running: eval "$(try init ~/src/tries)"
tryFor direct invocation without shell integration:
# Direct Ruby execution (outputs shell script, doesn't change directory)
ruby ~/.local/try.rb exec
./try.rb exec
# Or via Nix
nix run github:tobi/try# Launch interactive selector to browse all experiments
try
# Create new experiment with auto-dating
try my-experiment
# Creates: ~/src/tries/2025-12-31-my-experiment
# Search for existing experiment with fuzzy matching
try redis
# Finds: 2025-12-14-redis-cache-test, 2025-12-03-redis-cluster, etc.
# Clone a repository into dated directory
try clone https://github.com/user/repo.git
# Creates: ~/src/tries/2025-12-31-user-repo
# Create git worktree from current repo
cd ~/projects/myapp
try . feature-test
# Creates: ~/src/tries/2025-12-31-feature-test (with git worktree)
# Get help and version
try --help
try --versionAll commands, their parameters, return values, and prerequisites.
Launch an interactive terminal UI to browse and select from existing experiment directories.
try
try <query>Parameters:
query (optional): Initial search term to filter directoriesPrerequisites:
Returns:
try <query> invoked without TTYtry (no arguments) invoked without TTY (shows help message)Output:
Behavior:
~/src/tries)Error Cases:
Example:
# Launch interactive selector
try
# Fuzzy search for existing directory
try redisNon-interactive alternatives (do not require TTY):
try --help and try --versiontry inittry clone <url> (when not using shell wrapper)Generate shell-specific function wrappers for bash, zsh, or fish.
try init [path]
try init --path <path>Parameters:
path (optional): Base directory for experiments. Must be an absolute path starting with /. Relative paths (including ~) are ignored.--path <path> (option form): Recommended way to specify custom pathPrerequisites:
Returns:
Output: Shell function definition that can be evaluated:
try (using try() { ... } syntax)tryPath Requirements:
/ are recognized (e.g., /home/user/mydir)~ are ignored (e.g., ~/mydir)mydir)~/src/tries) or $TRY_PATH if setExample:
# Default path (uses ~/src/tries or $TRY_PATH)
eval "$(try init)"
# Custom path with absolute path
eval "$(try init /home/user/code/experiments)"
# Using --path option (recommended)
eval "$(try init --path /home/user/code/experiments)"Shell Detection:
Uses $SHELL environment variable to detect Fish shell and generate appropriate function syntax.
Create a new date-prefixed experiment directory and navigate to it.
try <name>Parameters:
name (required): Name for the experimentPrerequisites:
Returns:
Output:
Behavior:
YYYY-MM-DD-<name>Auto-versioning:
YYYY-MM-DD-name exists and name ends with number: increments number
2025-12-31-experiment1 exists → creates 2025-12-31-experiment2-2, -3, etc.
2025-12-31-redis exists → creates 2025-12-31-redis-2Example:
# Create date-prefixed directory
try my-experiment
# Creates: 2025-12-31-my-experiment
# Spaces converted to hyphens
try new api
# Creates: 2025-12-31-new-apiClone a git repository into an automatically named, date-prefixed directory.
try clone <url> [name]
try <url> [name]Parameters:
url (required): Git repository URL (HTTPS or SSH format)name (optional): Custom directory name (overrides auto-generation)Prerequisites:
Returns:
Output:
Supported URL Formats:
https://github.com/user/repo.gitgit@github.com:user/repo.githttps://gitlab.com/user/repo.gitgit@host.com:user/repo.gitAuto-generated Directory Names:
YYYY-MM-DD-<user>-<repo>.git suffix automatically removed from repo nameExample:
# Auto-generated name
try clone https://github.com/tobi/try.git
# Creates: 2025-12-31-tobi-try
# Custom name
try clone https://github.com/tobi/try.git my-fork
# Creates: my-fork
# Shorthand (without 'clone')
try https://github.com/tobi/try.git
# Creates: 2025-12-31-tobi-tryError Cases:
Create a git worktree from a repository in a date-prefixed directory.
try . <name>
try <path> [name]
try worktree <repo> [name]Parameters:
repo: Path to git repository (. for current directory, or explicit path)name: Name for worktree directory (required when using ., optional otherwise)Prerequisites:
Returns:
Output:
Behavior:
YYYY-MM-DD-<name>Name Default:
name omitted (and not using .): defaults to repository basenameExample:
# From current repository (name required)
cd ~/projects/myapp
try . feature-branch
# Creates: 2025-12-31-feature-branch with git worktree
# From specific repository
try ~/projects/myapp feature-test
# Creates: 2025-12-31-feature-test
# Explicit worktree command
try worktree ~/projects/myapp experiment
# Creates: 2025-12-31-experimentError Cases:
try . without name: Exits with errorDisplay usage instructions and examples.
try --help
try -hPrerequisites:
Returns:
Output:
Display version number.
try --version
try -vPrerequisites:
Returns:
Output:
Command-line options that can be used with any command.
try [command] --path <directory>
try [command] --no-colors
try [command] --no-expand-tokensOptions:
--path <directory>: Override base directory (overrides $TRY_PATH environment variable)--no-colors: Disable ANSI color output--no-expand-tokens: Disable formatting token expansion (preserve internal tokens as literals)Note: Additional test-only flags exist for internal testing purposes but are intentionally undocumented as they are not intended for regular use.
Token Expansion Behavior:
{h1}, {reset}, {/b}) are converted to ANSI escape sequences--no-expand-tokens: Tokens are preserved as literal strings instead of converting to ANSI codesUse Case:
The --no-expand-tokens option is primarily useful for testing or debugging the tool's output formatting.
Example:
# Override base directory
try --path /tmp/experiments redis
# Disable colors
try --no-colors
# Preserve formatting tokens
try --no-expand-tokensAdvanced command for custom shell integration or wrappers.
try exec [subcommand] [args...]Subcommands:
try exec: Interactive selector (same as try)try exec <query>: Interactive selector with querytry exec cd <query>: Change directorytry exec clone <url> [name]: Clone repositorytry exec worktree <repo> [name]: Create worktreePrerequisites:
Returns:
Output:
Cancelled.\n to stdoutBehavior: This is the underlying command used by the shell wrapper function. It outputs shell commands that modify the current shell session.
Example:
# Manual execution with output capture
out=$(try exec redis 2>/dev/tty)
eval "$out"
# Output on cancellation
out=$(try exec cd nonexistent 2>/dev/tty)
echo "$out"
# Output: "Cancelled.\n"Error Handling:
Cancelled.\nCancelled outputexport TRY_PATH=~/code/sketches
export TRY_HEIGHT=40
export TRY_WIDTH=120
export NO_COLOR=1
export SHELL=/usr/bin/fishVariables:
TRY_PATH: Base directory for all experiment directories
~/src/triesTRY_HEIGHT: Override terminal height detection
tput lines (fallback: 24)TRY_WIDTH: Override terminal width detection
tput cols (fallback: 80)NO_COLOR: Disable ANSI color output
SHELL: Shell type for init command
~/src/tries (or $TRY_PATH)tput lines (fallback: 24)tput cols (fallback: 80)NO_COLOR is set)When in interactive selector mode (try or try <query>), these keyboard controls are available.
↑ or Ctrl-P Move cursor up one line
↓ or Ctrl-N Move cursor down one line
← → No effect (ignored)
Enter Select highlighted directory or create new directory from query
ESC or Ctrl-C Cancel selection and exit (returns exit code 1)Notes:
Readline-style text editing for the search query.
Backspace or Ctrl-H Delete character backward
Ctrl-A Move cursor to beginning of line
Ctrl-E Move cursor to end of line
Ctrl-B Move cursor backward one character
Ctrl-F Move cursor forward one character
Ctrl-K Kill (delete) from cursor to end of line
Ctrl-W Delete word backward (alphanumeric characters)Accepted Characters: Search input accepts alphanumeric characters, hyphens, underscores, periods, and spaces. Spaces are automatically converted to hyphens in the final directory name.
Ctrl-D Toggle deletion mark on highlighted directory
Enter Confirm deletion (when in delete mode with marked directories)
ESC Cancel deletion and clear all marksDelete Mode Workflow:
Ctrl-D to mark directories for deletion (trash icon appears)Ctrl-D again on marked directories to unmarkEnter to proceed to confirmationYES (exact match, case-sensitive) to confirm deletionESC at any time to cancel and clear all marksImportant:
YES (uppercase) to confirmAll directories created by try use the format: YYYY-MM-DD-<name>
Examples:
2025-12-31-redis-experiment
2025-12-31-api-test
2025-12-31-bugfix-123When a directory name already exists for the current date, try automatically increments the version.
Case 1: Name ends with a number
Increments the existing number:
Existing: 2025-12-31-experiment1
Creates: 2025-12-31-experiment2
Existing: 2025-12-31-test5
Creates: 2025-12-31-test6Case 2: Name doesn't end with a number
Appends -2, -3, etc.:
Existing: 2025-12-31-redis
Creates: 2025-12-31-redis-2
Existing: 2025-12-31-redis-2
Creates: 2025-12-31-redis-3The interactive selector uses a sophisticated fuzzy matching algorithm for directory search.
The algorithm scores directories based on multiple factors:
YYYY-MM-DD formatQuery Examples:
Query: "rds" → Matches: "redis-server", "redis"
Query: "connpool" → Matches: "connection-pool", "redis-connpool"
Query: "api" → Matches: "new-api", "api-test", "graphql-api"Scoring Display:
The UI shows relevance scores and relative timestamps:
→ 2025-12-14-redis-connection-pool 2h ago, 18.5
2025-12-03-thread-pool 3d ago, 12.1
2025-11-22-db-pooling 2w ago, 8.3Interpretation:
→ for selected item)0 Success (directory selected or command completed)
1 Cancelled, error, or missing required argument
2 No TTY available or no usable command providedCode 0 - Success:
--help, --version, init commandsCode 1 - Error/Cancellation:
try clone without URL)Code 2 - No Command:
try invoked without arguments and without TTY (shows help message)try --version # Returns 0 (success)
try --help # Returns 0 (success)
try init # Returns 0 (success)
try clone # Returns 1 (missing URL)
try # Returns 2 if no TTY (shows help), 0 if TTY available
try myquery # Returns 1 if no TTY, 0 or 1 in TTY
try exec cd nonexistent # Returns 1 and outputs "Cancelled.\n"try uses distinct output streams for different purposes:
Why this matters:
This separation allows the shell integration to work correctly by evaluating only the commands from stdout while displaying the UI on the terminal.
Implementation Detail:
The shell wrapper function redirects STDERR to /dev/tty to ensure the interactive UI remains visible while capturing shell commands from STDOUT:
# Shell wrapper pattern
out=$(try exec redis 2>/dev/tty)
eval "$out"io/console, time, fileutilsInteractive commands require both STDIN and STDERR connected to a TTY:
Requires TTY:
try (interactive selector)try <query> (interactive selector with query)Does NOT require TTY:
try --help, try --versiontry init [path]try clone <url> (when not using shell wrapper)try worktree <repo> (when not using shell wrapper)TTY Failure Behavior:
clone and worktree features# Create new experiment
try my-idea
# Automatically at: ~/src/tries/2025-12-31-my-idea
# Work in the directory...
# ... write code, test, experiment ...
# Later, quickly return
try idea
# Fuzzy search finds "2025-12-31-my-idea" instantly# Clone interesting repository
try https://github.com/user/interesting-lib
# Creates: ~/src/tries/2025-12-31-user-interesting-lib
# Work with it...
# ... explore code, make changes ...
# Next day, find it again
try inter
# Fuzzy search locates "interesting-lib"# In your main project
cd ~/projects/myapp
# Create experimental worktree
try . crazy-refactor
# Creates: ~/src/tries/2025-12-31-crazy-refactor
# Git worktree is linked to ~/projects/myapp
# Work in isolated environment...
# ... make experimental changes ...
# Git operations affect the main repo
# Abandon or merge back as needed# Browse experiments
try
# Mark old experiments with Ctrl-D
# (trash icon appears on marked items)
# Continue marking multiple directories
# Press Enter to proceed to confirmation
# Type "YES" to confirm deletion
# Marked directories are removed# Day 1: Start experiment
try redis-cache-test
# Creates: 2025-12-31-redis-cache-test
# Day 2: Continue work
try redis
# Fuzzy search finds yesterday's directory
# Recency bonus helps it rank high
# Day 3: New related experiment
try redis-cluster
# Creates: 2026-01-02-redis-cluster
# Both experiments remain separateThree ways to set custom base directory (in order of precedence):
Command-line option (highest precedence):
try --path /custom/pathEnvironment variable:
export TRY_PATH=/custom/path
tryInit parameter (absolute paths only):
eval "$(try init /custom/path)"Three ways to disable colors:
NO_COLOR environment variable (standard):
export NO_COLOR=1
try--no-colors option:
try --no-colorsNon-TTY context (automatic): Colors are automatically disabled when STDOUT is not a TTY
For advanced use cases, you can create custom shell wrappers:
# Custom wrapper function
my_try() {
local out
out=$(try exec "$@" 2>/dev/tty)
if [[ $? -eq 0 ]] && [[ -n "$out" ]]; then
eval "$out"
else
echo "Operation cancelled or failed"
fi
}try init only recognizes absolute paths starting with /~ are not recognized as absolute paths--path option or $TRY_PATH environment variableYES (uppercase)TRY_HEIGHT and TRY_WIDTH must be positive integers