28 Unix tools. One binary. Zero dependencies.·the missing coreutils for the agent era·try vrk in your browser at vrk.sh/play·curl vrk.sh/install.sh | sh - ready in 5 seconds·

vrk slug

Try it in your browser

vrk, compiled to WebAssembly

# Turns a title into a lowercase, hyphenated slug.

Enter runs, Shift+Enter adds a line
    output
    Press RUN. Nothing leaves your browser.

    files you can cat:

    Edit the command and press RUN. Open the full playground for more recipes, or install vrk to run it on your own files.

    vrk slug converts any text to a URL-safe, filename-safe slug with Unicode normalization.

    The problem

    A slugify function turns “Uber’s $3.1B Q4 Revenue” into “uber-s–3-1b-q4-revenue” with a double hyphen. Another title has Unicode characters that pass through unchanged and break a downstream system expecting ASCII-only paths. tr and sed handle simple cases but miss edge cases consistently.

    The solution

    vrk slug converts any text to a URL-safe, filename-safe slug. It folds Latin text to ASCII (Straße becomes strasse) and keeps other scripts, such as Devanagari and CJK, as they are. It lowercases the text, replaces non-alphanumeric characters with hyphens, and collapses consecutive hyphens. --max cuts the slug at a word boundary.

    Before and after

    Before

    echo "$TITLE" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-'
    # Misses Unicode normalization, doesn't collapse double hyphens
    

    After

    echo $TITLE | vrk slug
    

    Example

    echo 'My Blog Post: A Deep Dive into LLM Pipelines!' | vrk slug
    

    Exit codes

    CodeMeaning
    0Success
    1Runtime error (I/O failure)
    2Interactive TTY with no stdin

    Flags

    FlagShortTypeDescription
    --separatorstringWord separator character or string
    --maxintMax output length in characters; truncated at last separator (0 = no limit)
    --asciiboolKeep only ASCII; other scripts are dropped (empty slug plus a warning if nothing is left)
    --json-jboolEmit JSON per line: {input, output}
    --quiet-qboolSuppress stderr output

    How it works

    vrk slug turns text into a URL-safe slug: lowercase words joined by hyphens.

    $ echo 'Hello World' | vrk slug
    hello-world
    
    $ echo 'My Blog Post: A Deep Dive into LLM Pipelines!' | vrk slug
    my-blog-post-a-deep-dive-into-llm-pipelines
    

    Custom separator

    $ echo 'Hello World' | vrk slug --separator _
    hello_world
    

    Length limit

    --max cuts the slug at a word boundary, so a word is never cut in half:

    $ echo 'My Very Long Blog Post Title That Goes On Forever' | vrk slug --max 30
    my-very-long-blog-post-title
    

    Batch processing

    slug makes one slug per input line:

    $ printf 'First Post\nSecond Post\nThird Post\n' | vrk slug
    first-post
    second-post
    third-post
    

    Non-Latin text

    Latin letters fold to ASCII. slug keeps other scripts as they are, so a Hindi or Japanese title still gets a slug:

    $ printf 'Straße\nनमस्ते दुनिया\n東京 2026\n' | vrk slug
    strasse
    नमस्ते-दुनिया
    東京-2026
    

    Every input line gives exactly one output line. If a line has nothing to keep, slug prints an empty line and warns on stderr, so the output lines match the input lines. Use --ascii when the target needs strict ASCII:

    $ echo '東京 2026' | vrk slug --ascii
    2026
    

    JSON output

    $ echo 'Hello World' | vrk slug --json
    {"input":"Hello World","output":"hello-world"}
    

    Pipeline integration

    Generate cache keys from URLs

    # Use slugified URLs as kv keys
    for url in $(cat urls.txt); do
      KEY=$(echo "$url" | vrk slug)
      vrk kv set --ns cache "$KEY" "$(vrk grab "$url")" --ttl 24h
    done
    

    Create filenames from document titles

    # Generate safe filenames for downloaded articles
    while IFS= read -r url; do
      TITLE=$(vrk grab --json "$url" | jq -r '.title')
      FILENAME=$(echo "$TITLE" | vrk slug --max 50).md
      vrk grab "$url" > "$FILENAME"
    done < urls.txt
    

    When it fails

    If you give no input on an interactive terminal, slug exits 2:

    $ vrk slug
    usage error: slug: no input
    $ echo $?
    2