Creating a Developer CLI Tool using AI

Hướng dẫn chi tiết về Creating a Developer CLI Tool using AI trong Vibe Coding dành cho None.

Building internal tools has traditionally been the “forgotten” task of the software engineering cycle. We all have those repetitive terminal workflows—grepping through logs, formatting complex JSON, or orchestrating multi-step Git operations—that we promise to automate “someday.” In the world of Vibe Coding, “someday” is a legacy concept.

Vibe Coding is about collapsing the distance between a technical intuition and a functional implementation. When you’re in the flow, you shouldn’t be stalled by the boilerplate of argument parsing or the nuances of regex. This article explores how to use AI as your primary architect to build sophisticated, production-grade CLI tools that solve real-world development friction. We aren’t just writing scripts; we are building intelligent companions for your terminal.

The Problem: The Automation Tax

Every developer faces the “Automation Tax.” You realize a task takes 10 minutes and you do it three times a week. Automating it would take four hours. You do the math, decide the ROI isn’t there, and continue suffering.

The Vibe Coding approach changes this equation. By leveraging AI to handle the “plumbing”—parsing CLI arguments, managing environment variables, and interfacing with APIs—the cost of automation drops by 90%. You can now justify building a custom tool for a task that only saves you five minutes a day. Over a year, that is 20 hours of reclaimed cognitive load.

Core Concepts: The Anatomy of an AI-Powered CLI

To build an effective CLI tool using AI, you need to understand the shift from deterministic logic to semantic logic.

1. The LLM as the “Router”

Traditional CLIs rely on rigid if/else blocks or switch statements. An AI-powered CLI uses the Large Language Model (LLM) to interpret intent. Instead of remembering --force --recursive --exclude-dir=node_modules, you want a tool that understands clean up my workspace but keep the dependencies.

2. The Context Injection Pattern

A CLI tool is only as good as the data it can see. In Vibe Coding, your CLI acts as a bridge between your local file system and the LLM’s reasoning. The “Context Injection Pattern” involves:

  • Discovery: Programmatically gathering file contents, git diffs, or terminal outputs.
  • Packaging: Formatting this data into a structured prompt (often Markdown or JSON).
  • Inference: Sending it to an LLM (Claude, GPT-4o) for processing.
  • Action: Converting the LLM’s text output back into system commands (writing files, running shell scripts).

3. The “Human-in-the-Loop” Gate

Because AI is stochastic, intermediate-level CLI tools must include a verification gate. Never allow an AI-generated command to run rm -rf without a confirmation prompt. We use libraries like Inquirer.js or Python’s Rich to present the AI’s “plan” before execution.


Practical Example: Building “Vibe-Commit”

Let’s build a tool called vibe-commit. Its job is to read your staged changes, analyze the “vibe” of your work, and generate a perfectly formatted Conventional Commit message.

Step 1: Choosing the Stack

For speed and AI-friendliness, we will use Python with the click library for CLI structure and instructor for structured LLM outputs.

Why this stack?

  • Click: Handles arguments and help text with zero friction.
  • Instructor: Forces the LLM to return data in a specific Pydantic model (no more “Here is your commit message” conversational filler).

Step 2: Defining the Schema

First, we define what a “Commit” looks like to our tool.

from pydantic import BaseModel, Field
from typing import Optional

class CommitMessage(BaseModel):
    type: str = Field(..., description="feat, fix, docs, style, refactor, etc.")
    scope: Optional[str] = Field(None, description="The module affected")
    subject: str = Field(..., description="Short imperative summary")
    body: str = Field(..., description="Detailed explanation of changes")

Step 3: Implementing the Logic

The core of the tool is fetching the git diff and passing it to the model.

import subprocess
import click
import instructor
from anthropic import Anthropic

def get_git_diff():
    # Fetch staged changes
    return subprocess.check_output(["git", "diff", "--staged"]).decode("utf-8")

