or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/github-tobi--try

CLI tool for managing ephemeral experiment directories with fuzzy search

Workspace
tessl
Visibility
Public
Created
Last updated

To install, run

npx @tessl/cli install tessl/github-tobi--try@1.2.1

index.mddocs/

try - Ephemeral Workspace Manager

try 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.

Package Information

  • Package Name: try
  • Package Type: GitHub-hosted CLI tool
  • Primary Distribution: Homebrew, Direct Download, Nix Flakes
  • Language: Ruby
  • Repository: https://github.com/tobi/try
  • Version: 1.2.0

Installation

Homebrew

# 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.fish

Direct Download

curl -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

Nix Flakes

# 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.

Core Imports

After installation with shell integration, the try command is available as a shell function:

# Available after running: eval "$(try init ~/src/tries)"
try

For 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

Basic Usage

# 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 --version

Capabilities

All commands, their parameters, return values, and prerequisites.

Interactive Directory Selection

Launch an interactive terminal UI to browse and select from existing experiment directories.

try
try <query>

Parameters:

  • query (optional): Initial search term to filter directories

Prerequisites:

  • Requires TTY: Both STDIN and STDERR must be connected to a terminal
  • Shell integration must be configured for directory navigation

Returns:

  • Exit code 0 on success
  • Exit code 1 if cancelled (ESC or Ctrl-C in TTY)
  • Exit code 1 if try <query> invoked without TTY
  • Exit code 2 if try (no arguments) invoked without TTY (shows help message)

Output:

  • UI output to STDERR
  • Shell commands to STDOUT (when using shell wrapper)

Behavior:

  • Displays all directories in base path (default: ~/src/tries)
  • Provides fuzzy search filtering with scoring
  • Shows relative timestamps and relevance scores
  • Allows navigation with arrow keys or Ctrl-P/N
  • Creates new directory if query doesn't match existing ones

Error Cases:

  • Without TTY and with query: Outputs ANSI escape sequences and "Cancelled." to stdout, exits with code 1
  • Without TTY and no query: Shows help message, exits with code 2

Example:

# Launch interactive selector
try

# Fuzzy search for existing directory
try redis

Non-interactive alternatives (do not require TTY):

  • try --help and try --version
  • try init
  • try clone <url> (when not using shell wrapper)

Shell Integration Initialization

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 path

Prerequisites:

  • None (does not require TTY)

Returns:

  • Exit code 0
  • Shell function definition as text to stdout

Output: Shell function definition that can be evaluated:

  • For bash/zsh: A bash/zsh function named try (using try() { ... } syntax)
  • For fish: A fish function named try

Path Requirements:

  • ✅ Absolute paths starting with / are recognized (e.g., /home/user/mydir)
  • ❌ Paths with ~ are ignored (e.g., ~/mydir)
  • ❌ Relative paths are ignored (e.g., mydir)
  • If path is invalid or omitted, uses default (~/src/tries) or $TRY_PATH if set

Example:

# 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 New Directory

Create a new date-prefixed experiment directory and navigate to it.

try <name>

Parameters:

  • name (required): Name for the experiment

Prerequisites:

  • Shell integration must be configured for navigation

Returns:

  • Exit code 0 on success

Output:

  • Shell command to navigate to new directory (via stdout when using shell wrapper)

Behavior:

  • Creates directory with format: YYYY-MM-DD-<name>
  • Spaces in name are converted to hyphens
  • Automatically navigates to the new directory
  • If name already exists for today, appends numeric suffix (see Auto-versioning below)

Auto-versioning:

  • If YYYY-MM-DD-name exists and name ends with number: increments number
    • 2025-12-31-experiment1 exists → creates 2025-12-31-experiment2
  • If name doesn't end with number: appends -2, -3, etc.
    • 2025-12-31-redis exists → creates 2025-12-31-redis-2

Example:

# 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-api

Clone Git Repository

Clone 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:

  • Git must be installed
  • Shell integration required for automatic navigation

Returns:

  • Exit code 0 on success
  • Exit code 1 if URL is missing or git clone fails

Output:

  • Shell command to navigate to cloned directory (via stdout when using shell wrapper)
  • Git clone output to STDERR

Supported URL Formats:

  • https://github.com/user/repo.git
  • git@github.com:user/repo.git
  • https://gitlab.com/user/repo.git
  • git@host.com:user/repo.git

Auto-generated Directory Names:

  • Format: YYYY-MM-DD-<user>-<repo>
  • .git suffix automatically removed from repo name

Example:

# 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-try

Error Cases:

  • Missing URL: Exits with code 1
  • Git clone failure: Exits with code 1

Create Git Worktree

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:

  • Git must be installed
  • Repository path must be a valid git repository
  • Shell integration required for automatic navigation

Returns:

  • Exit code 0 on success
  • Exit code 1 if git worktree creation fails

