• Talk to an expert
  • All posts

    The Vibe Coding Revolution: Setting Up Your AI-Powered Development Environment on Ubuntu

    vibe-coding

    A comprehensive guide to transforming your workflow with Claude Code and the power of CLAUDE.md configuration files

    Introduction: What Is Vibe Coding?

    Six months ago, I was writing code line by line, memorizing syntax, searching documentation for every API call. Today, I describe what I want to build in plain English, and AI assistants transform my intentions into working code. This paradigm shift is called "vibe coding" – and it's revolutionizing how developers and system administrators work.

    Vibe coding isn't about letting AI write all your code. It's about expressing your ideas naturally and having AI handle the implementation details while you focus on architecture, design, and problem-solving. Think of it as having a senior developer who instantly understands your intent and can translate it into any programming language or framework.

    For system administrators and DevOps engineers, vibe coding means no more memorizing complex command-line options, configuration file formats, or API structures. You describe what you want to achieve – "create a secure web server with SSL certificates and monitoring" – and AI generates the exact commands, scripts, and configurations you need.

    Why Ubuntu? The Perfect Foundation for AI-Powered Development

    Ubuntu has emerged as the ideal platform for vibe coding for several compelling reasons:

    1. Native AI Support: Ubuntu offers first-class support for AI frameworks and tools, with most AI development happening on Ubuntu first
    2. Extensive Package Ecosystem: Access to the largest repository of development tools and libraries
    3. Long-Term Stability: LTS versions provide 5 years of updates, perfect for production environments
    4. Community: The largest Linux community means better documentation, faster problem resolution, and more resources
    5. Developer-Friendly: Built-in support for modern development workflows and containerization

    Setting Up Your Ubuntu Environment

    Let's begin by preparing Ubuntu for vibe coding:

    #!/bin/bash
    # vibe-setup.sh - Complete Ubuntu setup for vibe coding
    
    # Update system
    sudo apt update && sudo apt upgrade -y
    
    # Install essential development tools
    sudo apt install -y \
        build-essential \
        curl \
        wget \
        git \
        vim \
        neovim \
        tmux \
        htop \
        jq \
        ripgrep \
        fzf \
        bat \
        exa \
        zsh \
        python3-pip \
        nodejs \
        npm \
        chromium-browser \
        firefox
    
    # Install Docker for containerized development
    curl -fsSL https://get.docker.com | sudo sh
    sudo usermod -aG docker $USER
    
    # Note: Browser automation dependencies are handled by Docker/Playwright MCP
    # No need to install browser-specific libraries on the host system
    
    echo "✅ Base system setup complete!"
    echo "ℹ️  Browser automation will use Docker containers via Playwright MCP"
    

    Terminal Enhancement with Zsh

    Transform your terminal into an AI-friendly command center:

    # Install Oh My Zsh
    sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
    
    # Configure Zsh for vibe coding
    cat >> ~/.zshrc << 'EOF'
    
    # Vibe Coding Configuration
    plugins=(git docker npm python)
    
    # AI Command Aliases
    alias ai="claude"
    alias aic="claude chat"
    alias aihelp="claude help"
    
    # History Configuration for Better Context
    export HISTSIZE=100000
    export SAVEHIST=100000
    setopt EXTENDED_HISTORY
    setopt HIST_FIND_NO_DUPS
    setopt HIST_IGNORE_SPACE
    setopt SHARE_HISTORY
    
    # AI Context Directory
    export AI_CONTEXT_DIR="$HOME/.ai-context"
    mkdir -p $AI_CONTEXT_DIR
    
    # Quick context saving function
    save_context() {
        echo "$(date): $1" >> "$AI_CONTEXT_DIR/context.log"
    }
    
    # Quick note for AI
    ainote() {
        echo "$1" >> "$AI_CONTEXT_DIR/notes.md"
        echo "Note saved for AI context"
    }
    
    # Directory shortcuts
    alias projects="cd ~/projects"
    alias aiconf="cd ~/.claude"
    
    # Git-aware prompt for better context
    export GIT_PS1_SHOWDIRTYSTATE=1
    export GIT_PS1_SHOWUNTRACKEDFILES=1
    
    EOF
    

    claude code

    Claude Code: Your Terminal AI Assistant

    Claude Code brings Anthropic's advanced AI models directly to your command line. It's designed for developers who want to "evolve code at thought speed" – transforming complex workflows into single commands.

    Installation

    Claude Code offers two installation methods. Choose the one that works best for your system:

    # Quick install using the native installer
    curl -fsSL https://claude.ai/install.sh | bash
    
    # Verify installation
    claude --version
    

    Method 2: NPM Install (Requires Node.js 18+)

    # First, ensure Node.js 18+ is installed
    curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
    sudo apt-get install -y nodejs
    
    # Verify Node.js installation
    node --version  # Should show v18 or higher
    npm --version
    
    # Install Claude Code globally via npm
    npm install -g @anthropic-ai/claude-code
    
    # Verify installation
    claude --version
    

    First-Time Setup

    # Start Claude Code in your project directory
    cd my-project
    claude
    
    # If not already logged in, use:
    claude /login
    # This will open your browser for authentication
    

    Project Initialization with Git

    One of the most powerful features of Claude Code is its deep integration with Git. Always start your projects with version control:

    # Create a new project directory
    mkdir my-awesome-project
    cd my-awesome-project
    
    # Initialize Git repository FIRST
    git init
    
    # Start Claude in your project directory
    claude
    
    # Claude will automatically understand your project context
    

    When you start Claude in a Git repository, it automatically:

    • Analyzes your project structure
    • Reads existing code and documentation
    • Understands your technology stack
    • Respects your .gitignore patterns

    Working with Claude Code

    Claude Code operates in several modes:

    # Interactive conversation mode (most common)
    claude
    
    # Execute a specific task and continue conversation
    claude "create a Python web scraper for extracting product prices"
    
    # Quick query mode - run task and exit
    claude -p "explain what this function does"
    
    # Create a Git commit with AI-generated message
    claude commit
    
    # Work with your codebase
    claude "analyze this codebase and suggest improvements"
    
    # Generate tests
    claude "write comprehensive tests for all functions in src/"
    

    Claude Commands

    Key commands you'll use frequently within Claude:

    # Get help and see all available commands
    /help
    
    # Clear conversation history
    /clear
    
    # Login if needed
    /login
    
    # Exit Claude
    /exit
    
    # Tab completion works for commands
    # Type / and press Tab to see available commands
    

    Pro Tips for Claude Code

    1. Be Specific: The more detail you provide, the better the results
    2. Break Complex Tasks: Divide large projects into smaller, manageable steps
    3. Use Tab Completion: Press Tab to autocomplete commands
    4. Explore Capabilities: Ask "What can Claude Code do?" to discover features
    5. Permission-Based: Claude always asks before modifying files

    The Power of CLAUDE.md: Your AI's Knowledge Base

    CLAUDE.md files are the secret weapon of vibe coding. They provide context, preferences, and instructions to AI assistants, transforming generic AI into your personalized coding partner.

    Understanding CLAUDE.md Architecture

    CLAUDE.md files work at multiple levels:

    1. Global (~/.claude/CLAUDE.md): Your personal preferences across all projects
    2. Project (./CLAUDE.md or .claude/README.md): Project-specific context and requirements
    3. Directory (./docs/CLAUDE.md): Subdirectory-specific instructions

    AI assistants read these files hierarchically, with more specific files overriding general ones.

    Creating Your Global CLAUDE.md

    mkdir -p ~/.claude
    cat > ~/.claude/CLAUDE.md << 'EOF'
    # Global AI Assistant Configuration
    
    ## About Me
    I'm a DevOps engineer focused on automation, monitoring, and reliable systems.
    I prefer clear, maintainable code over clever one-liners.
    I work primarily on Ubuntu Linux systems.
    
    ## Coding Philosophy

    while(curious) {
    question everything();
    dig_deeper();
    connect_dots(unexpected);

    if (stuck) {
    keep_thinking();
    }
    }
    ## Coding Preferences ### General Principles - **Clarity over cleverness**: Write code that junior developers can understand - **Explicit over implicit**: Be clear about intentions - **Security first**: Always consider security implications - **Test everything**: Include tests with all code - **Document why, not what**: Comments should explain reasoning - **Git commits**: Use conventional commits (feat:, fix:, docs:, etc.) ### Language Preferences #### Python - Use type hints always - Prefer f-strings for formatting - Use pathlib for file operations - Follow PEP 8 strictly - Use dataclasses for data structures - Virtual environments for all projects ```python # Preferred style example from pathlib import Path from typing import List, Optional from dataclasses import dataclass @dataclass class Config: """Application configuration.""" name: str version: str debug: bool = False def process_files(directory: Path) -> List[str]: """Process all Python files in directory.""" return [f.name for f in directory.glob("*.py")]

    JavaScript/TypeScript

    • Prefer TypeScript over JavaScript
    • Use async/await over promises
    • Functional style preferred
    • Use const by default
    • Destructuring for cleaner code
    // Preferred style
    interface User {
      id: string;
      name: string;
      email: string;
    }
    
    const processUsers = async (users: User[]): Promise<void> => {
      const validUsers = users.filter(({ email }) => email.includes('@'));
      await Promise.all(validUsers.map(saveUser));
    };
    

    Shell Scripting

    • Use bash for scripts, not sh
    • Always use set -euo pipefail
    • Quote all variables
    • Use long options for clarity
    • Add help text
    #!/usr/bin/env bash
    set -euo pipefail
    
    # Script: deploy.sh
    # Purpose: Deploy application to production
    # Usage: ./deploy.sh [environment]
    
    readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    readonly ENVIRONMENT="${1:-staging}"
    
    main() {
        echo "Deploying to ${ENVIRONMENT}..."
        # Deployment logic here
    }
    
    main "$@"
    

    Version Control

    • Always use Git
    • Commit early and often
    • Write meaningful commit messages
    • Never commit secrets or credentials
    • Use .gitignore properly
    • Branch protection for main/master

    Error Handling

    Always include comprehensive error handling:

    • Try/catch blocks in appropriate places
    • Meaningful error messages
    • Proper cleanup on failure
    • Logging for debugging

    Security Practices

    • Never hardcode credentials
    • Always validate input
    • Use environment variables for configuration
    • Implement rate limiting for APIs
    • Enable CORS appropriately
    • Use HTTPS everywhere

    Testing Requirements

    Every piece of code should include:

    • Unit tests for functions
    • Integration tests for APIs
    • Edge case coverage
    • Error condition tests
    • Documentation of test setup

    Project Structure

    Prefer this organization:

    project/
    ├── src/           # Source code
    ├── tests/         # Test files
    ├── docs/          # Documentation
    ├── scripts/       # Utility scripts
    ├── config/        # Configuration files
    ├── .claude/       # Claude-specific configuration
    ├── .github/       # GitHub specific files
    └── README.md      # Project documentation
    

    Response Style

    • Be concise but complete
    • Explain complex concepts simply
    • Provide working examples
    • Suggest alternatives when appropriate
    • Mention potential pitfalls

    Remember: Good code is written for humans to read and machines to execute. EOF

    
    ### Creating Project-Specific Configuration
    
    You can create a `.claude/README.md` file for project-specific instructions that Claude will automatically read:
    
    ```bash
    cat > .claude/README.md << 'EOF'
    # Project: Web Automation Framework
    
    ## Project Overview
    Building a web automation framework for testing and web scraping using Playwright.
    Focus on reliability, maintainability, and ease of use.
    
    ## Technology Stack
    - **Language**: Python 3.11+
    - **Automation**: Playwright
    - **Testing**: Pytest
    - **Data**: Pandas for data processing
    - **Database**: SQLite for local storage
    
    ## Project Structure

    web-automation/
    ├── automation/
    │   ├── core/          # Core automation logic
    │   ├── pages/         # Page object models
    │   ├── workflows/     # Automation workflows
    │   └── utils/         # Utility functions
    ├── tests/
    │   ├── unit/          # Unit tests
    │   ├── integration/   # Integration tests
    │   └── e2e/           # End-to-end tests
    ├── data/
    │   ├── inputs/        # Input data files
    │   └── outputs/       # Generated outputs
    └── .claude/
      └── README.md      # This file

    ## Coding Standards ### Naming Conventions - Classes: PascalCase (e.g., `WebAutomator`) - Functions: snake_case (e.g., `get_page_content`) - Constants: UPPER_SNAKE_CASE (e.g., `MAX_RETRIES`) - Files: snake_case (e.g., `web_scraper.py`) ### Playwright Patterns Always use page object model pattern: ```python from playwright.sync_api import Page from typing import Optional class LoginPage: """Page object for login functionality.""" def __init__(self, page: Page): self.page = page self.username_input = page.locator("#username") self.password_input = page.locator("#password") self.login_button = page.locator("button[type='submit']") self.error_message = page.locator(".error-message") def login(self, username: str, password: str) -> None: """Perform login action.""" self.username_input.fill(username) self.password_input.fill(password) self.login_button.click() def get_error_message(self) -> Optional[str]: """Get error message if present.""" if self.error_message.is_visible(): return self.error_message.text_content() return None

    Git Workflow

    • Feature branches from main
    • Pull requests for all changes
    • Code review required
    • Squash and merge strategy
    • Semantic versioning for releases

    Testing Requirements

    • Minimum 80% code coverage
    • All functions must have tests
    • E2E tests for critical paths
    • Mock external dependencies
    • Use pytest fixtures

    Documentation Standards

    • Docstrings for all public functions
    • README.md in each major directory
    • Examples for complex features
    • API documentation if applicable
    • Change log for versions

    Remember: Always prioritize reliability over speed in web automation. EOF

    
    ## MCP for Playwright: Browser Automation Integration
    
    Model Context Protocol (MCP) extends Claude's capabilities by allowing direct interaction with tools. 
    For web automation, the Playwright MCP server enables Claude to control browsers directly. ### Setting Up Playwright MCP There are two ways to configure MCP: system-wide or project-specific.
    We recommend project-specific configuration for better isolation. #### Project-Specific MCP Configuration (Recommended) ```bash # In your project directory cd my-project # Initialize git if not already done git init # Add Playwright MCP to this project claude mcp add playwright npx '@playwright/mcp@latest' # This creates/updates .mcp.json in your project

    The .mcp.json file in your project root will look like this:

    {
      "mcpServers": {
        "playwright": {
          "command": "npx",
          "args": ["@playwright/mcp@latest"],
          "env": {}
        }
      }
    }
    

    Benefits of Project-Specific MCP

    1. Isolation: Each project has its own MCP configuration
    2. Version Control: .mcp.json can be committed to Git
    3. Team Collaboration: Everyone gets the same MCP setup
    4. No Global Pollution: Keeps your system clean

    Using Playwright MCP with Claude

    Once configured, you can use natural language to control browsers:

    # Start Claude in your project directory
    claude
    
    # Use Playwright MCP
    > Use playwright mcp to open a browser to example.com
    
    # Take screenshots
    > Take a screenshot of the current page
    
    # Fill forms
    > Fill out the login form with username "test" and password "demo"
    
    # Extract data
    > Extract all the product names and prices from this page
    
    # Navigate
    > Click on the "Next" button and wait for the page to load
    

    Advanced Playwright MCP Usage

    When using Playwright MCP, be explicit initially:

    # First time in a session
    > Use playwright mcp to navigate to github.com
    
    # After that, Claude remembers the context
    > Search for "vibe coding"
    > Click on the first result
    > Take a screenshot
    

    Authentication Tip

    When you need to log into a site:

    > Use playwright mcp to open linkedin.com
    > Please wait while I log in manually
    # Log in manually in the browser window
    > Great! Now navigate to my profile page
    

    The browser will remember cookies for the session, making subsequent interactions seamless.

    Creating a Custom MCP Configuration

    You can extend the basic Playwright MCP configuration:

    {
      "mcpServers": {
        "playwright": {
          "command": "npx",
          "args": ["@playwright/mcp@latest"],
          "env": {
            "HEADLESS": "false",
            "DEFAULT_TIMEOUT": "30000",
            "BROWSER": "chromium"
          }
        },
        "filesystem": {
          "command": "npx",
          "args": ["@modelcontextprotocol/server-filesystem", "./"],
          "env": {}
        }
      }
    }
    

    Best Practices for Vibe Coding

    1. Always Start with Version Control

    # Right way
    git init
    claude /init
    
    # Wrong way
    claude /init  # Without git
    

    2. Be Specific in Your Requests

    # Good
    > Create a Python function that validates email addresses using regex, 
    > handles common edge cases, and includes comprehensive tests
    
    # Too vague
    > Make an email validator
    

    3. Iterate and Refine

    # First iteration
    > Create a basic web scraper
    
    # Refine
    > Add error handling and retry logic
    
    # Enhance
    > Add logging and progress indicators
    
    # Polish  
    > Add type hints and comprehensive documentation
    

    4. Use MCP for Complex Tasks

    # For browser automation
    > Use playwright mcp to automate the login process
    
    # For file operations
    > Read all CSV files in the data directory and combine them
    

    5. Maintain Context with CLAUDE.md

    Keep your CLAUDE.md files updated with:

    • Current project goals
    • Technical constraints
    • Coding standards
    • Team conventions
    • Security requirements

    Security Considerations

    Never Commit Secrets

    # .gitignore should include
    .env
    *.key
    *.pem
    secrets/
    credentials.json
    

    Use Environment Variables

    import os
    from dotenv import load_dotenv
    
    load_dotenv()
    
    API_KEY = os.getenv('API_KEY')
    DATABASE_URL = os.getenv('DATABASE_URL')
    

    Validate AI-Generated Code

    Always review AI-generated code for:

    • Security vulnerabilities
    • Hardcoded credentials
    • Unsafe operations
    • Input validation
    • Error handling

    Conclusion: The Future Is Natural

    Vibe coding represents a fundamental shift in how we create software. By expressing our intentions naturally and letting AI handle implementation details, we can focus on what truly matters: solving problems, creating value, and building amazing things.

    The tools and techniques in this guide are just the beginning. As AI models become more capable and our understanding of effective prompting deepens, the possibilities are limitless. The key is to start now, experiment freely, and find the patterns that work best for your workflow.

    Remember: Vibe coding isn't about replacing your skills – it's about amplifying them. You still need to understand what good code looks like, what secure systems require, and what users need. AI is your implementation partner, not your replacement.

    Start with simple tasks. Generate a function. Create a test. Build a script. As you gain confidence, tackle larger projects. Before long, you'll wonder how you ever coded without AI assistance.

    Welcome to the vibe coding revolution. The future of development is here, and it speaks your language.


    This guide is part of the Vibe Coding series. Share your experiences and connect with the community.

    Resources:

    Version: 1.0.0
    Last Updated: January 2025
    License: MIT