@click.command()
@click.option('--model', default="claude-3-5-sonnet-20241022")
def main(model):
    diff = get_git_diff()
    if not diff:
        click.echo("No staged changes found!")
        return

    client = instructor.from_anthropic(Anthropic())
    
    # The 'Vibe' prompt
    commit = client.messages.create(
        model=model,
        max_tokens=1024,
        response_model=CommitMessage,
        messages=[
            {"role": "system", "content": "You are a senior engineer. Analyze the git diff and generate a commit message."},
            {"role": "user", "content": diff}
        ]
    )

    # UI Feedback
    click.secho(f"\n[{commit.type}{'(' + commit.scope + ')' if commit.scope else ''}]: {commit.subject}", fg="green", bold=True)
    click.echo(f"\n{commit.body}")
    
    if click.confirm("\nDo you want to commit with this message?"):
        full_msg = f"{commit.type}{'(' + commit.scope + ')' if commit.scope else ''}: {commit.subject}\n\n{commit.body}"
        subprocess.run(["git", "commit", "-m", full_msg])

Step 4: The Vibe Coding Edge

To make this truly a “Vibe” tool, we add a “Style” parameter. Maybe today you want your commits to be “professional,” but tomorrow you want them to be “playful” or “extremely technical.” By adding a simple flag that adjusts the system prompt, you’ve moved from a static script to a personalized agent.


Best Practices & Professional Tips

Building a CLI tool is easy; building one that doesn’t break your workflow is hard. Here are the intermediate-level standards you should follow.

1. Robust Error Handling (The “AI-is-Down” Scenario)

Your CLI should never crash if the API is unreachable. Wrap your LLM calls in try-except blocks. If the AI fails, fall back to a standard git commit prompt. Vibe Tip: Implement a local “cache” for your context. If you’re building a tool that analyzes logs, don’t re-upload the same 10MB of logs every time. Hash the file and only send the “new” vibes.

2. Secret Hygiene

Never hardcode your API keys. Use python-dotenv or fetch directly from your shell environment. When distributing your tool to your team, ensure you have a setup command that guides the user through adding their ANTHROPIC_API_KEY.

3. Handling Large Contexts (The Token Strategy)

Git diffs can be massive. If you try to send a 50,000-line diff to an LLM, you’ll hit token limits and spend $5 on a single commit message. Strategy:

  • Summarize first: If the diff is > 10KB, use a regex to pull out only the function signatures and changed line numbers.
  • File filtering: Exclude package-lock.json, pnpm-lock.yaml, or image assets from the context.

4. Interactive UX

Command-line tools are interfaces. Even if there’s no “button,” the experience matters.

  • Use Spinners: Use the rich library to show a “Thinking…” spinner while the LLM is processing. Silence in the terminal feels like a hang.
  • Color Coding: Use green for success, yellow for AI-suggested changes, and red for system errors.
  • Streaming: If you are generating a long documentation file, stream the response to the terminal so the user can start reading immediately.

Solving Real Problems in Vibe Coding

How exactly does this fit into the Todyle/Cody Master ecosystem?

In a Vibe Coding workflow, you are often managing multiple “Tracks” or “Phases” of development. A common pain point is “Context Drift”—forgetting which files were changed for which feature.

You can build a CLI tool that:

  1. Scans your active Track: Reads your plan.md or todo.md.
  2. Analyzes your workspace: Sees which files deviate from the plan.
  3. Generates an “Alignment Report”: “Hey, you’re working on the API auth, but you just modified the CSS for the footer. Is that intentional?”

This type of tool acts as an automated project manager. It doesn’t write the code; it ensures the coder stays in the vibe of the current objective.

Conclusion: From User to Architect

Creating your own CLI tools using AI is the ultimate expression of developer autonomy. You no longer have to wait for a third-party extension or a platform update to solve your specific workflow hurdles.

The transition from a “User” (someone who uses Git, Grep, and Awk) to an “Architect” (someone who builds vibe-git, vibe-logs, and vibe-deploy) is the hallmark of an intermediate Vibe Coder. You are building a customized operating system for your own brain.

Start small. Find one task you do every day that involves more than three terminal commands. Use the patterns above—Schema definition, Context Injection, and Human-in-the-Loop verification—to build your first companion. The terminal is no longer just a place to run commands; it is the canvas where your AI agents live. Go build the vibe you want to work in.