Output:

  • Shell command to navigate to worktree directory (via stdout when using shell wrapper)
  • Git worktree output to STDERR

Behavior:

  • Creates directory with format: YYYY-MM-DD-<name>
  • Inside a git repository: adds a detached HEAD git worktree (not checked out to any branch)
  • Outside a git repository: creates a regular directory
  • Automatically navigates to the new directory

Name Default:

  • If name omitted (and not using .): defaults to repository basename

Example:

# 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-experiment

Error Cases:

  • try . without name: Exits with error
  • Non-git repository path: Creates regular directory instead of worktree
  • Git worktree creation fails: Exits with code 1

Display Help

Display usage instructions and examples.

try --help
try -h

Prerequisites:

  • None (does not require TTY)

Returns:

  • Exit code 0

Output:

  • Help text to stdout

Display Version

Display version number.

try --version
try -v

Prerequisites:

  • None (does not require TTY)

Returns:

  • Exit code 0

Output:

  • Version string to stdout (format: "try X.Y.Z")

Global Options

Command-line options that can be used with any command.

try [command] --path <directory>
try [command] --no-colors
try [command] --no-expand-tokens

Options:

  • --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:

  • Default: Internal formatting tokens ({h1}, {reset}, {/b}) are converted to ANSI escape sequences
  • With --no-expand-tokens: Tokens are preserved as literal strings instead of converting to ANSI codes
  • In non-TTY contexts: Tokens are automatically stripped regardless of this setting

Use 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-tokens

Manual Execution Mode

Advanced 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 query
  • try exec cd <query>: Change directory
  • try exec clone <url> [name]: Clone repository
  • try exec worktree <repo> [name]: Create worktree

Prerequisites:

  • TTY required for interactive subcommands

Returns:

  • Exit code 0 on success
  • Exit code 1 on cancellation or error

Output:

  • Shell script to stdout that should be evaluated
  • UI output to STDERR
  • On error or cancellation: Outputs Cancelled.\n to stdout

Behavior: 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:

  • Directory not found or operation cancelled: Outputs Cancelled.\n
  • In non-TTY environments: Interactive operations fail with Cancelled output

Configuration

Environment Variables

export TRY_PATH=~/code/sketches
export TRY_HEIGHT=40
export TRY_WIDTH=120
export NO_COLOR=1
export SHELL=/usr/bin/fish

Variables:

  • TRY_PATH: Base directory for all experiment directories

    • Type: String (directory path)
    • Default: ~/src/tries
    • Can be any valid directory path
  • TRY_HEIGHT: Override terminal height detection

    • Type: Positive integer (must be >0)
    • Default: Auto-detected via tput lines (fallback: 24)
    • Invalid values (0, negative, non-numeric) are ignored
  • TRY_WIDTH: Override terminal width detection

    • Type: Positive integer (must be >0)
    • Default: Auto-detected via tput cols (fallback: 80)
    • Invalid values (0, negative, non-numeric) are ignored
  • NO_COLOR: Disable ANSI color output

    • Type: Boolean (any non-empty value)
    • Default: Not set (colors enabled)
    • Follows no-color.org convention
  • SHELL: Shell type for init command

    • Type: String (path to shell executable)
    • Default: Auto-detected from environment
    • Used to detect Fish shell for appropriate function generation

Default Values

  • Base directory: ~/src/tries (or $TRY_PATH)
  • Terminal height: Auto-detected via tput lines (fallback: 24)
  • Terminal width: Auto-detected via tput cols (fallback: 80)
  • Colors: Enabled (unless NO_COLOR is set)

Interactive UI Controls

When in interactive selector mode (try or try <query>), these keyboard controls are available.

Navigation Controls

↑ 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:

  • Vim-style Ctrl-J/K navigation is not supported
  • Use Ctrl-P/N or arrow keys for navigation

Text Input Controls

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.

Directory Deletion Controls

Ctrl-D    Toggle deletion mark on highlighted directory
Enter     Confirm deletion (when in delete mode with marked directories)
ESC       Cancel deletion and clear all marks

Delete Mode Workflow:

  1. Press Ctrl-D to mark directories for deletion (trash icon appears)
  2. Press Ctrl-D again on marked directories to unmark
  3. Press Enter to proceed to confirmation
  4. Type YES (exact match, case-sensitive) to confirm deletion
  5. Press ESC at any time to cancel and clear all marks

Important:

  • Must type exactly YES (uppercase) to confirm
  • Case-sensitive match required
  • Marked directories are not deleted until confirmed

Directory Naming and Versioning

Date Prefix Format

All 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-123

Automatic Version Incrementing

When 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-test6

Case 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-3

Fuzzy Search Algorithm

The interactive selector uses a sophisticated fuzzy matching algorithm for directory search.

Scoring Criteria

