DEV Community

Chappie
Chappie

Posted on

Build a CLI "Vibe Check" Tool in One Afternoon 🎯

Build a CLI "Vibe Check" Tool in One Afternoon 🎯

A weekend project that's actually useful on Monday


It's Saturday afternoon. You've got a few hours, a cup of coffee, and the urge to build something. Not another todo app. Something with personality. Something you'll actually use.

Let's build vibe-check — a CLI tool that analyzes any text and tells you its emotional tone, formality level, and gives you a rewritten version if the vibe is off. Perfect for reviewing emails before you send something you'll regret, or checking if your documentation sounds too aggressive.

Time needed: 2-3 hours

Difficulty: Beginner-friendly

What you'll learn: CLI design, API integration, Python packaging

The Vision

$ echo "Per my last email, I've attached the document." | vibe-check

📊 Vibe Analysis
━━━━━━━━━━━━━━━━━━━━━━━━━━
Tone:      😤 Passive-aggressive (87%)
Formality: 🎩 Corporate stiff
Energy:    ⚡ Low-key hostile

💡 Suggested rewrite:
"I've attached the document — let me know if you need anything else!"
Enter fullscreen mode Exit fullscreen mode

Yes. We're building this. Let's go.

Step 1: Project Setup (10 minutes)

Create your project structure:

mkdir vibe-check && cd vibe-check
python -m venv venv
source venv/bin/activate  # or `venv\Scripts\activate` on Windows
pip install openai click rich
Enter fullscreen mode Exit fullscreen mode

We're using:

  • click — Makes CLI tools painless
  • rich — Beautiful terminal output
  • openai — For the AI analysis (works with any OpenAI-compatible API)

Step 2: The Core Analyzer (30 minutes)

Create vibe_check/analyzer.py:

import json
from openai import OpenAI

client = OpenAI()  # Uses OPENAI_API_KEY env var

SYSTEM_PROMPT = """You are a communication tone analyzer. Given text, analyze:

1. tone: The emotional undertone (friendly, neutral, aggressive, passive-aggressive, anxious, confident, etc.)
2. tone_score: Confidence 0-100
3. tone_emoji: Single emoji representing the tone
4. formality: One of: casual, neutral, formal, corporate-stiff
5. formality_emoji: Single emoji for formality
6. energy: The vibe energy (enthusiastic, calm, low-key-hostile, desperate, chill, etc.)
7. energy_emoji: Single emoji for energy
8. suggestions: List of 1-3 brief improvement suggestions (empty if text is fine)
9. rewrite: A better version IF the tone could be improved, otherwise null

Return valid JSON only. No markdown, no explanation."""

def analyze_vibe(text: str) -> dict:
    """Analyze the vibe of given text."""
    response = client.chat.completions.create(
        model="gpt-4o-mini",  # Cheap and fast
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": f"Analyze this text:\n\n{text}"}
        ],
        temperature=0.3,
        max_tokens=500
    )

    result = response.choices[0].message.content
    return json.loads(result)
Enter fullscreen mode Exit fullscreen mode

The magic is in the prompt engineering. We're asking for structured JSON output with specific fields — this gives us predictable data to display beautifully.

Step 3: The Beautiful CLI (45 minutes)

Create vibe_check/cli.py:

import sys
import click
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from .analyzer import analyze_vibe

console = Console()

@click.command()
@click.argument('text', required=False)
@click.option('--file', '-f', type=click.File('r'), help='Read from file')
@click.option('--raw', is_flag=True, help='Output raw JSON')
def main(text, file, raw):
    """Analyze the vibe of any text. 🎯

    Pass text as argument, pipe it in, or use --file.

    Examples:
        vibe-check "Looking forward to our meeting!"
        echo "Per my last email..." | vibe-check
        vibe-check -f email-draft.txt
    """
    # Get input from various sources
    if file:
        content = file.read()
    elif text:
        content = text
    elif not sys.stdin.isatty():
        content = sys.stdin.read()
    else:
        console.print("[red]No input provided![/red] Pass text, use --file, or pipe input.")
        raise SystemExit(1)

    content = content.strip()
    if not content:
        console.print("[red]Empty input![/red]")
        raise SystemExit(1)

    # Analyze
    with console.status("[bold blue]Checking vibes...[/bold blue]"):
        result = analyze_vibe(content)

    if raw:
        import json
        print(json.dumps(result, indent=2))
        return

    # Display results beautifully
    display_results(result)

