
Before And After
Capture and share before-and-after artifacts (screenshots or files) via CLI uploads to 0x0.st or a custom blob endpoint for visual regression and release notes.
Overview
Before-and-after is an agent skill most often used in Ship (also Build, Launch) that uploads before/after files to 0x0.st or custom blob storage and returns shareable URLs.
Install
npx skills add https://github.com/vercel-labs/before-and-after --skill before-and-afterWhat is this skill?
- Bundled bash adapters upload comparison files to 0x0.st (no signup, 512 MiB cap, ~365-day retention) or a self-hosted BL
- before-after-cli/1.0 User-Agent on 0x0.st uploads for traceability
- Multipart form upload with a file field; accepts plain-text URL or JSON with a url field from custom endpoints
- Fails fast with clear errors when the file path, env var, or response is invalid
- 512 MiB max upload on 0x0.st
- Files on 0x0.st expire after 365 days (or sooner for larger files)
Adoption & trust: 1.1k installs on skills.sh; 199 GitHub stars; 0/3 security scanners passed (skills.sh audits).
What problem does it solve?
You have before-and-after files on disk but no quick, scriptable way to host them for QA, PRs, or launch posts.
Who is it for?
Indie builders who already generate comparison files and want agent-driven uploads during ship or launch checkpoints.
Skip if: Teams that need private, long-lived asset management, automated pixel diffing, or compliance-reviewed storage without third-party hosts.
When should I use this skill?
You have local before/after files and need public URLs via shell upload during review, ship, or launch workflows.
What do I get? / Deliverables
After running the adapters you get HTTPS URLs you can drop into tests, reviews, or distribution copy without manual drag-and-drop hosting.
- HTTPS URL to the uploaded comparison file
- stderr diagnostics when upload or validation fails
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Canonical shelf is Ship because the skill’s core job is proving what changed—visual or file diffs—right before or after you merge, deploy, or demo. Testing is the best fit: uploaded pairs support regression checks, QA sign-off, and evidence bundles rather than one-off ideation.
Where it fits
Upload paired screenshots after a UI fix so your agent can paste URLs into a regression checklist.
Host before/after images for README or internal docs without wiring S3 first.
Attach hosted comparison assets to a Product Hunt or changelog draft.
Reuse the same upload flow when support needs a quick visual proof link for a customer thread.
How it compares
Use as a lightweight upload helper for comparison assets—not a replacement for dedicated visual-regression platforms or design review suites.
Common Questions / FAQ
Who is before-and-after for?
Solo and indie builders using Claude Code, Cursor, or similar agents who ship web products and need shareable before/after proof in PRs, QA, or launch content.
When should I use before-and-after?
During Ship testing when attaching regression evidence, during Build docs when illustrating UI changes, or at Launch distribution when posts need hosted comparison images—anytime you have local files and need URLs fast.
Is before-and-after safe to install?
Review the Security Audits panel on this Prism page and treat 0x0.st or custom endpoints as untrusted: only upload non-sensitive artifacts and read the skill source before granting network and shell access.
SKILL.md
READMESKILL.md - Before And After
#!/bin/bash # 0x0.st adapter - Free, no-signup file hosting # https://0x0.st # # Usage: ./0x0st.sh <file> # Output: URL to uploaded file (stdout) # # Notes: # - Files expire after 365 days (or sooner for larger files) # - Max file size: 512 MiB # - No authentication required set -e FILE="$1" if [[ -z "$FILE" ]]; then echo "Usage: $0 <file>" >&2 exit 1 fi if [[ ! -f "$FILE" ]]; then echo "Error: File not found: $FILE" >&2 exit 1 fi # Upload to 0x0.st - returns the URL directly URL=$(curl -s -A "before-after-cli/1.0" -F "file=@$FILE" https://0x0.st) # Validate we got a URL back if [[ ! "$URL" =~ ^https?:// ]]; then echo "Error: Upload failed. Response: $URL" >&2 exit 1 fi echo "$URL" #!/bin/bash # Custom blob storage adapter - For self-hosted or custom endpoints # # Usage: ./blob.sh <file> # Output: URL to uploaded file (stdout) # # Environment: # BLOB_UPLOAD_URL Required. URL endpoint for uploading images # # Notes: # - Expects endpoint to accept multipart form upload with "file" field # - Expects response to be either: # - Plain text URL # - JSON with "url" field set -e FILE="$1" if [[ -z "$FILE" ]]; then echo "Usage: $0 <file>" >&2 exit 1 fi if [[ ! -f "$FILE" ]]; then echo "Error: File not found: $FILE" >&2 exit 1 fi if [[ -z "$BLOB_UPLOAD_URL" ]]; then echo "Error: BLOB_UPLOAD_URL environment variable not set" >&2 echo "" >&2 echo "Set it with:" >&2 echo " export BLOB_UPLOAD_URL='https://your-blob-service.com/upload'" >&2 exit 1 fi # Upload file RESPONSE=$(curl -s -X POST -F "file=@$FILE" "$BLOB_UPLOAD_URL") # Try to extract URL from JSON response URL=$(echo "$RESPONSE" | grep -o '"url"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/"url"[[:space:]]*:[[:space:]]*"//' | sed 's/"$//' || true) # Fallback: maybe the response is just the URL if [[ -z "$URL" ]]; then URL="$RESPONSE" fi # Validate we got a URL back if [[ ! "$URL" =~ ^https?:// ]]; then echo "Error: Upload failed. Response: $RESPONSE" >&2 exit 1 fi echo "$URL" #!/bin/bash # GitHub Gist adapter - Upload images via gh CLI # # Usage: ./gist.sh <file> # Output: Raw URL to uploaded file (stdout) # # Requirements: # - gh CLI installed and authenticated # # Notes: # - Creates a public gist for each upload # - Files persist indefinitely # - Requires GitHub authentication set -e FILE="$1" if [[ -z "$FILE" ]]; then echo "Usage: $0 <file>" >&2 exit 1 fi if [[ ! -f "$FILE" ]]; then echo "Error: File not found: $FILE" >&2 exit 1 fi # Check gh is available if ! command -v gh &> /dev/null; then echo "Error: gh CLI not found. Install from https://cli.github.com" >&2 exit 1 fi # Create gist and capture output GIST_OUTPUT=$(gh gist create "$FILE" --public 2>&1) # Extract the gist URL from output GIST_URL=$(echo "$GIST_OUTPUT" | grep -o 'https://gist.github.com/[^ ]*' | head -1) if [[ -z "$GIST_URL" ]]; then echo "Error: Failed to create gist. Output: $GIST_OUTPUT" >&2 exit 1 fi # Convert to raw URL # Format: https://gist.github.com/user/id -> https://gist.githubusercontent.com/user/id/raw/filename GIST_ID=$(echo "$GIST_URL" | sed 's|.*/||') FILENAME=$(basename "$FILE") # Get the raw URL via gh api RAW_URL=$(gh api "gists/$GIST_ID" --jq ".files[\"$FILENAME\"].raw_url") if [[ -z "$RAW_URL" ]]; then echo "Error: Could not get raw URL for gist" >&2 exit 1 fi echo "$RAW_URL" #!/bin/bash # capture.sh - Core screenshot capture using agent-browser # Usage: ./capture.sh <url> <output.png> [--full] [--element <selector>] # # Options: # --full Full page screenshot (viewport 1500x1000) # --element <sel> Element screenshot (auto-sized to element bounds) # # Examples: # ./capture.sh "http://localhost:3000" ~/Downloads/screenshot.png --full # ./capture.sh "http://localhost:3000" ~/Downloads/button.png --element ".btn-primary" set -e URL="$1" OUTPUT="$2" shift 2 # Default to full page MODE="full" SEL