| # Learning Path: Building AI-Powered CLI Tools with Python | |
| A structured learning path for developers with basic Python knowledge who want to build AI-powered CLI tools using modern development practices. | |
| ## π― Prerequisites | |
| **What You Should Know:** | |
| - Basic Python syntax (variables, functions, loops, conditionals) | |
| - How to run Python scripts from the command line | |
| - Basic understanding of files and directories | |
| - Familiarity with text editors or IDEs | |
| **What You'll Learn:** | |
| - Building professional CLI applications | |
| - Integrating AI/LLM capabilities | |
| - Modern Python package management with pixi | |
| - AI-assisted development with GitHub Copilot | |
| - Package publishing and distribution | |
| --- | |
| ## π Learning Phases | |
| ### Phase 1: Foundation Setup (Week 1) | |
| #### 1.1 Development Environment Setup | |
| **Install Required Tools:** | |
| ```bash | |
| # Install pixi (cross-platform package manager) | |
| curl -fsSL https://pixi.sh/install.sh | bash | |
| # Verify installation | |
| pixi --version | |
| # Install Git (if not already installed) | |
| # Linux: sudo apt install git | |
| # macOS: brew install git | |
| # Windows: Download from git-scm.com | |
| ``` | |
| **Set Up GitHub Copilot:** | |
| 1. Install VS Code or your preferred IDE | |
| 2. Install GitHub Copilot extension | |
| 3. Sign in with your GitHub account (requires Copilot subscription) | |
| 4. Complete the Copilot quickstart tutorial | |
| **Resources:** | |
| - [Pixi Documentation](https://pixi.sh/latest/) | |
| - [GitHub Copilot Getting Started](https://docs.github.com/en/copilot/getting-started-with-github-copilot) | |
| - [VS Code Python Setup](https://code.visualstudio.com/docs/python/python-tutorial) | |
| #### 1.2 Understanding Modern Python Project Structure | |
| **Learn About:** | |
| - Project organization (src layout vs flat layout) | |
| - Virtual environments and dependency isolation | |
| - Configuration files (`pyproject.toml`, `pixi.toml`) | |
| - Version control with Git | |
| **Hands-On Exercise:** | |
| Create a simple "Hello World" project with pixi: | |
| ```bash | |
| # Create new project | |
| pixi init my-first-cli | |
| cd my-first-cli | |
| # Add Python dependency | |
| pixi add python | |
| # Create a simple script | |
| mkdir src | |
| echo 'print("Hello from pixi!")' > src/hello.py | |
| # Run it | |
| pixi run python src/hello.py | |
| ``` | |
| **Use Copilot to:** | |
| - Generate a `.gitignore` file for Python projects | |
| - Create a basic `README.md` template | |
| - Write docstrings for your functions | |
| --- | |
| ### Phase 2: CLI Development Fundamentals (Week 2-3) | |
| #### 2.1 Building Your First CLI with Typer | |
| **Learning Objectives:** | |
| - Understand command-line argument parsing with type hints | |
| - Create commands, options, and flags using Python types | |
| - Handle user input and validation | |
| - Display formatted output with Rich integration | |
| **Project: Simple File Organizer CLI** | |
| > **Note**: This is a simplified version for learning CLI basics. For a comprehensive, production-ready example that integrates Docker AI, MCP servers, and multi-agent systems, see the [FileOrganizer project](projects/FileOrganizer.md) in Phase 7. | |
| ```bash | |
| # Initialize project with pixi | |
| pixi init file-organizer-cli | |
| cd file-organizer-cli | |
| # Add dependencies | |
| pixi add python typer rich | |
| # Create project structure | |
| mkdir -p src/file_organizer | |
| touch src/file_organizer/__init__.py | |
| touch src/file_organizer/cli.py | |
| ``` | |
| **Example CLI Structure (use Copilot to help generate):** | |
| ```python | |
| # src/file_organizer/cli.py | |
| import typer | |
| from pathlib import Path | |
| from rich.console import Console | |
| from typing import Optional | |
| app = typer.Typer(help="File organizer CLI tool") | |
| console = Console() | |
| @app.command() | |
| def organize( | |
| directory: Path = typer.Argument(..., help="Directory to organize", exists=True), | |
| dry_run: bool = typer.Option(False, "--dry-run", help="Preview changes without executing"), | |
| verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed output") | |
| ): | |
| """Organize files in DIRECTORY by extension.""" | |
| if verbose: | |
| console.print(f"[blue]Organizing files in: {directory}[/blue]") | |
| # Use Copilot to generate the organization logic | |
| if dry_run: | |
| console.print("[yellow]DRY RUN - No changes will be made[/yellow]") | |
| pass | |
| @app.command() | |
| def stats(directory: Path = typer.Argument(..., exists=True)): | |
| """Show statistics about files in DIRECTORY.""" | |
| # Use Copilot to generate statistics logic | |
| pass | |
| if __name__ == '__main__': | |
| app() | |
| ``` | |
| **Copilot Prompts to Try:** | |
| - "Create a function to organize files by extension using pathlib" | |
| - "Add error handling for file operations with try-except" | |
| - "Generate help text and docstrings for CLI commands" | |
| - "Add progress bar using rich library for file processing" | |
| **Resources:** | |
| - [Typer Documentation](https://typer.tiangolo.com/) | |
| - [Typer Tutorial](https://typer.tiangolo.com/tutorial/) | |
| - [Rich Documentation](https://rich.readthedocs.io/) | |
| #### 2.2 Configuration and Settings Management | |
| **Learn About:** | |
| - Reading configuration files (YAML, TOML, JSON) | |
| - Environment variables | |
| - User preferences and defaults | |
| - Configuration validation with Pydantic | |
| **Add to Your Project:** | |
| ```bash | |
| # Add configuration dependencies | |
| pixi add pydantic pyyaml python-dotenv | |
| ``` | |
| **Use Copilot to Generate:** | |
| - Configuration schema with Pydantic | |
| - Config file loader functions | |
| - Environment variable handling | |
| --- | |
| ### Phase 3: AI Integration Basics (Week 4-5) | |
| #### 3.1 Understanding HuggingFace and LLM APIs | |
| **Learning Objectives:** | |
| - API authentication and token management | |
| - Using HuggingFace Inference API and local models | |
| - Making API requests with transformers and huggingface_hub | |
| - Handling streaming responses | |
| - Error handling and rate limiting | |
| **Project: Add AI Capabilities to Your CLI** | |
| ```bash | |
| # Add AI dependencies | |
| pixi add transformers huggingface-hub python-dotenv | |
| # For local inference (optional) | |
| pixi add torch | |
| # Create .env file for API keys | |
| echo "HUGGINGFACE_TOKEN=your-token-here" > .env | |
| echo ".env" >> .gitignore | |
| ``` | |
| **Simple AI Integration Example:** | |
| ```python | |
| # src/file_organizer/ai_helper.py | |
| from huggingface_hub import InferenceClient | |
| import os | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| def suggest_organization_strategy(file_list: list[str]) -> str: | |
| """Use AI to suggest file organization strategy.""" | |
| client = InferenceClient(token=os.getenv("HUGGINGFACE_TOKEN")) | |
| prompt = f"""Given these files: {', '.join(file_list)} | |
| Suggest an intelligent organization strategy. Group related files and explain your reasoning. | |
| Respond in JSON format.""" | |
| # Use a free model like Mistral or Llama | |
| response = client.text_generation( | |
| prompt, | |
| model="mistralai/Mistral-7B-Instruct-v0.2", | |
| max_new_tokens=500, | |
| temperature=0.7 | |
| ) | |
| return response | |
| # Alternative: Using local models with transformers | |
| from transformers import pipeline | |
| def analyze_file_content_local(content: str) -> str: | |
| """Analyze file content using a local model.""" | |
| # Use Copilot to complete this function | |
| # Prompt: "Create a function that uses a local HuggingFace model | |
| # to analyze and categorize file content" | |
| classifier = pipeline( | |
| "text-classification", | |
| model="distilbert-base-uncased-finetuned-sst-2-english" | |
| ) | |
| result = classifier(content[:512]) # Truncate for model limits | |
| return result | |
| ``` | |
| **Copilot Exercises:** | |
| - "Create a function to summarize file contents using HuggingFace models" | |
| - "Add retry logic for API failures with exponential backoff" | |
| - "Implement streaming response handler for long-form generation" | |
| - "Create a model selector that chooses between local and API inference" | |
| **Resources:** | |
| - [HuggingFace Hub Documentation](https://huggingface.co/docs/huggingface_hub/) | |
| - [Transformers Documentation](https://huggingface.co/docs/transformers/) | |
| - [HuggingFace Inference API](https://huggingface.co/docs/api-inference/) | |
| - [Free Models on HuggingFace](https://huggingface.co/models) | |
| **Popular Models to Try:** | |
| - **Text Generation**: `mistralai/Mistral-7B-Instruct-v0.2`, `meta-llama/Llama-2-7b-chat-hf` | |
| - **Summarization**: `facebook/bart-large-cnn`, `google/pegasus-xsum` | |
| - **Classification**: `distilbert-base-uncased`, `roberta-base` | |
| - **Embeddings**: `sentence-transformers/all-MiniLM-L6-v2` | |
| **Local vs API Inference:** | |
| ```python | |
| # src/file_organizer/inference.py | |
| from typing import Literal | |
| import os | |
| class AIHelper: | |
| """Flexible AI helper supporting both local and API inference.""" | |
| def __init__(self, mode: Literal["local", "api"] = "api"): | |
| self.mode = mode | |
| if mode == "api": | |
| from huggingface_hub import InferenceClient | |
| self.client = InferenceClient(token=os.getenv("HUGGINGFACE_TOKEN")) | |
| else: | |
| from transformers import pipeline | |
| # Load model once at initialization | |
| self.pipeline = pipeline( | |
| "text-generation", | |
| model="distilgpt2", # Smaller model for local use | |
| device=-1 # CPU, use 0 for GPU | |
| ) | |
| def generate(self, prompt: str) -> str: | |
| """Generate text using configured mode.""" | |
| if self.mode == "api": | |
| return self.client.text_generation( | |
| prompt, | |
| model="mistralai/Mistral-7B-Instruct-v0.2", | |
| max_new_tokens=500 | |
| ) | |
| else: | |
| result = self.pipeline(prompt, max_new_tokens=100) | |
| return result[0]['generated_text'] | |
| # Usage in CLI | |
| # Use Copilot: "Add a --local flag to switch between API and local inference" | |
| ``` | |
| **When to Use Each:** | |
| - **API Inference**: Better quality, larger models, no local resources needed, requires internet | |
| - **Local Inference**: Privacy, offline use, no API costs, but requires more RAM/GPU | |
| - **vLLM Server**: Best of both worlds - local privacy with high performance and OpenAI-compatible API | |
| **Advanced: Serving Local Models with vLLM** | |
| vLLM is a high-performance inference engine that can serve local models with significantly better throughput and lower latency than standard transformers. | |
| ```bash | |
| # Install vLLM (requires GPU for best performance) | |
| pixi add vllm | |
| # Or install with specific CUDA version | |
| pixi add "vllm[cuda12]" | |
| ``` | |
| **Starting a vLLM Server:** | |
| ```bash | |
| # Start vLLM server with a model | |
| # This creates an OpenAI-compatible API endpoint | |
| vllm serve mistralai/Mistral-7B-Instruct-v0.2 \ | |
| --host 0.0.0.0 \ | |
| --port 8000 \ | |
| --max-model-len 4096 | |
| # For smaller GPUs, use quantized models | |
| vllm serve TheBloke/Mistral-7B-Instruct-v0.2-GPTQ \ | |
| --quantization gptq \ | |
| --dtype half | |
| ``` | |
| **Using vLLM Server in Your CLI:** | |
| ```python | |
| # src/file_organizer/vllm_client.py | |
| from openai import OpenAI | |
| from typing import Optional | |
| class vLLMClient: | |
| """Client for vLLM server with OpenAI-compatible API.""" | |
| def __init__(self, base_url: str = "http://localhost:8000/v1"): | |
| # vLLM provides OpenAI-compatible endpoints | |
| self.client = OpenAI( | |
| base_url=base_url, | |
| api_key="not-needed" # vLLM doesn't require API key | |
| ) | |
| def generate( | |
| self, | |
| prompt: str, | |
| model: str = "mistralai/Mistral-7B-Instruct-v0.2", | |
| max_tokens: int = 500, | |
| temperature: float = 0.7 | |
| ) -> str: | |
| """Generate text using vLLM server.""" | |
| response = self.client.completions.create( | |
| model=model, | |
| prompt=prompt, | |
| max_tokens=max_tokens, | |
| temperature=temperature | |
| ) | |
| return response.choices[0].text | |
| def chat_generate( | |
| self, | |
| messages: list[dict], | |
| model: str = "mistralai/Mistral-7B-Instruct-v0.2", | |
| max_tokens: int = 500 | |
| ) -> str: | |
| """Generate using chat completion format.""" | |
| response = self.client.chat.completions.create( | |
| model=model, | |
| messages=messages, | |
| max_tokens=max_tokens | |
| ) | |
| return response.choices[0].message.content | |
| # Usage in your CLI | |
| def suggest_organization_with_vllm(file_list: list[str]) -> str: | |
| """Use local vLLM server for suggestions.""" | |
| client = vLLMClient() | |
| messages = [ | |
| {"role": "system", "content": "You are a file organization assistant."}, | |
| {"role": "user", "content": f"Organize these files: {', '.join(file_list)}"} | |
| ] | |
| return client.chat_generate(messages) | |
| ``` | |
| **Complete Inference Strategy:** | |
| ```python | |
| # src/file_organizer/ai_strategy.py | |
| from typing import Literal | |
| import os | |
| from enum import Enum | |
| class InferenceMode(str, Enum): | |
| """Available inference modes.""" | |
| API = "api" # HuggingFace Inference API | |
| LOCAL = "local" # Direct transformers | |
| VLLM = "vllm" # vLLM server | |
| AUTO = "auto" # Auto-detect best option | |
| class UnifiedAIClient: | |
| """Unified client supporting multiple inference backends.""" | |
| def __init__(self, mode: InferenceMode = InferenceMode.AUTO): | |
| self.mode = self._resolve_mode(mode) | |
| self._setup_client() | |
| def _resolve_mode(self, mode: InferenceMode) -> InferenceMode: | |
| """Auto-detect best available mode.""" | |
| if mode != InferenceMode.AUTO: | |
| return mode | |
| # Check if vLLM server is running | |
| try: | |
| import requests | |
| requests.get("http://localhost:8000/health", timeout=1) | |
| return InferenceMode.VLLM | |
| except: | |
| pass | |
| # Check if HuggingFace token is available | |
| if os.getenv("HUGGINGFACE_TOKEN"): | |
| return InferenceMode.API | |
| # Fall back to local | |
| return InferenceMode.LOCAL | |
| def _setup_client(self): | |
| """Initialize the appropriate client.""" | |
| if self.mode == InferenceMode.VLLM: | |
| from openai import OpenAI | |
| self.client = OpenAI( | |
| base_url="http://localhost:8000/v1", | |
| api_key="not-needed" | |
| ) | |
| elif self.mode == InferenceMode.API: | |
| from huggingface_hub import InferenceClient | |
| self.client = InferenceClient(token=os.getenv("HUGGINGFACE_TOKEN")) | |
| else: # LOCAL | |
| from transformers import pipeline | |
| self.client = pipeline("text-generation", model="distilgpt2") | |
| def generate(self, prompt: str, **kwargs) -> str: | |
| """Generate text using configured backend.""" | |
| if self.mode == InferenceMode.VLLM: | |
| response = self.client.completions.create( | |
| model="mistralai/Mistral-7B-Instruct-v0.2", | |
| prompt=prompt, | |
| max_tokens=kwargs.get("max_tokens", 500) | |
| ) | |
| return response.choices[0].text | |
| elif self.mode == InferenceMode.API: | |
| return self.client.text_generation( | |
| prompt, | |
| model="mistralai/Mistral-7B-Instruct-v0.2", | |
| max_new_tokens=kwargs.get("max_tokens", 500) | |
| ) | |
| else: # LOCAL | |
| result = self.client(prompt, max_new_tokens=kwargs.get("max_tokens", 100)) | |
| return result[0]['generated_text'] | |
| # Use in CLI with Typer | |
| import typer | |
| @app.command() | |
| def organize( | |
| directory: Path, | |
| inference_mode: InferenceMode = typer.Option( | |
| InferenceMode.AUTO, | |
| "--mode", | |
| help="Inference mode: api, local, vllm, or auto" | |
| ) | |
| ): | |
| """Organize files using AI.""" | |
| ai_client = UnifiedAIClient(mode=inference_mode) | |
| # Use ai_client.generate() for suggestions | |
| ``` | |
| **vLLM Performance Tips:** | |
| 1. **GPU Memory**: Use `--gpu-memory-utilization 0.9` to maximize GPU usage | |
| 2. **Batch Size**: vLLM automatically batches requests for better throughput | |
| 3. **Quantization**: Use GPTQ or AWQ quantized models for lower memory usage | |
| 4. **Tensor Parallelism**: For multi-GPU: `--tensor-parallel-size 2` | |
| **Docker Compose for vLLM (Optional):** | |
| ```yaml | |
| # docker-compose.vllm.yml | |
| version: '3.8' | |
| services: | |
| vllm: | |
| image: vllm/vllm-openai:latest | |
| ports: | |
| - "8000:8000" | |
| environment: | |
| - MODEL=mistralai/Mistral-7B-Instruct-v0.2 | |
| - MAX_MODEL_LEN=4096 | |
| deploy: | |
| resources: | |
| reservations: | |
| devices: | |
| - driver: nvidia | |
| count: 1 | |
| capabilities: [gpu] | |
| command: > | |
| --host 0.0.0.0 | |
| --port 8000 | |
| --model ${MODEL} | |
| --max-model-len ${MAX_MODEL_LEN} | |
| ``` | |
| **Comparison:** | |
| | Feature | HF API | Transformers | vLLM | | |
| |---------|--------|--------------|------| | |
| | Setup | Easy | Easy | Medium | | |
| | Speed | Fast | Slow | Very Fast | | |
| | Cost | Pay per use | Free | Free (local) | | |
| | GPU Required | No | Optional | Recommended | | |
| | Offline | No | Yes | Yes | | |
| | Batch Processing | Limited | Poor | Excellent | | |
| | Memory Efficient | N/A | No | Yes | | |
| | OpenAI Compatible | No | No | Yes | | |
| **Recommended Workflow:** | |
| 1. **Development**: Use HuggingFace API for quick prototyping | |
| 2. **Testing**: Use vLLM locally for faster iteration | |
| 3. **Production**: Deploy vLLM server for best performance and privacy | |
| #### 3.2 Docker-Based Model Deployment | |
| Docker provides a modern, standardized way to deploy local LLM models with minimal configuration using Docker Compose v2.38+. | |
| **Why Use Docker for AI Models?** | |
| - **Consistent environments**: Same setup across development, testing, and production | |
| - **Easy deployment**: One command to start models and services | |
| - **Resource isolation**: Models run in containers with defined resource limits | |
| - **Portability**: Works locally with Docker Model Runner or on cloud providers | |
| - **Version control**: Pin specific model versions with OCI artifacts | |
| **Prerequisites:** | |
| ```bash | |
| # Ensure Docker Compose v2.38 or later | |
| docker compose version | |
| # Enable Docker Model Runner in Docker Desktop settings | |
| # Or install separately: https://docs.docker.com/ai/model-runner/ | |
| ``` | |
| **Basic Model Deployment with Docker Compose:** | |
| Create a `docker-compose.yml` for your CLI project: | |
| ```yaml | |
| # docker-compose.yml | |
| services: | |
| # Your CLI application | |
| file-organizer: | |
| build: . | |
| models: | |
| - llm # Reference to the model defined below | |
| environment: | |
| # Auto-injected by Docker: | |
| # LLM_URL - endpoint to access the model | |
| # LLM_MODEL - model identifier | |
| volumes: | |
| - ./data:/app/data | |
| models: | |
| llm: | |
| model: ai/smollm2 # Model from Docker Hub | |
| context_size: 4096 | |
| runtime_flags: | |
| - "--verbose" | |
| - "--log-colors" | |
| ``` | |
| **Using Models in Your Python CLI:** | |
| ```python | |
| # src/file_organizer/docker_ai.py | |
| import os | |
| from openai import OpenAI | |
| class DockerModelClient: | |
| """Client for Docker-deployed models with OpenAI-compatible API.""" | |
| def __init__(self): | |
| # Docker automatically injects these environment variables | |
| model_url = os.getenv("LLM_URL") | |
| model_name = os.getenv("LLM_MODEL") | |
| if not model_url: | |
| raise ValueError("LLM_URL not set. Are you running with Docker Compose?") | |
| # Docker models provide OpenAI-compatible endpoints | |
| self.client = OpenAI( | |
| base_url=model_url, | |
| api_key="not-needed" # Docker models don't require API keys | |
| ) | |
| self.model_name = model_name | |
| def generate(self, prompt: str, max_tokens: int = 500) -> str: | |
| """Generate text using Docker-deployed model.""" | |
| response = self.client.completions.create( | |
| model=self.model_name, | |
| prompt=prompt, | |
| max_tokens=max_tokens, | |
| temperature=0.7 | |
| ) | |
| return response.choices[0].text | |
| def chat_generate(self, messages: list[dict], max_tokens: int = 500) -> str: | |
| """Generate using chat completion format.""" | |
| response = self.client.chat.completions.create( | |
| model=self.model_name, | |
| messages=messages, | |
| max_tokens=max_tokens | |
| ) | |
| return response.choices[0].message.content | |
| # Usage in your CLI | |
| import typer | |
| @app.command() | |
| def organize(directory: Path): | |
| """Organize files using Docker-deployed AI model.""" | |
| try: | |
| ai_client = DockerModelClient() | |
| # Use the model for suggestions | |
| suggestion = ai_client.generate(f"Organize these files: {list(directory.iterdir())}") | |
| console.print(suggestion) | |
| except ValueError as e: | |
| console.print(f"[red]Error: {e}[/red]") | |
| console.print("[yellow]Run with: docker compose up[/yellow]") | |
| ``` | |
| **Multi-Model Setup:** | |
| Deploy multiple models for different tasks: | |
| ```yaml | |
| services: | |
| file-organizer: | |
| build: . | |
| models: | |
| chat-model: | |
| endpoint_var: CHAT_MODEL_URL | |
| model_var: CHAT_MODEL_NAME | |
| embeddings: | |
| endpoint_var: EMBEDDING_URL | |
| model_var: EMBEDDING_NAME | |
| models: | |
| chat-model: | |
| model: ai/smollm2 | |
| context_size: 4096 | |
| runtime_flags: | |
| - "--temp" | |
| - "0.7" | |
| embeddings: | |
| model: ai/all-minilm | |
| context_size: 512 | |
| ``` | |
| **Model Configuration Presets:** | |
| ```yaml | |
| # Development mode - verbose logging | |
| models: | |
| dev_model: | |
| model: ai/smollm2 | |
| context_size: 4096 | |
| runtime_flags: | |
| - "--verbose" | |
| - "--verbose-prompt" | |
| - "--log-timestamps" | |
| - "--log-colors" | |
| # Production mode - deterministic output | |
| models: | |
| prod_model: | |
| model: ai/smollm2 | |
| context_size: 4096 | |
| runtime_flags: | |
| - "--temp" | |
| - "0.1" # Low temperature for consistency | |
| - "--top-k" | |
| - "1" | |
| # Creative mode - high randomness | |
| models: | |
| creative_model: | |
| model: ai/smollm2 | |
| context_size: 4096 | |
| runtime_flags: | |
| - "--temp" | |
| - "1.0" | |
| - "--top-p" | |
| - "0.9" | |
| ``` | |
| **Running Your Dockerized CLI:** | |
| ```bash | |
| # Start models and services | |
| docker compose up -d | |
| # Check model status | |
| docker compose ps | |
| # View model logs | |
| docker compose logs llm | |
| # Run your CLI (models are available via environment variables) | |
| docker compose exec file-organizer python -m file_organizer organize ./data | |
| # Stop everything | |
| docker compose down | |
| ``` | |
| **Complete Example Dockerfile:** | |
| ```dockerfile | |
| # Dockerfile | |
| FROM python:3.11-slim | |
| WORKDIR /app | |
| # Install dependencies | |
| COPY pyproject.toml . | |
| RUN pip install -e . | |
| # Copy application code | |
| COPY src/ ./src/ | |
| # The CLI will use environment variables injected by Docker Compose | |
| CMD ["python", "-m", "file_organizer.cli"] | |
| ``` | |
| **Benefits of Docker Deployment:** | |
| | Feature | Docker Compose | Manual Setup | | |
| |---------|----------------|-------------| | |
| | Setup Time | Minutes | Hours | | |
| | Consistency | β Same everywhere | β Varies by system | | |
| | Resource Control | β Built-in limits | β οΈ Manual config | | |
| | Multi-model | β Easy | β Complex | | |
| | Cloud Portability | β Same config | β Rewrite needed | | |
| | Version Control | β Git-friendly | β οΈ Documentation | | |
| **Cloud Deployment:** | |
| The same `docker-compose.yml` works on cloud providers with extensions: | |
| ```yaml | |
| models: | |
| llm: | |
| model: ai/smollm2 | |
| context_size: 4096 | |
| # Cloud-specific options (provider-dependent) | |
| x-cloud-options: | |
| - "cloud.instance-type=gpu-small" | |
| - "cloud.region=us-west-2" | |
| - "cloud.auto-scaling=true" | |
| ``` | |
| **Resources:** | |
| - [Docker AI Documentation](https://docs.docker.com/ai/) | |
| - [Docker Compose Models Reference](https://docs.docker.com/ai/compose/models-and-compose/) | |
| - [Docker Model Runner](https://docs.docker.com/ai/model-runner/) | |
| - [Available Models on Docker Hub](https://hub.docker.com/search?q=ai%2F) | |
| #### 3.3 Docker MCP Toolkit: Secure Tool Integration | |
| The Model Context Protocol (MCP) provides a standardized way for AI agents to interact with external tools and data sources. Docker's MCP Toolkit makes this secure and easy. | |
| **What is MCP?** | |
| MCP is an open protocol that allows AI models to: | |
| - Execute code in isolated environments | |
| - Access databases and APIs securely | |
| - Use external tools (web search, calculators, etc.) | |
| - Retrieve real-world data | |
| **Why Docker MCP?** | |
| 1. **Security**: Tools run in isolated containers | |
| 2. **Trust**: Curated catalog with publisher verification | |
| 3. **Simplicity**: One-click deployment from Docker Desktop | |
| 4. **Dynamic Discovery**: Agents find and add tools as needed | |
| **Docker MCP Components:** | |
| ```yaml | |
| # docker-compose.yml with MCP Gateway | |
| services: | |
| # Your AI-powered CLI | |
| file-organizer: | |
| build: . | |
| models: | |
| - llm | |
| environment: | |
| - MCP_GATEWAY_URL=http://mcp-gateway:3000 | |
| depends_on: | |
| - mcp-gateway | |
| # MCP Gateway - manages MCP servers | |
| mcp-gateway: | |
| image: docker/mcp-gateway:latest | |
| ports: | |
| - "3000:3000" | |
| volumes: | |
| - mcp-data:/data | |
| environment: | |
| - MCP_CATALOG_URL=https://hub.docker.com/mcp | |
| models: | |
| llm: | |
| model: ai/smollm2 | |
| context_size: 4096 | |
| volumes: | |
| mcp-data: | |
| ``` | |
| **Using MCP in Your CLI:** | |
| ```python | |
| # src/file_organizer/mcp_client.py | |
| import os | |
| import requests | |
| from typing import Any | |
| class MCPClient: | |
| """Client for Docker MCP Gateway.""" | |
| def __init__(self): | |
| self.gateway_url = os.getenv("MCP_GATEWAY_URL", "http://localhost:3000") | |
| def find_servers(self, query: str) -> list[dict]: | |
| """Find MCP servers by name or description.""" | |
| response = requests.post( | |
| f"{self.gateway_url}/mcp-find", | |
| json={"query": query} | |
| ) | |
| return response.json()["servers"] | |
| def add_server(self, server_name: str) -> dict: | |
| """Add an MCP server to the current session.""" | |
| response = requests.post( | |
| f"{self.gateway_url}/mcp-add", | |
| json={"server": server_name} | |
| ) | |
| return response.json() | |
| def call_tool(self, server: str, tool: str, params: dict) -> Any: | |
| """Call a tool from an MCP server.""" | |
| response = requests.post( | |
| f"{self.gateway_url}/mcp-call", | |
| json={ | |
| "server": server, | |
| "tool": tool, | |
| "parameters": params | |
| } | |
| ) | |
| return response.json()["result"] | |
| # Example: Web search integration | |
| @app.command() | |
| def research(topic: str): | |
| """Research a topic using web search MCP.""" | |
| mcp = MCPClient() | |
| # Find web search servers | |
| servers = mcp.find_servers("web search") | |
| console.print(f"Found {len(servers)} search servers") | |
| # Add DuckDuckGo MCP | |
| mcp.add_server("duckduckgo-mcp") | |
| # Use the search tool | |
| results = mcp.call_tool( | |
| server="duckduckgo-mcp", | |
| tool="search", | |
| params={"query": topic, "max_results": 5} | |
| ) | |
| # Display results | |
| for result in results: | |
| console.print(f"[bold]{result['title']}[/bold]") | |
| console.print(f" {result['url']}") | |
| console.print(f" {result['snippet']}\n") | |
| ``` | |
| **Dynamic MCP Discovery:** | |
| Let AI agents discover and use tools automatically: | |
| ```python | |
| # src/file_organizer/ai_agent.py | |
| from openai import OpenAI | |
| import json | |
| class AIAgentWithMCP: | |
| """AI agent that can discover and use MCP tools.""" | |
| def __init__(self): | |
| self.llm = OpenAI(base_url=os.getenv("LLM_URL"), api_key="not-needed") | |
| self.mcp = MCPClient() | |
| self.available_tools = [] | |
| def discover_tools(self, task_description: str): | |
| """Ask LLM what tools are needed for a task.""" | |
| prompt = f"""Task: {task_description} | |
| What MCP tools would be helpful? Respond with JSON: | |
| {{"tools": ["tool-name-1", "tool-name-2"]}} | |
| """ | |
| response = self.llm.completions.create( | |
| model=os.getenv("LLM_MODEL"), | |
| prompt=prompt, | |
| max_tokens=200 | |
| ) | |
| tools_needed = json.loads(response.choices[0].text) | |
| # Add each tool | |
| for tool in tools_needed["tools"]: | |
| servers = self.mcp.find_servers(tool) | |
| if servers: | |
| self.mcp.add_server(servers[0]["name"]) | |
| self.available_tools.append(servers[0]) | |
| def execute_task(self, task: str): | |
| """Execute a task using available tools.""" | |
| # First, discover what tools we need | |
| self.discover_tools(task) | |
| # Then execute with those tools | |
| # (Implementation depends on your specific use case) | |
| pass | |
| # Usage | |
| @app.command() | |
| def smart_organize(directory: Path, strategy: str): | |
| """Organize files using AI with dynamic tool discovery.""" | |
| agent = AIAgentWithMCP() | |
| task = f"Organize files in {directory} using strategy: {strategy}" | |
| agent.execute_task(task) | |
| ``` | |
| **Available MCP Servers:** | |
| The [Docker MCP Catalog](https://hub.docker.com/mcp) includes 270+ servers: | |
| - **Web Search**: DuckDuckGo, Brave Search | |
| - **Databases**: PostgreSQL, MongoDB, Elasticsearch | |
| - **APIs**: Stripe, GitHub, Slack | |
| - **Monitoring**: Grafana, Prometheus | |
| - **File Systems**: Local files, S3, Google Drive | |
| - **Development**: Git, Docker, Kubernetes | |
| **Security Features:** | |
| 1. **Container Isolation**: Each MCP server runs in its own container | |
| 2. **Commit Pinning**: Servers tied to specific Git commits | |
| 3. **Publisher Trust Levels**: Official, verified, and community servers | |
| 4. **AI-Audited Updates**: Automated code review for changes | |
| 5. **Resource Limits**: CPU and memory constraints per server | |
| **Complete Example with MCP:** | |
| ```yaml | |
| # docker-compose.yml - Full AI CLI with MCP | |
| services: | |
| file-organizer: | |
| build: . | |
| models: | |
| - llm | |
| environment: | |
| - MCP_GATEWAY_URL=http://mcp-gateway:3000 | |
| - ENABLE_DYNAMIC_MCPS=true | |
| depends_on: | |
| - mcp-gateway | |
| volumes: | |
| - ./data:/app/data | |
| mcp-gateway: | |
| image: docker/mcp-gateway:latest | |
| ports: | |
| - "3000:3000" | |
| volumes: | |
| - mcp-data:/data | |
| - ./mcp-config.yml:/config/catalog.yml | |
| models: | |
| llm: | |
| model: ai/smollm2 | |
| context_size: 4096 | |
| runtime_flags: | |
| - "--temp" | |
| - "0.7" | |
| volumes: | |
| mcp-data: | |
| ``` | |
| **MCP Best Practices:** | |
| 1. **Start with trusted servers**: Use official and verified publishers | |
| 2. **Enable only needed tools**: Reduce attack surface | |
| 3. **Monitor MCP usage**: Track which tools are called | |
| 4. **Set resource limits**: Prevent runaway processes | |
| 5. **Review permissions**: Understand what each MCP can access | |
| **Resources:** | |
| - [Docker MCP Gateway (GitHub)](https://github.com/docker/mcp-gateway/) | |
| - [Docker MCP Catalog](https://hub.docker.com/mcp) | |
| - [MCP Registry](https://github.com/docker/mcp-registry) | |
| - [Dynamic MCPs Blog](https://www.docker.com/blog/dynamic-mcps-stop-hardcoding-your-agents-world/) | |
| - [MCP Security Blog](https://www.docker.com/blog/enhancing-mcp-trust-with-the-docker-mcp-catalog/) | |
| #### 3.4 Prompt Engineering for CLI Tools | |
| **Learn About:** | |
| - Crafting effective prompts for different model types | |
| - Understanding model-specific prompt formats (Mistral, Llama, etc.) | |
| - System vs user messages (for chat models) | |
| - Few-shot learning examples | |
| - Prompt templates and variables | |
| **Hands-On:** | |
| Create a prompt template system: | |
| ```python | |
| # src/file_organizer/prompts.py | |
| # For instruction-tuned models like Mistral | |
| MISTRAL_ORGANIZATION_PROMPT = """[INST] You are a helpful file organization assistant. | |
| Given the following list of files: | |
| {file_list} | |
| Suggest an intelligent organization strategy that: | |
| 1. Groups related files together | |
| 2. Creates meaningful folder names | |
| 3. Explains the reasoning | |
| Respond in JSON format with this structure: | |
| {{ | |
| "strategy": "description", | |
| "folders": [ | |
| {{"name": "folder_name", "files": ["file1", "file2"], "reason": "why"}} | |
| ] | |
| }} [/INST]""" | |
| # For Llama-2 chat models | |
| LLAMA_SYSTEM_PROMPT = """You are a helpful file organization assistant. | |
| Always respond in valid JSON format.""" | |
| def format_llama_prompt(user_message: str) -> str: | |
| """Format prompt for Llama-2 chat models.""" | |
| return f"""<s>[INST] <<SYS>> | |
| {LLAMA_SYSTEM_PROMPT} | |
| <</SYS>> | |
| {user_message} [/INST]""" | |
| # For general models without special formatting | |
| GENERIC_PROMPT_TEMPLATE = """Task: Organize the following files intelligently. | |
| Files: {file_list} | |
| Instructions: | |
| - Group related files together | |
| - Suggest meaningful folder names | |
| - Explain your reasoning | |
| - Output as JSON | |
| Response:""" | |
| # Use Copilot to generate more prompt templates for different tasks | |
| ``` | |
| **Model-Specific Considerations:** | |
| ```python | |
| # src/file_organizer/model_config.py | |
| MODEL_CONFIGS = { | |
| "mistralai/Mistral-7B-Instruct-v0.2": { | |
| "max_tokens": 8192, | |
| "prompt_format": "mistral", | |
| "temperature": 0.7, | |
| "use_case": "general instruction following" | |
| }, | |
| "meta-llama/Llama-2-7b-chat-hf": { | |
| "max_tokens": 4096, | |
| "prompt_format": "llama2", | |
| "temperature": 0.7, | |
| "use_case": "conversational tasks" | |
| }, | |
| "facebook/bart-large-cnn": { | |
| "max_tokens": 1024, | |
| "prompt_format": "none", | |
| "use_case": "summarization only" | |
| } | |
| } | |
| def get_model_config(model_name: str) -> dict: | |
| """Get configuration for a specific model.""" | |
| return MODEL_CONFIGS.get(model_name, {}) | |
| ``` | |
| **Copilot Prompts:** | |
| - "Create a function to format prompts based on model type" | |
| - "Generate few-shot examples for file categorization" | |
| - "Build a prompt validator that checks token limits" | |
| - "Create a prompt optimization function that reduces token usage" | |
| --- | |
| ### Phase 4: Advanced CLI Features (Week 6-7) | |
| #### 4.1 Interactive CLI Elements | |
| **Add Dependencies:** | |
| ```bash | |
| pixi add questionary rich typer | |
| ``` | |
| **Learn to Build:** | |
| - Interactive prompts and menus | |
| - Progress bars and spinners | |
| - Tables and formatted output | |
| - Color-coded messages | |
| **Example with Copilot:** | |
| ```python | |
| # Ask Copilot: "Create an interactive menu using questionary | |
| # to select file organization options" | |
| import questionary | |
| from rich.progress import track | |
| def interactive_organize(): | |
| # Copilot will help generate this | |
| pass | |
| ``` | |
| #### 4.2 Batch Processing and Async Operations | |
| **Learn About:** | |
| - Processing multiple files efficiently | |
| - Async/await for concurrent API calls | |
| - Rate limiting and throttling | |
| - Progress tracking for long operations | |
| ```bash | |
| # Add async dependencies | |
| pixi add aiohttp asyncio | |
| ``` | |
| **Copilot Exercise:** | |
| - "Create an async function to process multiple files with OpenAI API" | |
| - "Add rate limiting to prevent API quota exhaustion" | |
| - "Implement a queue system for batch processing" | |
| --- | |
| ### Phase 5: Testing and Quality (Week 8) | |
| #### 5.1 Writing Tests | |
| **Add Testing Dependencies:** | |
| ```bash | |
| pixi add pytest pytest-cov pytest-asyncio pytest-mock | |
| ``` | |
| **Learn to Test:** | |
| - Unit tests for individual functions | |
| - Integration tests for CLI commands | |
| - Mocking API calls | |
| - Test coverage reporting | |
| **Example Test Structure:** | |
| ```python | |
| # tests/test_cli.py | |
| import pytest | |
| from typer.testing import CliRunner | |
| from file_organizer.cli import app | |
| runner = CliRunner() | |
| def test_organize_command(): | |
| # Use Copilot to generate test cases | |
| result = runner.invoke(app, ['organize', 'test_dir', '--dry-run']) | |
| assert result.exit_code == 0 | |
| assert "DRY RUN" in result.stdout | |
| def test_organize_with_verbose(): | |
| result = runner.invoke(app, ['organize', 'test_dir', '--verbose']) | |
| assert result.exit_code == 0 | |
| def test_stats_command(): | |
| result = runner.invoke(app, ['stats', 'test_dir']) | |
| assert result.exit_code == 0 | |
| ``` | |
| **Copilot Prompts:** | |
| - "Generate pytest fixtures for mocking HuggingFace Inference API" | |
| - "Create test cases for error handling with API timeouts" | |
| - "Write integration tests for the organize command" | |
| - "Mock transformers pipeline for local model testing" | |
| **Example Mocking HuggingFace:** | |
| ```python | |
| # tests/conftest.py | |
| import pytest | |
| from unittest.mock import Mock, patch | |
| @pytest.fixture | |
| def mock_hf_client(): | |
| """Mock HuggingFace InferenceClient.""" | |
| with patch('huggingface_hub.InferenceClient') as mock: | |
| mock_instance = Mock() | |
| mock_instance.text_generation.return_value = '{"strategy": "test"}' | |
| mock.return_value = mock_instance | |
| yield mock_instance | |
| @pytest.fixture | |
| def mock_transformers_pipeline(): | |
| """Mock transformers pipeline for local models.""" | |
| with patch('transformers.pipeline') as mock: | |
| mock_pipeline = Mock() | |
| mock_pipeline.return_value = [{"label": "POSITIVE", "score": 0.99}] | |
| mock.return_value = mock_pipeline | |
| yield mock_pipeline | |
| ``` | |
| #### 5.2 Code Quality Tools | |
| ```bash | |
| # Add quality tools | |
| pixi add ruff mypy black isort | |
| ``` | |
| **Set Up:** | |
| - Linting with ruff | |
| - Type checking with mypy | |
| - Code formatting with black | |
| - Import sorting with isort | |
| **Create `pyproject.toml` configuration (use Copilot):** | |
| ```toml | |
| [tool.ruff] | |
| line-length = 100 | |
| target-version = "py311" | |
| [tool.mypy] | |
| python_version = "3.11" | |
| strict = true | |
| [tool.black] | |
| line-length = 100 | |
| ``` | |
| --- | |
| ### Phase 6: Package Publishing with Pixi (Week 9) | |
| #### 6.1 Preparing for Publication | |
| **Project Structure:** | |
| ``` | |
| my-cli-tool/ | |
| βββ pixi.toml # Pixi configuration | |
| βββ pyproject.toml # Python package metadata | |
| βββ README.md # Documentation | |
| βββ LICENSE # License file | |
| βββ src/ | |
| β βββ my_cli_tool/ | |
| β βββ __init__.py | |
| β βββ cli.py | |
| β βββ ... | |
| βββ tests/ | |
| β βββ test_*.py | |
| βββ docs/ | |
| βββ ... | |
| ``` | |
| **Configure `pyproject.toml` for Publishing:** | |
| ```toml | |
| [build-system] | |
| requires = ["hatchling"] | |
| build-backend = "hatchling.build" | |
| [project] | |
| name = "my-cli-tool" | |
| version = "0.1.0" | |
| description = "AI-powered file organization CLI" | |
| authors = [{name = "Your Name", email = "you@example.com"}] | |
| readme = "README.md" | |
| requires-python = ">=3.11" | |
| dependencies = [ | |
| "typer>=0.9", | |
| "rich>=13.0", | |
| "transformers>=4.30", | |
| "huggingface-hub>=0.16", | |
| ] | |
| [project.scripts] | |
| my-cli = "my_cli_tool.cli:cli" | |
| [project.urls] | |
| Homepage = "https://github.com/yourusername/my-cli-tool" | |
| Documentation = "https://my-cli-tool.readthedocs.io" | |
| ``` | |
| **Use Copilot to:** | |
| - Generate comprehensive README with usage examples | |
| - Create CHANGELOG.md | |
| - Write contributing guidelines | |
| - Generate documentation | |
| #### 6.2 Building and Publishing | |
| **Build Package:** | |
| ```bash | |
| # Add build tools | |
| pixi add hatchling build twine | |
| # Build the package | |
| pixi run python -m build | |
| # This creates: | |
| # - dist/my_cli_tool-0.1.0.tar.gz | |
| # - dist/my_cli_tool-0.1.0-py3-none-any.whl | |
| ``` | |
| **Publish to PyPI:** | |
| ```bash | |
| # Test on TestPyPI first | |
| pixi run twine upload --repository testpypi dist/* | |
| # Then publish to PyPI | |
| pixi run twine upload dist/* | |
| ``` | |
| **Publish as Pixi Package:** | |
| ```bash | |
| # Create pixi.toml with package metadata | |
| pixi project init --name my-cli-tool | |
| # Add to pixi.toml: | |
| [project] | |
| name = "my-cli-tool" | |
| version = "0.1.0" | |
| description = "AI-powered file organization CLI" | |
| channels = ["conda-forge"] | |
| platforms = ["linux-64", "osx-64", "win-64"] | |
| [dependencies] | |
| python = ">=3.11" | |
| typer = ">=0.9" | |
| rich = ">=13.0" | |
| [tasks] | |
| start = "my-cli" | |
| ``` | |
| **Resources:** | |
| - [Python Packaging Guide](https://packaging.python.org/) | |
| - [Pixi Publishing Guide](https://pixi.sh/latest/advanced/publishing/) | |
| - [Semantic Versioning](https://semver.org/) | |
| --- | |
| ### Phase 7: Real-World Project (Week 10-12) | |
| #### 7.1 Choose a Project from the Ideas List | |
| **Comprehensive Example Project:** | |
| **[FileOrganizer](projects/FileOrganizer.md)** - AI-Powered File Organization CLI | |
| - **What it demonstrates**: Complete integration of all concepts from this learning path | |
| - **Key technologies**: Docker Model Runner, MCP servers, CrewAI multi-agent system, Typer CLI | |
| - **Complexity**: Advanced | |
| - **Best for**: Learners who have completed Phases 1-6 and want to see a production-ready example | |
| - **Features**: | |
| - Multi-agent system (Scanner, Classifier, Organizer, Deduplicator) | |
| - Docker-based LLM deployment | |
| - MCP server for file operations | |
| - Research paper management with metadata extraction | |
| - Comprehensive CLI with multiple commands | |
| - **Learning outcomes**: See how Docker AI, MCP, multi-agent systems, and CLI development work together in a real project | |
| **Recommended Starter Projects:** | |
| 1. **smart-csv** (Data & Analytics) | |
| - Good for: Learning data manipulation | |
| - Key skills: Pandas, CSV processing, LLM integration | |
| - Complexity: Medium | |
| 2. **smart-summarize** (Document Processing) | |
| - Good for: Text processing and AI integration | |
| - Key skills: File I/O, API integration, prompt engineering | |
| - Complexity: Low-Medium | |
| 3. **error-translator** (DevOps) | |
| - Good for: String processing and knowledge retrieval | |
| - Key skills: Pattern matching, API usage, caching | |
| - Complexity: Medium | |
| 4. **task-prioritizer** (Productivity) | |
| - Good for: Building practical tools | |
| - Key skills: Data structures, AI reasoning, persistence | |
| - Complexity: Medium | |
| > **π‘ Tip**: Start with one of the simpler projects (2-4) to build confidence, then tackle FileOrganizer to see how all the concepts integrate in a production-ready application. | |
| #### 7.2 Development Workflow with GitHub Copilot | |
| **Step-by-Step Process:** | |
| 1. **Planning Phase:** | |
| - Use Copilot Chat to brainstorm features | |
| - Generate project structure | |
| - Create initial documentation | |
| 2. **Implementation Phase:** | |
| - Use Copilot for boilerplate code | |
| - Ask Copilot to explain unfamiliar concepts | |
| - Generate test cases alongside code | |
| 3. **Refinement Phase:** | |
| - Use Copilot to suggest optimizations | |
| - Generate documentation and examples | |
| - Create user guides | |
| **Effective Copilot Prompts:** | |
| ```python | |
| # In comments, be specific: | |
| # "Create a function that reads a CSV file, analyzes column types, | |
| # and returns a dictionary with column names as keys and suggested | |
| # data types as values. Handle errors gracefully." | |
| # Use descriptive function names: | |
| def analyze_csv_column_types(filepath: str) -> dict[str, str]: | |
| # Copilot will suggest implementation | |
| pass | |
| # Ask for explanations: | |
| # "Explain how to use asyncio to make concurrent API calls with rate limiting" | |
| ``` | |
| #### 7.3 Project Milestones | |
| **Week 10: MVP (Minimum Viable Product)** | |
| - [ ] Core functionality working | |
| - [ ] Basic CLI interface | |
| - [ ] Simple AI integration | |
| - [ ] README with usage examples | |
| **Week 11: Enhancement** | |
| - [ ] Add configuration system | |
| - [ ] Implement error handling | |
| - [ ] Add progress indicators | |
| - [ ] Write tests (>70% coverage) | |
| **Week 12: Polish & Publish** | |
| - [ ] Complete documentation | |
| - [ ] Add examples and tutorials | |
| - [ ] Set up CI/CD (GitHub Actions) | |
| - [ ] Publish to PyPI | |
| - [ ] Share on GitHub/social media | |
| --- | |
| ## π οΈ Essential Pixi Commands Reference | |
| ```bash | |
| # Project initialization | |
| pixi init my-project | |
| pixi init --channel conda-forge --channel bioconda | |
| # Dependency management | |
| pixi add package-name # Add runtime dependency | |
| pixi add --dev pytest # Add dev dependency | |
| pixi add "package>=1.0,<2.0" # Version constraints | |
| pixi remove package-name # Remove dependency | |
| pixi update # Update all dependencies | |
| # Environment management | |
| pixi shell # Activate environment | |
| pixi run python script.py # Run command in environment | |
| pixi run --environment prod start # Run in specific environment | |
| # Task management | |
| pixi task add start "python -m my_cli" | |
| pixi task add test "pytest tests/" | |
| pixi task add lint "ruff check src/" | |
| pixi run start # Run defined task | |
| # Multi-environment setup | |
| [feature.dev.dependencies] | |
| pytest = "*" | |
| ruff = "*" | |
| [environments] | |
| default = ["dev"] | |
| prod = [] | |
| ``` | |
| --- | |
| ## π Learning Resources | |
| ### Documentation | |
| - [Pixi Official Docs](https://pixi.sh/latest/) | |
| - [Python Packaging Guide](https://packaging.python.org/) | |
| - [Click Documentation](https://click.palletsprojects.com/) | |
| - [OpenAI API Reference](https://platform.openai.com/docs/) | |
| - [Docker AI Documentation](https://docs.docker.com/ai/) | |
| - [Docker Compose Models Reference](https://docs.docker.com/ai/compose/models-and-compose/) | |
| - [Docker MCP Gateway](https://github.com/docker/mcp-gateway/) | |
| - [Docker MCP Catalog](https://hub.docker.com/mcp) | |
| ### Tutorials & Courses | |
| - [Real Python: Building CLI Applications](https://realpython.com/command-line-interfaces-python-argparse/) | |
| - [GitHub Copilot Learning Path](https://github.com/skills/copilot) | |
| - [LangChain Tutorials](https://python.langchain.com/docs/tutorials/) | |
| ### Example Projects | |
| - [Typer Examples](https://github.com/tiangolo/typer/tree/master/docs_src) | |
| - [Rich Examples](https://github.com/Textualize/rich/tree/master/examples) | |
| - [AI CLI Tools on GitHub](https://github.com/topics/ai-cli) | |
| ### Community | |
| - [Python Discord](https://discord.gg/python) | |
| - [r/Python](https://reddit.com/r/Python) | |
| - [Pixi GitHub Discussions](https://github.com/prefix-dev/pixi/discussions) | |
| --- | |
| ## π‘ Tips for Success | |
| ### Using GitHub Copilot Effectively | |
| 1. **Write Clear Comments:** | |
| ```python | |
| # Create a function that takes a list of file paths, | |
| # sends them to GPT-4 for analysis, and returns | |
| # a structured JSON response with organization suggestions | |
| ``` | |
| 2. **Use Descriptive Names:** | |
| - Good: `analyze_and_categorize_files()` | |
| - Bad: `process()` | |
| 3. **Break Down Complex Tasks:** | |
| - Don't ask Copilot to generate entire applications | |
| - Build incrementally, function by function | |
| 4. **Review and Understand:** | |
| - Always review Copilot's suggestions | |
| - Understand the code before accepting it | |
| - Test thoroughly | |
| 5. **Use Copilot Chat for:** | |
| - Explaining error messages | |
| - Suggesting alternative approaches | |
| - Generating test cases | |
| - Writing documentation | |
| ### Pixi Best Practices | |
| 1. **Use Feature Flags:** | |
| ```toml | |
| [feature.ai] | |
| dependencies = {openai = "*", anthropic = "*"} | |
| [feature.dev] | |
| dependencies = {pytest = "*", ruff = "*"} | |
| [environments] | |
| default = ["ai"] | |
| dev = ["ai", "dev"] | |
| ``` | |
| 2. **Define Tasks:** | |
| ```toml | |
| [tasks] | |
| dev = "python -m my_cli --debug" | |
| test = "pytest tests/ -v" | |
| lint = "ruff check src/" | |
| format = "black src/ tests/" | |
| ``` | |
| 3. **Lock Dependencies:** | |
| - Commit `pixi.lock` to version control | |
| - Ensures reproducible builds | |
| 4. **Use Channels Wisely:** | |
| - Start with `conda-forge` | |
| - Add specialized channels as needed | |
| ### Development Workflow | |
| 1. **Start Small:** | |
| - Build the simplest version first | |
| - Add features incrementally | |
| - Test each addition | |
| 2. **Iterate Based on Feedback:** | |
| - Share early with friends/colleagues | |
| - Gather feedback | |
| - Improve based on real usage | |
| 3. **Document as You Go:** | |
| - Write docstrings immediately | |
| - Update README with new features | |
| - Keep CHANGELOG current | |
| 4. **Test Continuously:** | |
| - Write tests alongside code | |
| - Run tests before committing | |
| - Aim for >80% coverage | |
| --- | |
| ## π― Success Metrics | |
| By the end of this learning path, you should be able to: | |
| - β Set up a Python project with pixi | |
| - β Build a CLI application with commands and options | |
| - β Integrate AI/LLM capabilities effectively | |
| - β Write tests and maintain code quality | |
| - β Publish a package to PyPI | |
| - β Use GitHub Copilot to accelerate development | |
| - β Build one complete AI-powered CLI tool | |
| --- | |
| ## π Next Steps | |
| After completing this learning path: | |
| 1. **Build More Projects:** | |
| - Try different project ideas from the list | |
| - Experiment with different AI models | |
| - Contribute to open-source CLI tools | |
| 2. **Advanced Topics:** | |
| - Plugin architectures | |
| - Multi-command CLIs | |
| - Database integration | |
| - Web dashboards for CLI tools | |
| - CI/CD automation | |
| 3. **Share Your Work:** | |
| - Write blog posts about your projects | |
| - Create video tutorials | |
| - Contribute to the community | |
| - Help others learn | |
| --- | |
| *Last Updated: 2024-12-04* | |