def display_results(result: dict):
    """Render analysis results with style."""

    # Main metrics table
    table = Table(show_header=False, box=None, padding=(0, 2))
    table.add_column("Label", style="dim")
    table.add_column("Value")

    table.add_row(
        "Tone:",
        f"{result['tone_emoji']} {result['tone'].title()} ({result['tone_score']}%)"
    )
    table.add_row(
        "Formality:",
        f"{result['formality_emoji']} {result['formality'].replace('-', ' ').title()}"
    )
    table.add_row(
        "Energy:",
        f"{result['energy_emoji']} {result['energy'].replace('-', ' ').title()}"
    )

    console.print(Panel(table, title="📊 Vibe Analysis", border_style="blue"))

    # Suggestions
    if result.get('suggestions'):
        suggestions = "\n".join(f"{s}" for s in result['suggestions'])
        console.print(Panel(suggestions, title="💡 Suggestions", border_style="yellow"))

    # Rewrite
    if result.get('rewrite'):
        console.print(Panel(
            result['rewrite'],
            title="✨ Suggested Rewrite",
            border_style="green"
        ))
    else:
        console.print("\n[green]✓ Vibes are good! No changes needed.[/green]")

if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

Step 4: Package It (15 minutes)

Create pyproject.toml:

[project]
name = "vibe-check"
version = "0.1.0"
description = "Check the vibe of any text 🎯"
requires-python = ">=3.9"
dependencies = [
    "openai>=1.0.0",
    "click>=8.0.0",
    "rich>=13.0.0",
]

[project.scripts]
vibe-check = "vibe_check.cli:main"

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
Enter fullscreen mode Exit fullscreen mode

Create vibe_check/__init__.py (empty file), then install:

pip install -e .
Enter fullscreen mode Exit fullscreen mode

Step 5: Take It For a Spin

# The classic passive-aggressive email
$ vibe-check "As I mentioned before, the deadline was yesterday."

# Check your Slack message before sending  
$ echo "Can we talk?" | vibe-check

# Review that PR comment
$ vibe-check "This code is... interesting. Did you test it?"

# Batch check your documentation
$ vibe-check -f README.md
Enter fullscreen mode Exit fullscreen mode

Bonus: Add a "Fix It" Mode (30 minutes)

Want vibe-check to automatically copy the improved version to your clipboard? Add this to your CLI:

@click.option('--fix', is_flag=True, help='Copy improved version to clipboard')

# In main(), after analysis:
if fix and result.get('rewrite'):
    import subprocess
    subprocess.run(['pbcopy'], input=result['rewrite'].encode(), check=True)  # macOS
    # For Linux: subprocess.run(['xclip', '-selection', 'clipboard'], ...)
    console.print("[green]✓ Improved version copied to clipboard![/green]")
Enter fullscreen mode Exit fullscreen mode

Ideas to Extend This Weekend

Once the basics work, consider:

  1. Team calibration mode — Analyze your team's Slack channel and see communication patterns
  2. Git hook integration — Auto-check commit messages and PR descriptions
  3. Browser extension — Check emails before sending (that's a whole other weekend)
  4. Local mode — Swap OpenAI for Ollama and run completely offline

Wrapping Up

In about 2-3 hours, you've built a genuinely useful tool. The combination of Click + Rich makes CLI development delightful, and wrapping an LLM gives you capabilities that would've taken weeks to build with traditional NLP.

The best part? You'll actually use this. Next time you're about to send a message that sounds snippier than intended, pipe it through vibe-check first.

Happy building! 🛠️


What weekend project are you working on? Drop a comment below — I love seeing what people build in their spare time.

Top comments (0)