Codenotary Trustcenter Blog

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

Written by Dennis | Oct 6, 2025 12:36:32 PM

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: 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