26 Unix tools. One binary. Zero dependencies.·the missing coreutils for the agent era·vrk mcp - expose all 26 tools to any AI agent·curl vrk.sh/install.sh | sh - ready in 5 seconds·

vrk slug

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. Normalizes Unicode to ASCII, lowercases, replaces non-alphanumeric characters with hyphens, and collapses consecutive hyphens. --max truncates at word boundaries for length-limited contexts.

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; truncated at last separator (0 = no limit)
--json-jboolEmit JSON per line: {input, output}
--quiet-qboolSuppress stderr output

How it works

$ 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

Truncates at word boundaries so slugs don’t end mid-word:

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

Batch processing

One slug per input line:

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

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

No input:

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