The algorithm scores directories based on multiple factors:

  • Character matching: 1.0 point per matched character
  • Word boundary bonus: 1.0 point when match starts at word boundary
  • Proximity bonus: 2.0/√(gap+1) for character closeness
  • Density bonus: query length / last match position
  • Length penalty: 10 / (text length + 10)
  • Creation time bonus: 2.0/√(days since creation + 1)
  • Access time bonus: 3.0/√(hours since access + 1)
  • Date-prefix bonus: 2.0 points for YYYY-MM-DD format

Search Behavior

Query 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.3

Interpretation:

  • First column: Cursor indicator ( for selected item)
  • Second column: Directory name
  • Third column: Relative time since last access
  • Fourth column: Relevance score (higher is better match)

Exit Codes

0    Success (directory selected or command completed)
1    Cancelled, error, or missing required argument
2    No TTY available or no usable command provided

Exit Code Details

Code 0 - Success:

  • Directory successfully selected
  • Command completed successfully
  • --help, --version, init commands

Code 1 - Error/Cancellation:

  • Interactive mode cancelled (ESC or Ctrl-C in TTY)
  • Missing required arguments (e.g., try clone without URL)
  • Invalid command syntax
  • Git operations that fail
  • Some TTY-related failures

Code 2 - No Command:

  • try invoked without arguments and without TTY (shows help message)
  • Other non-interactive failure scenarios

Exit Code Examples

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"

Output Streams

try uses distinct output streams for different purposes:

  • STDOUT: Shell commands for eval (in exec mode)
  • STDERR: Interactive UI, prompts, and error messages

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"

Requirements

Core Requirements

  • Ruby interpreter: Any modern version (built into macOS, commonly available on Linux)
  • No gem dependencies: Uses only Ruby standard library
  • Standard library modules used: io/console, time, fileutils

TTY Requirements

Interactive 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 --version
  • try init [path]
  • try clone <url> (when not using shell wrapper)
  • try worktree <repo> (when not using shell wrapper)

TTY Failure Behavior:

  • Without TTY: "Error: try requires an interactive terminal" with exit code 1
  • Some contexts: May output ANSI escape sequences with exit code 2

Optional Dependencies

  • Git: Required only for clone and worktree features
  • Commands using git will fail with exit code 1 if git is not installed

Typical Workflows

Quick Experiment Workflow

# 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

Git Clone and Explore Workflow

# 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"

Git Worktree Workflow

# 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

Cleanup Workflow

# 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

Multi-day Project Workflow

# 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 separate

Terminal Behavior

Automatic Adaptation

  • Resize handling: Automatically detects and adapts to terminal resize events (SIGWINCH signal)
  • Dynamic redraw: UI redraws when terminal dimensions change
  • Efficient rendering: Uses double-buffered rendering (only redraws changed lines)
  • Non-TTY adaptation: Automatically switches to plain text output when not connected to a TTY (strips ANSI codes)

Output Routing

  • UI output: Goes to STDERR
  • Shell commands: Go to STDOUT
  • Result: Enables proper shell integration (eval stdout while showing UI on terminal)

Advanced Topics

Custom Base Directory

Three ways to set custom base directory (in order of precedence):

  1. Command-line option (highest precedence):

    try --path /custom/path
  2. Environment variable:

    export TRY_PATH=/custom/path
    try
  3. Init parameter (absolute paths only):

    eval "$(try init /custom/path)"

Color Output Control

Three ways to disable colors:

  1. NO_COLOR environment variable (standard):

    export NO_COLOR=1
    try
  2. --no-colors option:

    try --no-colors
  3. Non-TTY context (automatic): Colors are automatically disabled when STDOUT is not a TTY

Custom Shell Integration

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
}

Known Limitations and Edge Cases

Path Handling

  • try init only recognizes absolute paths starting with /
  • Paths with ~ are not recognized as absolute paths
  • Workaround: Use --path option or $TRY_PATH environment variable

TTY Detection

  • Some error scenarios show exit code 2 with ANSI escape sequences
  • Other scenarios show proper error message with exit code 1
  • Behavior varies based on which TTY checks fail
  • All non-TTY interactive attempts will fail, but error presentation may differ

Navigation Controls

  • Vim-style Ctrl-J/K navigation is not supported
  • Use Ctrl-P/N or arrow keys instead
  • Left/right arrow keys are ignored (no horizontal navigation)

Deletion Confirmation

  • Must type exactly YES (uppercase)
  • No partial match or lowercase accepted
  • No warning if you type something else - operation simply cancels

Environment Variable Constraints

  • TRY_HEIGHT and TRY_WIDTH must be positive integers
  • Values ≤0 or non-numeric values are silently ignored
  • Fallback to auto-detection or defaults

Git Worktree Behavior

  • Creates detached HEAD worktree (not checked out to any branch)
  • If not in a git repository, creates regular directory instead
  • No error message when falling back to regular directory